Skip to content

Commit

Permalink
Merge pull request #133 from redbearsam/feature/themable-heatmap
Browse files Browse the repository at this point in the history
Implemented themable color ranges for heatmap and X/Y
  • Loading branch information
andy-lee-eng authored Mar 28, 2019
2 parents 51a355a + 6966638 commit 83251e2
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 22 deletions.
53 changes: 47 additions & 6 deletions packages/perspective-viewer-d3fc/src/js/series/colorStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
*
*/

import * as d3 from "d3";
import * as gparser from "gradient-parser";

let initialised = false;
export const colorStyles = {};

Expand All @@ -18,7 +21,9 @@ export const initialiseStyles = (container, settings) => {
}

const styles = {
scheme: []
scheme: [],
gradient: {},
interpolator: {}
};

const computed = computedStyle(container);
Expand All @@ -32,6 +37,13 @@ export const initialiseStyles = (container, settings) => {

styles.opacity = getOpacityFromColor(styles.series);

const gradients = ["full", "positive", "negative"];
gradients.forEach(g => {
const gradient = computed(`--d3fc-gradient-${g}`);
styles.gradient[g] = parseGradient(gradient, styles.opacity);
styles.interpolator[g] = multiInterpolator(styles.gradient[g]);
});

if (!initialised) {
Object.keys(styles).forEach(p => {
colorStyles[p] = styles[p];
Expand All @@ -43,11 +55,13 @@ export const initialiseStyles = (container, settings) => {
};

const getOpacityFromColor = color => {
if (color.includes("rgba")) {
const rgbColors = color.substring(color.indexOf("(") + 1).split(",");
return parseFloat(rgbColors[3]);
}
return 1;
return d3.color(color).opacity;
};

const stepAsColor = (value, opacity) => {
const color = d3.color(`#${value}`);
color.opacity = opacity;
return color + "";
};

const computedStyle = container => {
Expand All @@ -58,3 +72,30 @@ const computedStyle = container => {
return d => containerStyles.getPropertyValue(d);
}
};

const parseGradient = (gradient, opacity) =>
gparser
.parse(gradient)[0]
.colorStops.map(g => [g.length.value / 100, stepAsColor(g.value, opacity)])
.sort((a, b) => a[0] - b[0]);

const multiInterpolator = gradientPairs => {
// A new interpolator that calls through to a set of
// interpolators between each value/color pair
const interpolators = gradientPairs.slice(1).map((p, i) => d3.interpolate(gradientPairs[i][1], p[1]));
return value => {
const index = gradientPairs.findIndex((p, i) => i < gradientPairs.length - 1 && value <= gradientPairs[i + 1][0] && value > p[0]);
if (index === -1) {
if (value <= gradientPairs[0][0]) {
return gradientPairs[0][1];
}
return gradientPairs[gradientPairs.length - 1][1];
}

const interpolator = interpolators[index];
const [value1] = gradientPairs[index];
const [value2] = gradientPairs[index + 1];

return interpolator((value - value1) / (value2 - value1));
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function heatmapSeries(settings, color) {

series.decorate(selection => {
tooltip().settings(settings)(selection);
selection.select("path").attr("fill", d => color(d.colorValue));
});

return fc
Expand Down
14 changes: 3 additions & 11 deletions packages/perspective-viewer-d3fc/src/js/series/seriesColors.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,8 @@ export function withOpacity(color) {

export function setOpacity(opacity) {
return color => {
const toInt = (c, offset, length) => parseInt(c.substring(offset, offset + length) + (length === 1 ? "0" : ""), 16);
const colorsFromRGB = c =>
c
.substring(c.indexOf("(") + 1)
.split(",")
.map(d => parseInt(d))
.slice(0, 3);
const colorsFromHex = c => (c.length === 4 ? [toInt(c, 1, 1), toInt(c, 2, 1), toInt(c, 3, 1)] : [toInt(c, 1, 2), toInt(c, 3, 2), toInt(c, 5, 2)]);

const colors = color.includes("rgb") ? colorsFromRGB(color) : colorsFromHex(color);
return opacity === 1 ? `rgb(${colors.join(",")})` : `rgba(${colors.join(",")},${opacity})`;
const decoded = d3.color(color);
decoded.opacity = opacity;
return decoded + "";
};
}
20 changes: 15 additions & 5 deletions packages/perspective-viewer-d3fc/src/js/series/seriesRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,19 @@ export function seriesLinearRange(settings, data, valueName) {
}

export function seriesColorRange(settings, data, valueName) {
return d3.scaleSequential(d3.interpolateViridis).domain(
domain()
.valueName(valueName)
.pad([0, 0])(data)
);
let extent = domain()
.valueName(valueName)
.pad([0, 0])(data);
let interpolator = settings.colorStyles.interpolator.full;

if (extent[0] >= 0) {
interpolator = settings.colorStyles.interpolator.positive;
} else if (extent[1] <= 0) {
interpolator = settings.colorStyles.interpolator.negative;
} else {
const maxVal = Math.max(-extent[0], extent[1]);
extent = [-maxVal, maxVal];
}

return d3.scaleSequential(interpolator).domain(extent);
}
19 changes: 19 additions & 0 deletions packages/perspective-viewer-d3fc/src/less/perspective-view.less
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,25 @@
--d3fc-series-8: #7f7f7f;
--d3fc-series-9: #bcbd22;
--d3fc-series-10: #17becf;
--d3fc-gradient-full: linear-gradient(
#4d342f 0%,
#e4521b 22.5%,
#feeb65 42.5%,
#f0f0f0 50%,
#dcedc8 57.5%,
#42b3d5 67.5%,
#1a237e 100%
);
--d3fc-gradient-positive: linear-gradient(
#dcedc8 0%,
#42b3d5 35%,
#1a237e 100%
);
--d3fc-gradient-negative: linear-gradient(
#feeb65 100%,
#e4521b 70%,
#4d342f 0%
);
}

:host([view=d3_xy_scatter]), :host([view=d3_candlestick]), :host([view=d3_ohlc]) {
Expand Down
21 changes: 21 additions & 0 deletions packages/perspective-viewer/src/themes/material.dark.less
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,27 @@ perspective-viewer {
--d3fc-series-8: #7f7f7f;
--d3fc-series-9: #bcbd22;
--d3fc-series-10: #17becf;
--d3fc-gradient-full: linear-gradient(
#4d342f 0%,
#e4521b 22.5%,
#feeb65 42.5%,
#f0f0f0 50%,
#dcedc8 57.5%,
#42b3d5 67.5%,
#1a237e 100%
);
--d3fc-gradient-positive: linear-gradient(
#222222 0%,
#1a237e 35%,
#42b3d5 70%,
#dcedc8 100%
);
--d3fc-gradient-negative: linear-gradient(
#feeb65 0%,
#e4521b 35%,
#4d342f 70%,
#222222 100%
);

--highcharts-heatmap-gradient-full: linear-gradient(
#feeb65 0%,
Expand Down

0 comments on commit 83251e2

Please sign in to comment.