mirror of
https://github.com/kalkih/mini-graph-card.git
synced 2025-12-20 00:35:56 +01:00
fix: use d3 to interpolate colors (#1118)
This commit is contained in:
36
package-lock.json
generated
36
package-lock.json
generated
@@ -5,12 +5,12 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mini-graph-card",
|
||||
"version": "0.11.0",
|
||||
"version": "0.12.2-dev.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@kalkih/lz-string": "^1.4.5",
|
||||
"custom-card-helpers": "^1.6.6",
|
||||
"d3-interpolate": "^3.0.1",
|
||||
"lit-element": "^2.2.1",
|
||||
"localforage": "^1.7.3",
|
||||
"spark-md5": "^3.0.1"
|
||||
@@ -3907,6 +3907,25 @@
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-color": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-interpolate": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/dateformat": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
|
||||
@@ -18952,6 +18971,19 @@
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
},
|
||||
"d3-color": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="
|
||||
},
|
||||
"d3-interpolate": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||
"requires": {
|
||||
"d3-color": "1 - 3"
|
||||
}
|
||||
},
|
||||
"dateformat": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"dependencies": {
|
||||
"@kalkih/lz-string": "^1.4.5",
|
||||
"custom-card-helpers": "^1.6.6",
|
||||
"d3-interpolate": "^3.0.1",
|
||||
"lit-element": "^2.2.1",
|
||||
"localforage": "^1.7.3",
|
||||
"spark-md5": "^3.0.1"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { interpolateColor } from './utils';
|
||||
import { interpolateRgb } from 'd3-interpolate';
|
||||
import {
|
||||
X, Y, V,
|
||||
ONE_HOUR,
|
||||
@@ -162,10 +162,10 @@ export default class Graph {
|
||||
let color;
|
||||
if (stop.value > this._max && arr[index + 1]) {
|
||||
const factor = (this._max - arr[index + 1].value) / (stop.value - arr[index + 1].value);
|
||||
color = interpolateColor(arr[index + 1].color, stop.color, factor);
|
||||
color = interpolateRgb(arr[index + 1].color, stop.color)(factor);
|
||||
} else if (stop.value < this._min && arr[index - 1]) {
|
||||
const factor = (arr[index - 1].value - this._min) / (arr[index - 1].value - stop.value);
|
||||
color = interpolateColor(arr[index - 1].color, stop.color, factor);
|
||||
color = interpolateRgb(arr[index - 1].color, stop.color)(factor);
|
||||
}
|
||||
let offset;
|
||||
if (scale <= 0) {
|
||||
|
||||
48
src/main.js
48
src/main.js
@@ -2,6 +2,7 @@ import { LitElement, html, svg } from 'lit-element';
|
||||
import localForage from 'localforage/src/localforage';
|
||||
import { stateIcon } from 'custom-card-helpers';
|
||||
import SparkMD5 from 'spark-md5';
|
||||
import { interpolateRgb } from 'd3-interpolate';
|
||||
import Graph from './graph';
|
||||
import style from './style';
|
||||
import handleClick from './handleClick';
|
||||
@@ -18,7 +19,6 @@ import {
|
||||
import {
|
||||
getMin, getAvg, getMax,
|
||||
getTime, getMilli,
|
||||
interpolateColor,
|
||||
compress, decompress,
|
||||
getFirstDefinedItem,
|
||||
compareArray,
|
||||
@@ -149,7 +149,7 @@ class MiniGraphCard extends LitElement {
|
||||
|
||||
shouldUpdate(changedProps) {
|
||||
if (UPDATE_PROPS.some(prop => changedProps.has(prop))) {
|
||||
this.color = this.intColor(
|
||||
this.color = this.computeColor(
|
||||
this.tooltip.value !== undefined
|
||||
? this.tooltip.value : this.entity[0] && this.entity[0].state,
|
||||
this.tooltip.entity || 0,
|
||||
@@ -356,7 +356,7 @@ class MiniGraphCard extends LitElement {
|
||||
renderIndicator(state, index) {
|
||||
return svg`
|
||||
<svg width='10' height='10'>
|
||||
<rect width='10' height='10' fill=${this.intColor(state, index)} />
|
||||
<rect width='10' height='10' fill=${this.computeColor(state, index)} />
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
@@ -475,7 +475,7 @@ class MiniGraphCard extends LitElement {
|
||||
if (!fill) return;
|
||||
const svgFill = this.gradient[i]
|
||||
? `url(#grad-${this.id}-${i})`
|
||||
: this.intColor(this.entity[i].state, i);
|
||||
: this.computeColor(this.entity[i].state, i);
|
||||
return svg`
|
||||
<rect class='fill--rect'
|
||||
?inactive=${this.tooltip.entity !== undefined && this.tooltip.entity !== i}
|
||||
@@ -605,17 +605,6 @@ class MiniGraphCard extends LitElement {
|
||||
handleClick(this, this._hass, this.config, this.config.tap_action, entity.entity_id || entity);
|
||||
}
|
||||
|
||||
computeColor(inState, i) {
|
||||
const { color_thresholds, line_color } = this.config;
|
||||
const state = Number(inState) || 0;
|
||||
const threshold = {
|
||||
color: line_color[i] || line_color[0],
|
||||
...color_thresholds.slice(-1)[0],
|
||||
...color_thresholds.find(ele => ele.value < state),
|
||||
};
|
||||
return this.config.entities[i].color || threshold.color;
|
||||
}
|
||||
|
||||
get visibleEntities() {
|
||||
return this.config.entities.filter(entity => entity.show_graph !== false);
|
||||
}
|
||||
@@ -641,28 +630,25 @@ class MiniGraphCard extends LitElement {
|
||||
return this.secondaryYaxisEntities.map(entity => this.Graph[entity.index]);
|
||||
}
|
||||
|
||||
intColor(inState, i) {
|
||||
computeColor(inState, i) {
|
||||
const { color_thresholds, line_color } = this.config;
|
||||
const state = Number(inState) || 0;
|
||||
|
||||
let intColor;
|
||||
if (color_thresholds.length > 0) {
|
||||
if (this.config.show.graph === 'bar') {
|
||||
const { color } = color_thresholds.find(ele => ele.value < state)
|
||||
|| color_thresholds.slice(-1)[0];
|
||||
intColor = color;
|
||||
const { color } = color_thresholds.find(ele => ele.value < state)
|
||||
|| color_thresholds.slice(-1)[0];
|
||||
intColor = color;
|
||||
const index = color_thresholds.findIndex(ele => ele.value < state);
|
||||
const c1 = color_thresholds[index];
|
||||
const c2 = color_thresholds[index - 1];
|
||||
if (c2) {
|
||||
const factor = (c2.value - state) / (c2.value - c1.value);
|
||||
intColor = interpolateRgb(c2.color, c1.color)(factor);
|
||||
} else {
|
||||
const index = color_thresholds.findIndex(ele => ele.value < state);
|
||||
const c1 = color_thresholds[index];
|
||||
const c2 = color_thresholds[index - 1];
|
||||
if (c2) {
|
||||
const factor = (c2.value - inState) / (c2.value - c1.value);
|
||||
intColor = interpolateColor(c2.color, c1.color, factor);
|
||||
} else {
|
||||
intColor = index
|
||||
? color_thresholds[color_thresholds.length - 1].color
|
||||
: color_thresholds[0].color;
|
||||
}
|
||||
intColor = index
|
||||
? color_thresholds[color_thresholds.length - 1].color
|
||||
: color_thresholds[0].color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
src/utils.js
18
src/utils.js
@@ -13,22 +13,6 @@ const getMax = (arr, val) => arr.reduce((max, p) => (
|
||||
const getTime = (date, extra, locale = 'en-US') => date.toLocaleString(locale, { hour: 'numeric', minute: 'numeric', ...extra });
|
||||
const getMilli = hours => hours * 60 ** 2 * 10 ** 3;
|
||||
|
||||
const interpolateColor = (a, b, factor) => {
|
||||
const ah = +a.replace('#', '0x');
|
||||
const ar = ah >> 16;
|
||||
const ag = (ah >> 8) & 0xff;
|
||||
const ab = ah & 0xff;
|
||||
const bh = +b.replace('#', '0x');
|
||||
const br = bh >> 16;
|
||||
const bg = (bh >> 8) & 0xff;
|
||||
const bb = bh & 0xff;
|
||||
const rr = ar + factor * (br - ar);
|
||||
const rg = ag + factor * (bg - ag);
|
||||
const rb = ab + factor * (bb - ab);
|
||||
|
||||
return `#${(((1 << 24) + (rr << 16) + (rg << 8) + rb) | 0).toString(16).slice(1)}`;
|
||||
};
|
||||
|
||||
const compress = data => lzStringCompress(JSON.stringify(data));
|
||||
|
||||
const decompress = data => (typeof data === 'string' ? JSON.parse(lzStringDecompress(data)) : data);
|
||||
@@ -44,7 +28,7 @@ const log = (message) => {
|
||||
};
|
||||
|
||||
export {
|
||||
getMin, getAvg, getMax, getTime, getMilli, interpolateColor, compress, decompress, log,
|
||||
getMin, getAvg, getMax, getTime, getMilli, compress, decompress, log,
|
||||
getFirstDefinedItem,
|
||||
compareArray,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user