From f8b8cc7364ff3815676ad0bd6fc6749fd2ff91e1 Mon Sep 17 00:00:00 2001 From: Hunter Trujillo Date: Fri, 28 Jul 2017 18:20:22 -0600 Subject: [PATCH] Add universal hashed colors algorithm. Fix bar graph column overlap. Remove crosshairs on bar graphs. --- ui/src/shared/components/Dygraph.js | 48 +++++++++++++++++++++++------ ui/src/shared/graphs/helpers.js | 32 ++++++++++++------- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index cfdb06968..02e5ba101 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -10,6 +10,12 @@ import getRange from 'shared/parsing/getRangeForDygraph' import {LINE_COLORS, multiColumnBarPlotter} from 'src/shared/graphs/helpers' import DygraphLegend from 'src/shared/components/DygraphLegend' +const hasherino = (str, len) => + str + .split('') + .map(char => char.charCodeAt(0)) + .reduce((hash, code) => (hash + code) % len, 0) + export default class Dygraph extends Component { constructor(props) { super(props) @@ -65,18 +71,42 @@ export default class Dygraph extends Component { const graphRef = this.graphRef const legendRef = this.legendRef - let finalLineColors = overrideLineColors + const finalLineColors = [...(overrideLineColors || LINE_COLORS)] - if (finalLineColors === null) { - finalLineColors = LINE_COLORS + const hashColorDygraphSeries = {} + const {length} = finalLineColors + + let used = [] + + for (const seriesName in dygraphSeries) { + const series = dygraphSeries[seriesName] + let hashIndex = hasherino(seriesName, length) + + // Check to see if color is already being used + while (used.includes(hashIndex)) { + hashIndex = (hashIndex + 1) % length + } + + used.push(hashIndex) + + // Empty used array if all colors are used + if (used.length === length) { + used = [] + } + + const color = finalLineColors[hashIndex] + + hashColorDygraphSeries[seriesName] = {...series, color} } const defaultOptions = { - plugins: [ - new Dygraphs.Plugins.Crosshair({ - direction: 'vertical', - }), - ], + plugins: isBarGraph + ? [] + : [ + new Dygraphs.Plugins.Crosshair({ + direction: 'vertical', + }), + ], labelsSeparateLines: false, labelsKMB: true, rightGap: 0, @@ -89,7 +119,7 @@ export default class Dygraph extends Component { animatedZooms: true, hideOverlayOnMouseOut: false, colors: finalLineColors, - series: dygraphSeries, + series: hashColorDygraphSeries, axes: { y: { valueRange: getRange(timeSeries, ranges.y, ruleValues), diff --git a/ui/src/shared/graphs/helpers.js b/ui/src/shared/graphs/helpers.js index a0dc84372..2470fafc5 100644 --- a/ui/src/shared/graphs/helpers.js +++ b/ui/src/shared/graphs/helpers.js @@ -26,7 +26,7 @@ export const darkenColor = colorStr => { return `rgb(${color.r},${color.g},${color.b})` } -// Bar Graph code below is from http://dygraphs.com/tests/plotters.html +// Bar Graph code below is adapted from http://dygraphs.com/tests/plotters.html export const multiColumnBarPlotter = e => { // We need to handle all the series simultaneously. if (e.seriesIndex !== 0) { @@ -51,24 +51,32 @@ export const multiColumnBarPlotter = e => { } } - const barWidth = Math.floor(2.0 / 3 * minSep) + const barWidth = Math.max(Math.floor(2.0 / 3.0 * minSep), 1) const fillColors = [] const strokeColors = g.getColors() + + let selPointX + if (g.selPoints_ && g.selPoints_.length) { + selPointX = g.selPoints_[0].canvasx + } + for (let i = 0; i < strokeColors.length; i++) { fillColors.push(darkenColor(strokeColors[i])) } + ctx.lineWidth = 2 + for (let j = 0; j < sets.length; j++) { - ctx.fillStyle = fillColors[j] ctx.strokeStyle = strokeColors[j] for (let i = 0; i < sets[j].length; i++) { const p = sets[j][i] const centerX = p.canvasx + ctx.fillStyle = fillColors[j] const xLeft = sets.length === 1 - ? centerX - barWidth / 2 - : centerX - barWidth / 2 * (1 - j / (sets.length - 1)) + ? centerX - barWidth / 1 + : centerX - barWidth / 1 * (1 - j / sets.length) ctx.fillRect( xLeft, @@ -77,12 +85,14 @@ export const multiColumnBarPlotter = e => { yBottom - p.canvasy ) - ctx.strokeRect( - xLeft, - p.canvasy, - barWidth / sets.length, - yBottom - p.canvasy - ) + if (selPointX === centerX) { + ctx.strokeRect( + xLeft, + p.canvasy, + barWidth / sets.length, + yBottom - p.canvasy + ) + } } } }