Skip to content

Commit

Permalink
added dynamic changing color thresholds (#45)
Browse files Browse the repository at this point in the history
    Added sort to thresholds

    Rename threshold option

    Improved accuracy

    Merge color threshold options into one

    Initial dynamic color support
  • Loading branch information
kalkih committed Feb 13, 2019
1 parent 331e7fe commit 70507bf
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 25 deletions.
18 changes: 18 additions & 0 deletions graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ export default class Graph {
return path;
}

computeGradient(thresholds, fallback) {
const length = 100 / this.coords.length;
const coords = this._calcY(this.coords);
let next;
let last = coords[0];
coords.shift();
return coords.map((coord, i) => {
next = coord;
const sum = (next[V] + last[V]) / 2;
last = next;
return {
offset: length * i + length,
color: fallback,
...thresholds.find(ele => ele.value < sum),
};
});
}

getFill(path) {
const height = this.height + this.margin[Y] * 2;
let fill = path;
Expand Down
74 changes: 50 additions & 24 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class MiniGraphCard extends LitElement {
this.line = [];
this.fill = [];
this.points = [];
this.gradient = [];
this.tooltip = {};
this.updateQueue = [];
}
Expand Down Expand Up @@ -88,6 +89,8 @@ class MiniGraphCard extends LitElement {
throw new Error(`The "entity" option was removed, please use "entities".\n See ${URL_DOCS}`);
if (!Array.isArray(config.entities))
throw new Error(`Please provide the "entities" option as a list.\n See ${URL_DOCS}`);
if (config.line_color_above || config.line_color_below)
throw new Error(`"line_color_above/line_color_below" was removed, please use "color_thresholds".\n See ${URL_DOCS}`);

const conf = {
animate: false,
Expand All @@ -97,8 +100,7 @@ class MiniGraphCard extends LitElement {
hours_to_show: 24,
points_per_hour: 1,
line_color: [...DEFAULT_COLORS],
line_color_above: [],
line_color_below: [],
color_thresholds: [],
line_width: 5,
more_info: true,
...config,
Expand All @@ -114,8 +116,7 @@ class MiniGraphCard extends LitElement {

conf.font_size = (config.font_size / 100) * FONT_SIZE || FONT_SIZE;
conf.hours_to_show = Math.floor(Number(conf.hours_to_show)) || 24;
conf.line_color_above.reverse();
conf.line_color_below.reverse();
conf.color_thresholds.sort((a, b) => b.value - a.value);
if (!this.Graph) {
this.Graph = [];
conf.entities.forEach((entity, index) => {
Expand Down Expand Up @@ -155,9 +156,10 @@ class MiniGraphCard extends LitElement {
<ha-card
class='flex'
?group=${config.group}
?fill=${this.config.show.graph && this.config.show.fill}
?points=${this.config.show.points === 'hover'}
?labels=${this.config.show.labels === 'hover'}
?fill=${config.show.graph && config.show.fill}
?points=${config.show.points === 'hover'}
?labels=${config.show.labels === 'hover'}
?gradient=${config.color_thresholds.length > 0}
?more-info=${config.more_info}
style='font-size: ${config.font_size}px;'
@click=${e => this.handlePopup(e, this.entity[0])}>
Expand Down Expand Up @@ -256,7 +258,7 @@ class MiniGraphCard extends LitElement {
${this.entity.map((entity, i) => html`
<div class='graph__legend__item' @click=${e => this.handlePopup(e, entity)}>
<svg width='10' height='10'>
<rect width='10' height='10' fill=${this.computeColor(entity, i)} />
<rect width='10' height='10' fill=${this.computeColor(entity.state, i)} />
</svg>
<span class='ellipsis'>${this.computeName(i)}</span>
</div>
Expand All @@ -266,13 +268,14 @@ class MiniGraphCard extends LitElement {

renderSvgFill(fill, i) {
if (!fill) return;
const color = this.computeColor(this.entity[i].state, i);
return svg`
<path
class='line--fill'
.id=${i} anim=${this.config.animate} ?init=${this.length[i]}
style="animation-delay: ${this.config.animate ? `${i * 0.5}s` : '0s'}"
fill=${this.computeColor(this.entity[i], i)}
stroke=${this.computeColor(this.entity[i], i)}
fill=${color}
stroke=${color}
stroke-width=${this.config.line_width}
d=${this.fill[i]}
/>`;
Expand All @@ -287,37 +290,57 @@ class MiniGraphCard extends LitElement {
style="animation-delay: ${this.config.animate ? `${i * 0.5}s` : '0s'}"
fill='none'
stroke-dasharray=${this.length[i] || 'none'} stroke-dashoffset=${this.length[i] || 'none'}
stroke=${this.computeColor(this.entity[i], i)}
stroke=${this.gradient[i] ? `url(#grad-${i})` : this.computeColor(this.entity[i].state, i)}
stroke-width=${this.config.line_width}
d=${this.line[i]}
/>`;
}

renderSvgPoints(points, i) {
if (!points) return;
const color = this.computeColor(this.entity[i].state, i);
return svg`
<g class='line--points'
?init=${this.length[i]}
anim=${this.config.animate && this.config.show.points !== 'hover'}
style="animation-delay: ${this.config.animate ? `${i * 0.5 + 0.5}s` : '0s'}"
fill=${this.computeColor(this.entity[i], i)}
stroke=${this.computeColor(this.entity[i], i)}
fill=${color}
stroke=${color}
stroke-width=${this.config.line_width / 2}>
${points.map(point => svg`
${points.map((point, num) => svg`
<circle
class='line--point' .id=${point[3]} .value=${point[2]} .entity=${i}
stroke=${this.gradient[i] ? this.gradient[i][num].color : 'inherit'}
fill=${this.gradient[i] ? this.gradient[i][num].color : 'inherit'}
cx=${point[0]} cy=${point[1]} r=${this.config.line_width}
@mouseover=${e => this.openTooltip(e)}
@mouseout=${() => this.tooltip = {}}
/>`)}
</g>`;
}

renderSvgGradient(gradients) {
if (!gradients) return;
const items = gradients.map((gradient, i) => {
if (!gradient) return;
return svg`
<linearGradient id=${`grad-${i}`}>
${gradient.map(stop => svg`
<stop stop-color=${stop.color}
offset=${`${stop.offset}%`}
/>
`)}
</linearGradient>`;
});
return svg`<defs>${items}</defs>`;
}

renderSvg() {
return svg`
<svg width='100%' height='100%' viewBox='0 0 500 ${this.config.height}'
@click=${e => e.stopPropagation()}>
<g>
${this.renderSvgGradient(this.gradient)}
${this.fill.map((fill, i) => this.renderSvgFill(fill, i))}
${this.line.map((line, i) => this.renderSvgLine(line, i))}
</g>
Expand Down Expand Up @@ -389,17 +412,14 @@ class MiniGraphCard extends LitElement {
return e;
}

computeColor(entity, i) {
const state = Number(entity.state) || 0;
const above = {
color: undefined,
...this.config.line_color_above.find(ele => state > ele.value),
computeColor(inState, i) {
const { color_thresholds, line_color } = this.config;
const state = Number(inState) || 0;
const threshold = {
color: line_color[i],
...color_thresholds.find(ele => ele.value < state),
};
const below = {
color: undefined,
...this.config.line_color_below.find(ele => state < ele.value),
};
return above.color || below.color || this.config.line_color[i] || this.config.line_color[0];
return threshold.color || line_color[0];
}

computeName(index) {
Expand Down Expand Up @@ -455,6 +475,12 @@ class MiniGraphCard extends LitElement {
this.fill[index] = this.Graph[index].getFill(this.line[index]);
if (config.show.points)
this.points[index] = this.Graph[index].getPoints();

if (config.color_thresholds.length > 0)
this.gradient[index] = this.Graph[index].computeGradient(
config.color_thresholds,
config.line_color[index] || config.line_color[0],
);
});
this.line = [...this.line];
}
Expand Down
4 changes: 3 additions & 1 deletion style.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,15 @@ const style = css`
.line--point {
cursor: pointer;
fill: var(--paper-card-background-color, white);
stroke: inherit;
stroke-width: inherit;
transition: fill .15s cubic-bezier(0.215, 0.61, 0.355, 1);
}
.line--point:hover {
fill: inherit;
}
ha-card[gradient] .line--point:hover {
fill: var(--primary-text-color, white);
}
path,
.line--points,
.line--fill {
Expand Down

0 comments on commit 70507bf

Please sign in to comment.