diff --git a/public/app/plugins/panel/heatmap/heatmap_ctrl.ts b/public/app/plugins/panel/heatmap/heatmap_ctrl.ts index c47af640af2..df07c60ff28 100644 --- a/public/app/plugins/panel/heatmap/heatmap_ctrl.ts +++ b/public/app/plugins/panel/heatmap/heatmap_ctrl.ts @@ -5,12 +5,7 @@ import TimeSeries from 'app/core/time_series2'; import { axesEditor } from './axes_editor'; import { heatmapDisplayEditor } from './display_editor'; import rendering from './rendering'; -import { - convertToHeatMap, - convertToCards, - elasticHistogramToHeatmap, - calculateBucketSize, -} from './heatmap_data_converter'; +import { convertToHeatMap, convertToCards, histogramToHeatmap, calculateBucketSize } from './heatmap_data_converter'; let X_BUCKET_NUMBER_DEFAULT = 30; let Y_BUCKET_NUMBER_DEFAULT = 10; @@ -139,12 +134,13 @@ export class HeatmapCtrl extends MetricsPanelCtrl { return; } - let xBucketSize, yBucketSize, heatmapStats, bucketsData; + let xBucketSize, yBucketSize, heatmapStats, bucketsData, tsBuckets; let logBase = this.panel.yAxis.logBase; if (this.panel.dataFormat === 'tsbuckets') { heatmapStats = this.parseHistogramSeries(this.series); - bucketsData = elasticHistogramToHeatmap(this.series); + bucketsData = histogramToHeatmap(this.series); + tsBuckets = _.map(this.series, 'label'); // Calculate bucket size based on ES heatmap data let xBucketBoundSet = _.map(_.keys(bucketsData), key => Number(key)); @@ -210,6 +206,10 @@ export class HeatmapCtrl extends MetricsPanelCtrl { cards: cards, cardStats: cardStats, }; + + if (tsBuckets) { + this.data.tsBuckets = tsBuckets; + } } onDataReceived(dataList) { diff --git a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts index bccd62235f5..f580cc585b7 100644 --- a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts +++ b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts @@ -51,6 +51,45 @@ function elasticHistogramToHeatmap(seriesList) { return heatmap; } +function histogramToHeatmap(seriesList) { + let heatmap = {}; + + for (let i = 0; i < seriesList.length; i++) { + let series = seriesList[i]; + let bound = i; + if (isNaN(bound)) { + return heatmap; + } + + for (let point of series.datapoints) { + let count = point[VALUE_INDEX]; + let time = point[TIME_INDEX]; + + if (!_.isNumber(count)) { + continue; + } + + let bucket = heatmap[time]; + if (!bucket) { + bucket = heatmap[time] = { x: time, buckets: {} }; + } + + bucket.buckets[bound] = { + y: bound, + count: count, + bounds: { + top: null, + bottom: bound, + }, + values: [], + points: [], + }; + } + } + + return heatmap; +} + /** * Convert buckets into linear array of "cards" - objects, represented heatmap elements. * @param {Object} buckets @@ -433,6 +472,7 @@ function emptyXOR(foo: any, bar: any): boolean { export { convertToHeatMap, + histogramToHeatmap, elasticHistogramToHeatmap, convertToCards, mergeZeroBuckets, diff --git a/public/app/plugins/panel/heatmap/rendering.ts b/public/app/plugins/panel/heatmap/rendering.ts index 90dac42dc8d..fe2aa46a584 100644 --- a/public/app/plugins/panel/heatmap/rendering.ts +++ b/public/app/plugins/panel/heatmap/rendering.ts @@ -296,6 +296,42 @@ export default function link(scope, elem, attrs, ctrl) { .remove(); } + function addYAxisFromBuckets() { + const tsBuckets = data.tsBuckets; + + scope.yScale = yScale = d3 + .scaleLinear() + .domain([0, tsBuckets.length - 1]) + .range([chartHeight, 0]); + + const tick_values = _.map(tsBuckets, (b, i) => i); + const tickFormatter = val => tsBuckets[val]; + + let yAxis = d3 + .axisLeft(yScale) + .tickValues(tick_values) + .tickFormat(tickFormatter) + .tickSizeInner(0 - width) + .tickSizeOuter(0) + .tickPadding(Y_AXIS_TICK_PADDING); + + heatmap + .append('g') + .attr('class', 'axis axis-y') + .call(yAxis); + + // Calculate Y axis width first, then move axis into visible area + const posY = margin.top; + const posX = getYAxisWidth(heatmap) + Y_AXIS_TICK_PADDING; + heatmap.select('.axis-y').attr('transform', 'translate(' + posX + ',' + posY + ')'); + + // Remove vertical line in the right of axis labels (called domain in d3) + heatmap + .select('.axis-y') + .select('.domain') + .remove(); + } + // Adjust data range to log base function adjustLogRange(min, max, logBase) { let y_min, y_max; @@ -362,10 +398,14 @@ export default function link(scope, elem, attrs, ctrl) { chartTop = margin.top; chartBottom = chartTop + chartHeight; - if (panel.yAxis.logBase === 1) { - addYAxis(); + if (panel.dataFormat === 'tsbuckets') { + addYAxisFromBuckets(); } else { - addLogYAxis(); + if (panel.yAxis.logBase === 1) { + addYAxis(); + } else { + addLogYAxis(); + } } yAxisWidth = getYAxisWidth(heatmap) + Y_AXIS_TICK_PADDING; @@ -414,7 +454,7 @@ export default function link(scope, elem, attrs, ctrl) { addHeatmapCanvas(); addAxes(); - if (panel.yAxis.logBase !== 1) { + if (panel.yAxis.logBase !== 1 && panel.dataFormat !== 'tsbuckets') { let log_base = panel.yAxis.logBase; let domain = yScale.domain(); let tick_values = logScaleTickValues(domain, log_base);