@opendata-ai/openchart-engine 6.28.4 → 6.28.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/tables/__tests__/heatmap.test.ts +4 -6
- package/src/tables/heatmap.ts +6 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opendata-ai/openchart-engine",
|
|
3
|
-
"version": "6.28.
|
|
3
|
+
"version": "6.28.6",
|
|
4
4
|
"description": "Headless compiler for openchart: spec validation, data compilation, scales, and layout",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Riley Hilliard",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"typecheck": "tsc --noEmit"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@opendata-ai/openchart-core": "6.28.
|
|
51
|
+
"@opendata-ai/openchart-core": "6.28.6",
|
|
52
52
|
"d3-array": "^3.2.0",
|
|
53
53
|
"d3-format": "^3.1.2",
|
|
54
54
|
"d3-interpolate": "^3.0.0",
|
|
@@ -112,7 +112,7 @@ describe('computeHeatmapColors', () => {
|
|
|
112
112
|
}
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it('
|
|
115
|
+
it('custom palette arrays are not adapted in dark mode', () => {
|
|
116
116
|
const col: ColumnConfig = {
|
|
117
117
|
key: 'value',
|
|
118
118
|
heatmap: { palette: ['#fca5a5', '#c44e52'], domain: [0, 100] },
|
|
@@ -122,16 +122,14 @@ describe('computeHeatmapColors', () => {
|
|
|
122
122
|
const lightColors = computeHeatmapColors(data, col, lightTheme, false);
|
|
123
123
|
const darkColors = computeHeatmapColors(data, col, darkTheme, true);
|
|
124
124
|
|
|
125
|
-
// Low value should have a visually lighter/less intense background than high value
|
|
126
|
-
// in both modes. Extract the backgrounds and compare luminance ordering.
|
|
127
125
|
const lightLowBg = lightColors.get(0)!.backgroundColor!;
|
|
128
126
|
const lightHighBg = lightColors.get(4)!.backgroundColor!;
|
|
129
127
|
const darkLowBg = darkColors.get(0)!.backgroundColor!;
|
|
130
128
|
const darkHighBg = darkColors.get(4)!.backgroundColor!;
|
|
131
129
|
|
|
132
|
-
//
|
|
133
|
-
expect(
|
|
134
|
-
expect(
|
|
130
|
+
// Custom palettes produce the same colors in both modes
|
|
131
|
+
expect(darkLowBg).toBe(lightLowBg);
|
|
132
|
+
expect(darkHighBg).toBe(lightHighBg);
|
|
135
133
|
});
|
|
136
134
|
|
|
137
135
|
it('supports array of color stops as palette', () => {
|
package/src/tables/heatmap.ts
CHANGED
|
@@ -11,17 +11,6 @@ import { interpolateRgb } from 'd3-interpolate';
|
|
|
11
11
|
import { scaleSequential } from 'd3-scale';
|
|
12
12
|
import { accessibleTextColor } from './utils';
|
|
13
13
|
|
|
14
|
-
/** WCAG relative luminance from a hex color string. */
|
|
15
|
-
function relativeLuminance(hex: string): number {
|
|
16
|
-
const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(hex);
|
|
17
|
-
if (!m) return 0;
|
|
18
|
-
const [r, g, b] = [m[1], m[2], m[3]].map((c) => {
|
|
19
|
-
const v = Number.parseInt(c, 16) / 255;
|
|
20
|
-
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
21
|
-
});
|
|
22
|
-
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
14
|
/**
|
|
26
15
|
* Build an interpolator from an array of color stops.
|
|
27
16
|
* Uses d3-interpolate for smooth color transitions.
|
|
@@ -106,29 +95,16 @@ export function computeHeatmapColors(
|
|
|
106
95
|
domain = [min, max];
|
|
107
96
|
}
|
|
108
97
|
|
|
109
|
-
// Resolve palette and build scale
|
|
98
|
+
// Resolve palette and build scale.
|
|
99
|
+
// Only adapt theme-derived palettes for dark mode. Custom color arrays
|
|
100
|
+
// are used as-is since the author chose them for a reason, and
|
|
101
|
+
// adaptColorForDarkMode inverts the perceived intensity ordering
|
|
102
|
+
// (light pink -> dark red becomes dark red -> pink on dark backgrounds).
|
|
110
103
|
let stops = resolvePalette(config.palette, theme);
|
|
111
|
-
if (darkMode) {
|
|
104
|
+
if (darkMode && !Array.isArray(config.palette)) {
|
|
112
105
|
const lightBg = '#ffffff';
|
|
113
106
|
const darkBg = theme.colors.background;
|
|
114
|
-
const originalStops = stops;
|
|
115
107
|
stops = stops.map((c) => adaptColorForDarkMode(c, lightBg, darkBg));
|
|
116
|
-
|
|
117
|
-
// adaptColorForDarkMode preserves contrast ratios independently per stop,
|
|
118
|
-
// which can invert the luminance ordering (light-to-dark becomes dark-to-light).
|
|
119
|
-
// Detect this and reverse the adapted stops to preserve the intended gradient direction.
|
|
120
|
-
if (originalStops.length >= 2) {
|
|
121
|
-
const origDirection = Math.sign(
|
|
122
|
-
relativeLuminance(originalStops[originalStops.length - 1]) -
|
|
123
|
-
relativeLuminance(originalStops[0]),
|
|
124
|
-
);
|
|
125
|
-
const adaptedDirection = Math.sign(
|
|
126
|
-
relativeLuminance(stops[stops.length - 1]) - relativeLuminance(stops[0]),
|
|
127
|
-
);
|
|
128
|
-
if (origDirection !== 0 && adaptedDirection !== 0 && origDirection !== adaptedDirection) {
|
|
129
|
-
stops = stops.slice().reverse();
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
108
|
}
|
|
133
109
|
|
|
134
110
|
const interpolator = interpolatorFromStops(stops);
|