Skip to content

Commit

Permalink
Implemented themable color ranges for heatmap and X/Y
Browse files Browse the repository at this point in the history
Implemented a special interpolator to connect up multiple two-color interpolators
Heatmap color has to be reapplied because the d3fc one forces it to the data extent rather than the color range you've given it
Found some d3 color utility functions
  • Loading branch information
andy-lee-eng committed Mar 27, 2019
1 parent 51a355a commit 6966638
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 6966638

Please sign in to comment.