diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts index 92e5ce177e1..bd9c091f313 100755 --- a/public/app/plugins/panel/graph/graph.ts +++ b/public/app/plugins/panel/graph/graph.ts @@ -279,8 +279,14 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) { break; } default: { - if (data.length && data[0].stats.timeStep) { - options.series.bars.barWidth = data[0].stats.timeStep / 1.5; + var width; + for (let i = 0; i < data.length; i++) { + if (data[i].stats.timeStep && (width == null || (data[i].stats.timeStep / 1.5) < width)) { + width = data[i].stats.timeStep / 1.5; + } + } + if (width) { + options.series.bars.barWidth = width; } addTimeAxis(options); break; diff --git a/public/app/plugins/panel/graph/graph_tooltip.js b/public/app/plugins/panel/graph/graph_tooltip.js index 704eb9097ec..697dce0b7ee 100644 --- a/public/app/plugins/panel/graph/graph_tooltip.js +++ b/public/app/plugins/panel/graph/graph_tooltip.js @@ -2,7 +2,7 @@ define([ 'jquery', 'lodash' ], -function ($, _) { +function ($) { 'use strict'; function GraphTooltip(elem, dashboard, scope, getSeriesFn) { @@ -21,7 +21,8 @@ function ($, _) { var initial = last*ps; var len = series.datapoints.points.length; for (var j = initial; j < len; j += ps) { - if (series.datapoints.points[j] > posX) { + if ((series.datapoints.points[initial] != null && series.datapoints.points[j] == null && ! series.lines.steps) + || series.datapoints.points[j] > posX) { return Math.max(j - ps, 0)/ps; } } @@ -51,6 +52,8 @@ function ($, _) { //now we know the current X (j) position for X and Y values var last_value = 0; //needed for stacked values + var minDistance, minTime; + for (i = 0; i < seriesList.length; i++) { series = seriesList[i]; @@ -65,9 +68,16 @@ function ($, _) { } hoverIndex = this.findHoverIndexFromData(pos.x, series); - hoverDistance = Math.abs(pos.x - series.data[hoverIndex][0]); + hoverDistance = pos.x - series.data[hoverIndex][0]; pointTime = series.data[hoverIndex][0]; + if (! minDistance + || (hoverDistance >=0 && (hoverDistance < minDistance || minDistance < 0)) + || (hoverDistance < 0 && hoverDistance > minDistance)) { + minDistance = hoverDistance; + minTime = pointTime; + } + if (series.stack) { if (panel.tooltip.value_type === 'individual') { value = series.data[hoverIndex][1]; @@ -107,7 +117,7 @@ function ($, _) { } // Find point which closer to pointer - results.time = _.min(results, 'distance').time; + results.time = minTime; return results; }; @@ -153,6 +163,8 @@ function ($, _) { seriesHtml = ''; + absoluteTime = dashboard.formatDate(seriesHoverInfo.time, tooltipFormat); + // Dynamically reorder the hovercard for the current time point if the // option is enabled, sort by yaxis by default. if (panel.tooltip.sort === 2) { @@ -169,8 +181,6 @@ function ($, _) { }); } - var distance, time; - for (i = 0; i < seriesHoverInfo.length; i++) { hoverInfo = seriesHoverInfo[i]; @@ -178,11 +188,6 @@ function ($, _) { continue; } - if (! distance || hoverInfo.distance < distance) { - distance = hoverInfo.distance; - time = hoverInfo.time; - } - var highlightClass = ''; if (item && i === item.seriesIndex) { highlightClass = 'graph-tooltip-list-item--highlight'; @@ -198,7 +203,6 @@ function ($, _) { plot.highlight(hoverInfo.index, hoverInfo.hoverIndex); } - absoluteTime = dashboard.formatDate(time, tooltipFormat); self.showTooltip(absoluteTime, seriesHtml, pos); } // single series tooltip diff --git a/public/app/plugins/panel/graph/specs/graph_specs.ts b/public/app/plugins/panel/graph/specs/graph_specs.ts index 9f8d91ca9de..046409b77b2 100644 --- a/public/app/plugins/panel/graph/specs/graph_specs.ts +++ b/public/app/plugins/panel/graph/specs/graph_specs.ts @@ -135,7 +135,7 @@ describe('grafanaGraph', function() { }); it('should set barWidth', function() { - expect(ctx.plotOptions.series.bars.barWidth).to.be(10/1.5); + expect(ctx.plotOptions.series.bars.barWidth).to.be(1/1.5); }); }); diff --git a/public/vendor/flot/jquery.flot.js b/public/vendor/flot/jquery.flot.js index ec91314c49d..e0941bb24c0 100644 --- a/public/vendor/flot/jquery.flot.js +++ b/public/vendor/flot/jquery.flot.js @@ -1201,24 +1201,21 @@ Licensed under the MIT license. points[k + m] = null; } } - else { - // a little bit of line specific stuff that - // perhaps shouldn't be here, but lacking - // better means... - if (insertSteps && k > 0 - && points[k - ps] != null - && points[k - ps] != points[k] - && points[k - ps + 1] != points[k + 1]) { - // copy the point to make room for a middle point - for (m = 0; m < ps; ++m) - points[k + ps + m] = points[k + m]; - // middle point has same y - points[k + 1] = points[k - ps + 1]; + if (insertSteps && k > 0 && (!nullify || points[k - ps] != null)) { + // copy the point to make room for a middle point + for (m = 0; m < ps; ++m) + points[k + ps + m] = points[k + m]; - // we've added a point, better reflect that - k += ps; - } + // middle point has same y + points[k + 1] = points[k - ps + 1] || 0; + + // if series has null values, let's give the last correct value a nice step + if(nullify) + points[k] = p[0]; + + // we've added a point, better reflect that + k += ps; } } } diff --git a/public/vendor/flot/jquery.flot.stack.js b/public/vendor/flot/jquery.flot.stack.js index ffb412ca2a0..ba2a6b86a2f 100644 --- a/public/vendor/flot/jquery.flot.stack.js +++ b/public/vendor/flot/jquery.flot.stack.js @@ -78,41 +78,41 @@ charts or filled areas). i = 0, j = 0, l, m; while (true) { - if (i >= points.length) + if (i >= points.length && j >= otherpoints.length) break; l = newpoints.length; + px = points[i + keyOffset]; + py = points[i + accumulateOffset]; + qx = otherpoints[j + keyOffset]; + qy = otherpoints[j + accumulateOffset]; + bottom = 0; - if (points[i] == null) { - // copy gaps + if (i < points.length && px == null) { + // ignore point + i += ps; + } + else if (j < otherpoints.length && qx == null) { + // ignore point + j += otherps; + } + else if (i >= points.length) { + // take the remaining points from the previous series + for (m = 0; m < ps; ++m) + newpoints.push(otherpoints[j + m]); + bottom = qy; + j += otherps; + } + else if (j >= otherpoints.length) { + // take the remaining points from the current series for (m = 0; m < ps; ++m) newpoints.push(points[i + m]); i += ps; } - else if (j >= otherpoints.length) { - // for lines, we can't use the rest of the points - if (!withlines) { - for (m = 0; m < ps; ++m) - newpoints.push(points[i + m]); - } - i += ps; - } - else if (otherpoints[j] == null) { - // oops, got a gap - for (m = 0; m < ps; ++m) - newpoints.push(null); - fromgap = true; - j += otherps; - } else { // cases where we actually got two points - px = points[i + keyOffset]; - py = points[i + accumulateOffset]; - qx = otherpoints[j + keyOffset]; - qy = otherpoints[j + accumulateOffset]; - bottom = 0; - if (px == qx) { + // take the point from the current series and skip the previous' one for (m = 0; m < ps; ++m) newpoints.push(points[i + m]); @@ -123,54 +123,36 @@ charts or filled areas). j += otherps; } else if (px > qx) { - // we got past point below, might need to - // insert interpolated extra point - if (withlines && i > 0 && points[i - ps] != null) { - intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px); - newpoints.push(qx); - newpoints.push(intery + qy); - for (m = 2; m < ps; ++m) - newpoints.push(points[i + m]); - bottom = qy; - } + // take the point from the previous series so that the next series can stack over it + for (m = 0; m < ps; ++m) + newpoints.push(otherpoints[j + m]); + + // we might be able to interpolate + if (i > 0 && points[i - ps] != null) + newpoints[l + accumulateOffset] += py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px); + + bottom = qy; j += otherps; } else { // px < qx - if (fromgap && withlines) { - // if we come from a gap, we just skip this point - i += ps; - continue; - } - + // take the point from the current series for (m = 0; m < ps; ++m) newpoints.push(points[i + m]); // we might be able to interpolate a point below, // this can give us a better y - if (withlines && j > 0 && otherpoints[j - otherps] != null) + if (j > 0 && otherpoints[j - otherps] != null) bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx); newpoints[l + accumulateOffset] += bottom; i += ps; } + } - fromgap = false; - - if (l != newpoints.length && withbottom) - newpoints[l + 2] += bottom; - } - - // maintain the line steps invariant - if (withsteps && l != newpoints.length && l > 0 - && newpoints[l] != null - && newpoints[l] != newpoints[l - ps] - && newpoints[l + 1] != newpoints[l - ps + 1]) { - for (m = 0; m < ps; ++m) - newpoints[l + ps + m] = newpoints[l + m]; - newpoints[l + 1] = newpoints[l - ps + 1]; - } + if (l != newpoints.length && withbottom) + newpoints[l + 2] = bottom; } datapoints.points = newpoints;