diff --git a/CHANGELOG.md b/CHANGELOG.md index 08006cf7f7..b2be3e6c8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ ### UI Improvements 1. [#1796](https://github.com/influxdata/chronograf/pull/1796): Add spinner to indicate data is being written +1. [#1800](https://github.com/influxdata/chronograf/pull/1796): Embiggen text area for line protocol manual entry in Data Explorer's Write Data overlay +1. [#1805](https://github.com/influxdata/chronograf/pull/1805): Fix bar graphs overlapping +1. [#1805](https://github.com/influxdata/chronograf/pull/1805): Add series names hashing so that graph colors should stay the same for the same series across charts 1. [#1800](https://github.com/influxdata/chronograf/pull/1800): Embiggen text area for line protocol manual entry in Data Explorer's Write Data overlay 1. [#1812](https://github.com/influxdata/chronograf/pull/1812): Improve error message when request for Status Page News Feed fails diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index 697a2ae880..e90fa28fd1 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -11,6 +11,12 @@ import {LINE_COLORS, multiColumnBarPlotter} from 'src/shared/graphs/helpers' import DygraphLegend from 'src/shared/components/DygraphLegend' import {buildYLabel} from 'shared/presenters' +const hasherino = (str, len) => + str + .split('') + .map(char => char.charCodeAt(0)) + .reduce((hash, code) => hash + code, 0) % len + export default class Dygraph extends Component { constructor(props) { super(props) @@ -80,21 +86,29 @@ 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 + + for (const seriesName in dygraphSeries) { + const series = dygraphSeries[seriesName] + const hashIndex = hasherino(seriesName, length) + const color = finalLineColors[hashIndex] + hashColorDygraphSeries[seriesName] = {...series, color} } const yAxis = _.get(axes, ['y', 'bounds'], [null, null]) const y2Axis = _.get(axes, ['y2', 'bounds'], undefined) const defaultOptions = { - plugins: [ - new Dygraphs.Plugins.Crosshair({ - direction: 'vertical', - }), - ], + plugins: isBarGraph + ? [] + : [ + new Dygraphs.Plugins.Crosshair({ + direction: 'vertical', + }), + ], labelsSeparateLines: false, labelsKMB: true, rightGap: 0, @@ -103,12 +117,11 @@ export default class Dygraph extends Component { fillGraph: isGraphFilled, axisLineWidth: 2, gridLineWidth: 1, - highlightCircleSize: 3, + highlightCircleSize: isBarGraph ? 0 : 3, animatedZooms: true, hideOverlayOnMouseOut: false, colors: finalLineColors, - series: dygraphSeries, - ylabel: this.getLabel('y'), + series: hashColorDygraphSeries, axes: { y: { valueRange: getRange(timeSeries, yAxis, ruleValues), @@ -119,7 +132,7 @@ export default class Dygraph extends Component { }, highlightSeriesOpts: { strokeWidth: 2, - highlightCircleSize: 5, + highlightCircleSize: isBarGraph ? 0 : 5, }, legendFormatter: legend => { if (!legend.x) { @@ -259,6 +272,7 @@ export default class Dygraph extends Component { dygraphSeries, ruleValues, isBarGraph, + overrideLineColors, } = this.props const dygraph = this.dygraph @@ -272,6 +286,17 @@ export default class Dygraph extends Component { const y2 = _.get(axes, ['y2', 'bounds'], undefined) const timeSeries = this.getTimeSeries() const ylabel = this.getLabel('y') + const finalLineColors = [...(overrideLineColors || LINE_COLORS)] + + const hashColorDygraphSeries = {} + const {length} = finalLineColors + + for (const seriesName in dygraphSeries) { + const series = dygraphSeries[seriesName] + const hashIndex = hasherino(seriesName, length) + const color = finalLineColors[hashIndex] + hashColorDygraphSeries[seriesName] = {...series, color} + } const updateOptions = { labels, @@ -288,7 +313,8 @@ export default class Dygraph extends Component { stepPlot: options.stepPlot, stackedGraph: options.stackedGraph, underlayCallback: options.underlayCallback, - series: dygraphSeries, + colors: finalLineColors, + series: hashColorDygraphSeries, plotter: isBarGraph ? multiColumnBarPlotter : null, visibility: this.visibility(), } diff --git a/ui/src/shared/graphs/helpers.js b/ui/src/shared/graphs/helpers.js index a0dc843722..33786c8b5e 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,34 @@ export const multiColumnBarPlotter = e => { } } - const barWidth = Math.floor(2.0 / 3 * minSep) + // calculate bar width using some graphics math while + // ensuring a bar is never smaller than one px, so it is always rendered + const barWidth = Math.max(Math.floor(2.0 / 3.0 * minSep), 1.0) 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 + : centerX - barWidth * (1 - j / sets.length) ctx.fillRect( xLeft, @@ -77,12 +87,15 @@ export const multiColumnBarPlotter = e => { yBottom - p.canvasy ) - ctx.strokeRect( - xLeft, - p.canvasy, - barWidth / sets.length, - yBottom - p.canvasy - ) + // hover highlighting + if (selPointX === centerX) { + ctx.strokeRect( + xLeft, + p.canvasy, + barWidth / sets.length, + yBottom - p.canvasy + ) + } } } }