diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index fa0bfbc1351687..cad5d9e3a5bd1a 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -122,6 +122,11 @@ define(function (require) { ); }; + AggConfig.prototype.makeLabel = function () { + if (!this.type) return ''; + return this.type.makeLabel(this); + }; + return AggConfig; }; }); \ No newline at end of file diff --git a/src/kibana/components/vis_types/converters/histogram.js b/src/kibana/components/vis_types/converters/histogram.js index 8be33f03175d49..28f899562cbf42 100644 --- a/src/kibana/components/vis_types/converters/histogram.js +++ b/src/kibana/components/vis_types/converters/histogram.js @@ -1,9 +1,14 @@ define(function (require) { - return function HistogramConverterFn(Private, timefilter) { + return function HistogramConverterFn(Private, timefilter, $compile, $rootScope) { var _ = require('lodash'); + var $ = require('jquery'); var moment = require('moment'); var interval = require('utils/interval'); + var $tooltipScope = $rootScope.$new(); + var $tooltip = $(require('text!components/vis_types/tooltips/histogram.html')); + $compile($tooltip)($tooltipScope); + return function (chart, columns, rows) { // index of color var iColor = _.findIndex(columns, { categoryName: 'group' }); @@ -79,24 +84,41 @@ define(function (require) { // setup the formatter for the label - chart.tooltipFormatter = function (datum) { - var vals = [['x', colX], ['y', colY]] - .map(function (set) { - var axis = set[0]; - var col = set[1]; - var val = datum[axis]; - - var name = (col.field && col.field.name) || col.label || axis; + chart.tooltipFormatter = function (event) { + $tooltipScope.details = columns.map(function (col) { + var datum = event.point; + var aggConfig = col.aggConfig; + + var label; + var val; + + switch (col) { + case colX: + label = 'x'; + val = datum.x; + break; + case colY: + label = 'y'; + val = datum.y; + break; + case colColor: + label = 'color'; + val = datum.label; + break; + } + + label = aggConfig.makeLabel() || (col.field && col.field.name) || label; if (col.field) val = col.field.format.convert(val); - return name + ': ' + val; - }).join('
'); + return { + label: label, + value: val + }; - var out = ''; - if (datum.label) out += colColor.field.name + ': ' + datum.label + '
'; - out += vals; + }); - return out; + $tooltipScope.$apply(); + return $tooltip[0].outerHTML; }; var series = chart.series = []; diff --git a/src/kibana/components/vis_types/converters/pie.js b/src/kibana/components/vis_types/converters/pie.js index e66fdac14e317e..96d0def52256df 100644 --- a/src/kibana/components/vis_types/converters/pie.js +++ b/src/kibana/components/vis_types/converters/pie.js @@ -1,9 +1,14 @@ define(function (require) { - return function HistogramConverterFn(Private, timefilter) { + return function HistogramConverterFn(Private, timefilter, $compile, $rootScope, $sce) { var _ = require('lodash'); + var $ = require('jquery'); var moment = require('moment'); var interval = require('utils/interval'); + var $tooltip = $(require('text!components/vis_types/tooltips/pie.html')); + var $tooltipScope = $rootScope.$new(); + $compile($tooltip)($tooltipScope); + return function (chart, columns, rows) { // Checks for obj.parent.name and @@ -24,31 +29,44 @@ define(function (require) { } // tooltip formatter for pie charts - chart.tooltipFormatter = function (datum) { - function sumValue(sum, cur) { - return sum + cur.value; + chart.tooltipFormatter = function (event) { + var datum = event.point; + var parent; + var sum; + + // the sum of values at all levels/generations is the same, but levels + // are seperated by their parents so the root is the simplest to find + for (parent = datum; parent; parent = parent.parent) { + sum = parent.value; } - // find the root datum - var root = datum; - while (root.parent) root = root.parent; + var rows = $tooltipScope.rows = []; + for (parent = datum; parent.parent; parent = parent.parent) { + var i = parent.depth - 1; + var col = columns[i]; - // the value of the root datum is the sum of every row. coincidental? not certain - var sum = root.value; + // field/agg details + var group = (col.field && col.field.name) || col.label || ('level ' + datum.depth); - var labels = []; - for (var cur = datum; cur.parent; cur = cur.parent) { - var label = cur.name + ': ' + cur.value; - label += ' (' + Math.round((cur.value / sum) * 100) + '%)'; + // field value that defines the bucket + var bucket = parent.name; + if (col.field) bucket = col.field.format.convert(bucket); - if (cur === datum) { - label = '' + label + ''; - } + // metric for the bucket + var val = parent.value; - labels.unshift(label); + rows.unshift({ + spacer: $sce.trustAsHtml(_.repeat(' ', i)), + field: group, + bucket: bucket, + metric: val + ' (' + Math.round((parent.value / sum) * 100) + '%)' + }); } - return labels.join('
'); + $tooltipScope.metricCol = _.find(columns, { categoryName: 'metric' }); + + $tooltipScope.$apply(); + return $tooltip[0].outerHTML; }; diff --git a/src/kibana/components/vis_types/tooltips/histogram.html b/src/kibana/components/vis_types/tooltips/histogram.html new file mode 100644 index 00000000000000..904b1643dc0091 --- /dev/null +++ b/src/kibana/components/vis_types/tooltips/histogram.html @@ -0,0 +1,14 @@ + + + + + + + + + + + + + +
Value
{{detail.label}}{{detail.value}}
\ No newline at end of file diff --git a/src/kibana/components/vis_types/tooltips/pie.html b/src/kibana/components/vis_types/tooltips/pie.html new file mode 100644 index 00000000000000..0c4e4b48b0a8cd --- /dev/null +++ b/src/kibana/components/vis_types/tooltips/pie.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + +
fieldvalue{{metricCol.label}}
{{row.field}}{{row.bucket}}{{row.metric}}
\ No newline at end of file diff --git a/src/kibana/components/vislib/lib/dispatch.js b/src/kibana/components/vislib/lib/dispatch.js index 799f55b9bc3690..393d61b2230ede 100644 --- a/src/kibana/components/vislib/lib/dispatch.js +++ b/src/kibana/components/vislib/lib/dispatch.js @@ -5,16 +5,16 @@ define(function (require) { /** * Events Class */ - function Dispatch(vis, chartData) { + function Dispatch(handler, chartData) { if (!(this instanceof Dispatch)) { - return new Dispatch(vis, chartData); + return new Dispatch(handler, chartData); } - var type = vis._attr.type; + var type = handler._attr.type; - this.vis = vis; + this.handler = handler; this.chartData = chartData; - this.color = type === 'pie' ? vis.data.getPieColorFunc() : vis.data.getColorFunc(); - this._attr = _.defaults(vis._attr || {}, { + this.color = type === 'pie' ? handler.data.getPieColorFunc() : handler.data.getColorFunc(); + this._attr = _.defaults(handler._attr || {}, { yValue: function (d) { return d.y; }, @@ -24,24 +24,48 @@ define(function (require) { // Response to `click` and `hover` events Dispatch.prototype.eventResponse = function (d, i) { - var label = d.label ? d.label : d.name; + var label = d.label; var getYValue = this._attr.yValue; var color = this.color; var chartData = this.chartData; var attr = this._attr; - var vis = this.vis; + var handler = this.handler; return { - value : getYValue(d, i), - point : d, - label : label, - color : color(label), + value: getYValue(d, i), + point: d, + label: label, + color: color(label), pointIndex: i, - series : chartData.series, - config : attr, - data : chartData, - e : d3.event, - vis : vis + series: chartData.series, + config: attr, + data: chartData, + e: d3.event, + handler: handler + }; + }; + + // Pie response to `click` and `hover` events + Dispatch.prototype.pieResponse = function (d, i) { + var label = d.key; + var color = this.color; + var chartData = this.chartData; + var attr = this._attr; + var handler = this.handler; + + return { + value: d.value, + point: d, + label: label, + color: color(label), + pointIndex: i, + children: d.children ? d.children : undefined, + parent: d.parent ? d.parent : undefined, + appConfig: d.appConfig, + config: attr, + data: chartData, + e: d3.event, + handler: handler }; }; diff --git a/src/kibana/components/vislib/lib/handler/handler.js b/src/kibana/components/vislib/lib/handler/handler.js index b207c0f06579ab..6c59a694a74b50 100644 --- a/src/kibana/components/vislib/lib/handler/handler.js +++ b/src/kibana/components/vislib/lib/handler/handler.js @@ -4,7 +4,6 @@ define(function (require) { var Data = Private(require('components/vislib/lib/data')); var Layout = Private(require('components/vislib/lib/layout/layout')); - var Tooltip = Private(require('components/vislib/lib/tooltip')); /* * Handles building all the components of the visualization @@ -34,10 +33,6 @@ define(function (require) { this.chartTitle = opts.chartTitle; this.axisTitle = opts.axisTitle; - if (this._attr.addTooltip) { - this.tooltip = new Tooltip(this.el, this.data.get('tooltipFormatter')); - } - if (this._attr.addLegend && this.data.isLegendShown()) { this.legend = opts.legend; } diff --git a/src/kibana/components/vislib/lib/legend.js b/src/kibana/components/vislib/lib/legend.js index 680231c29e642e..7ff2e1f90f7e2a 100644 --- a/src/kibana/components/vislib/lib/legend.js +++ b/src/kibana/components/vislib/lib/legend.js @@ -25,7 +25,6 @@ define(function (require) { this.el = el; this.labels = labels; this.color = color; - this.tooltip = new Tooltip(this.el, function (d) { return d; }); this._attr = _.defaults(_attr || {}, { // Legend specific attributes 'legendClass' : 'legend-col-wrapper', @@ -109,10 +108,6 @@ define(function (require) { } }); - headerIcon - .datum(['Legend']) - .call(self.tooltip.render()); - visEl.selectAll('.color') .on('mouseover', function (d) { var liClass = '.' + self.colorToClass(self.color(d)); diff --git a/src/kibana/components/vislib/lib/tooltip.js b/src/kibana/components/vislib/lib/tooltip.js index e030df5eba054e..ce4b0e1c35eb8e 100644 --- a/src/kibana/components/vislib/lib/tooltip.js +++ b/src/kibana/components/vislib/lib/tooltip.js @@ -12,18 +12,20 @@ define(function (require) { * el => reference to DOM element * formatter => tooltip formatter */ - function Tooltip(el, formatter) { + function Tooltip(el, formatter, events) { if (!(this instanceof Tooltip)) { - return new Tooltip(el, formatter); + return new Tooltip(el, formatter, events); } this.el = el; - this.tooltipFormatter = formatter; + this.formatter = formatter; + this.events = events; this.tooltipClass = 'vis-tooltip'; this.containerClass = 'vis-wrapper'; } Tooltip.prototype.render = function () { var self = this; + var tooltipFormatter = this.formatter; return function (selection) { @@ -36,62 +38,94 @@ define(function (require) { var tooltipDiv = d3.select('.' + self.tooltipClass); - selection.each(function () { + selection.each(function (data, i) { var element = d3.select(this); - var offset; element .on('mousemove.tip', function (d) { - var mouseMove = { - left: d3.event.clientX, - top: d3.event.clientY - }; - offset = self.getOffsets(mouseMove); - return tooltipDiv.datum(d) - .html(self.tooltipFormatter) + var placement = self.getTooltipPlacement(d3.event); + + // return text and position for tooltip + return tooltipDiv.datum(self.events.eventResponse(d, i)) + .html(tooltipFormatter) .style('visibility', 'visible') - .style('left', mouseMove.left + offset.left + 'px') - .style('top', mouseMove.top + offset.top + 'px'); + .style('left', placement.left + 'px') + .style('top', placement.top + 'px'); }) .on('mouseout.tip', function () { return tooltipDiv.style('visibility', 'hidden') .style('left', '-500px') .style('top', '-500px'); - }); }); }; }; - Tooltip.prototype.getOffsets = function (mouseMove) { - + Tooltip.prototype.getTooltipPlacement = function (event) { var self = this; - var offset = {top: -10, left: 10}; - - if ($(self.el).find('.' + self.containerClass)) { - var container = $(self.el).find('.' + self.containerClass); - var chartXOffset = container.offset().left; - var chartYOffset = container.offset().top; - var chartWidth = container.width(); - var chartHeight = container.height(); - var tip = $('.' + self.tooltipClass)[0]; - var tipWidth = tip.clientWidth; - var tipHeight = tip.clientHeight; - - // change xOffset to keep tooltip within container - // if tip width + xOffset puts it over right edge of container, flip left - // unless flip left puts it over left edge of container - // change yOffset to keep tooltip within container - if (mouseMove.left + offset.left + tipWidth > chartXOffset + chartWidth && - mouseMove.left - tipWidth - 10 > chartXOffset) { - offset.left = -10 - tipWidth; + var OFFSET = 10; + + var chart = $(self.el).find('.' + self.containerClass); + if (!chart.size()) return; + + var chartPos = chart.offset(); + chartPos.right = chartPos.left + chart.outerWidth(); + chartPos.bottom = chartPos.top + chart.outerHeight(); + + var tip = $('.' + self.tooltipClass); + var tipWidth = tip.outerWidth(); + var tipHeight = tip.outerHeight(); + + return _.mapValues({ + left: { + default: event.clientX + OFFSET + } + }); + + // the placements if we were to place the tip east or west + var left = { + east: , + west: event.clientX - tipWidth - OFFSET + }; + + // the placements if we were to place the tip north or south + var top = { + south: event.clientY + OFFSET, + north: event.clientY - tipHeight - OFFSET + }; + + // number of pixels that the toolip would overflow it's far + // side, if we placed it that way. (negative === no overflow) + var overflow = { + north: chartPos.top - top.north, + east: (left.east + tipWidth) - chartPos.right, + south: (top.south + tipHeight) - chartPos.bottom, + west: chartPos.left - left.west + }; + + var placement = {}; + + if (overflow.south > 0) { + if (overflow.north < 0) { + placement.top = top.north; + } else { + placement.top = top.south - overflow.south; } - if (mouseMove.top + tipHeight - 10 > chartYOffset + chartHeight) { - offset.top = chartYOffset + chartHeight; + } else { + placement.top = top.south; + } + + if (overflow.east > 0) { + if (overflow.west < 0) { + placement.left = left.west; + } else { + placement.left = left.east - overflow.east; } + } else { + placement.left = left.east; } - - return offset; + + return placement; }; return Tooltip; diff --git a/src/kibana/components/vislib/styles/main.less b/src/kibana/components/vislib/styles/main.less index 03371f6f57972c..8b8dff8a4bb719 100644 --- a/src/kibana/components/vislib/styles/main.less +++ b/src/kibana/components/vislib/styles/main.less @@ -1,3 +1,4 @@ +@import (reference) "../../../styles/main.less"; @import (reference) "lesshat.less"; /* vislib styles */ @@ -218,12 +219,27 @@ p.rows-label, p.columns-label { font-weight: normal; padding: 8px; background: rgba(70, 82, 93, 0.95); - color: #fff; + color: @gray-lighter; border-radius: 4px; position: fixed; z-index: 120; word-wrap: break-word; max-width: 40%; + + table { + td,th { + padding: 2px 4px; + } + + tr { + border-bottom: 1px solid @gray; + } + + // only apply to tr in the body, not the header + tbody tr:last-child { + border-bottom: none; + } + } } .rect { diff --git a/src/kibana/components/vislib/visualizations/_chart.js b/src/kibana/components/vislib/visualizations/_chart.js index c1a19e8f89eaae..2d939f5d013c1b 100644 --- a/src/kibana/components/vislib/visualizations/_chart.js +++ b/src/kibana/components/vislib/visualizations/_chart.js @@ -4,21 +4,30 @@ define(function (require) { var Legend = Private(require('components/vislib/lib/legend')); var Dispatch = Private(require('components/vislib/lib/dispatch')); + var Tooltip = Private(require('components/vislib/lib/tooltip')); /* * Base Class for all visualizations. * Exposes a render method. */ - function Chart(vis, el, chartData) { + function Chart(handler, el, chartData) { if (!(this instanceof Chart)) { - return new Chart(vis, el, chartData); + return new Chart(handler, el, chartData); } - this.vis = vis; + this.handler = handler; this.chartEl = el; this.chartData = chartData; - this.events = new Dispatch(vis, chartData); - this._attr = _.defaults(vis._attr || {}, {}); + var events = this.events = new Dispatch(handler, chartData); + + if (handler._attr.addTooltip) { + var $el = this.handler.el; + var formatter = this.handler.data.get('tooltipFormatter'); + // Add tooltip + this.tooltip = new Tooltip($el, formatter, events); + } + + this._attr = _.defaults(handler._attr || {}, {}); } // Render the visualization. diff --git a/src/kibana/components/vislib/visualizations/column_chart.js b/src/kibana/components/vislib/visualizations/column_chart.js index fc608c7324fd62..e0db32bb983c53 100644 --- a/src/kibana/components/vislib/visualizations/column_chart.js +++ b/src/kibana/components/vislib/visualizations/column_chart.js @@ -13,14 +13,14 @@ define(function (require) { * Column chart visualization => vertical bars, stacked bars */ _(ColumnChart).inherits(Chart); - function ColumnChart(vis, chartEl, chartData) { + function ColumnChart(handler, chartEl, chartData) { if (!(this instanceof ColumnChart)) { - return new ColumnChart(vis, chartEl, chartData); + return new ColumnChart(handler, chartEl, chartData); } ColumnChart.Super.apply(this, arguments); // Column chart specific attributes - this._attr = _.defaults(vis._attr || {}, { + this._attr = _.defaults(handler._attr || {}, { xValue: function (d, i) { return d.x; }, yValue: function (d, i) { return d.y; } }); @@ -46,10 +46,10 @@ define(function (require) { ColumnChart.prototype.addBars = function (svg, layers) { var self = this; var data = this.chartData; - var color = this.vis.data.getColorFunc(); - var xScale = this.vis.xAxis.xScale; - var yScale = this.vis.yAxis.yScale; - var tooltip = this.vis.tooltip; + var color = this.handler.data.getColorFunc(); + var xScale = this.handler.xAxis.xScale; + var yScale = this.handler.yAxis.yScale; + var tooltip = this.tooltip; var isTooltip = this._attr.addTooltip; var layer; var bars; @@ -117,7 +117,7 @@ define(function (require) { ColumnChart.prototype.addBarEvents = function (svg, bars, brush) { var events = this.events; var dispatch = this.events._attr.dispatch; - var xScale = this.vis.xAxis.xScale; + var xScale = this.handler.xAxis.xScale; var startXInv; bars @@ -158,7 +158,7 @@ define(function (require) { ColumnChart.prototype.draw = function () { // Attributes var self = this; - var xScale = this.vis.xAxis.xScale; + var xScale = this.handler.xAxis.xScale; var $elem = $(this.chartEl); var margin = this._attr.margin; var elWidth = this._attr.width = $elem.width(); diff --git a/src/kibana/components/vislib/visualizations/line_chart.js b/src/kibana/components/vislib/visualizations/line_chart.js index 9e8215731b63c1..20341636fc8d59 100644 --- a/src/kibana/components/vislib/visualizations/line_chart.js +++ b/src/kibana/components/vislib/visualizations/line_chart.js @@ -9,14 +9,14 @@ define(function (require) { require('css!components/vislib/styles/main'); _(LineChart).inherits(Chart); - function LineChart(vis, chartEl, chartData) { + function LineChart(handler, chartEl, chartData) { if (!(this instanceof LineChart)) { - return new LineChart(vis, chartEl, chartData); + return new LineChart(handler, chartEl, chartData); } LineChart.Super.apply(this, arguments); // Line chart specific attributes - this._attr = _.defaults(vis._attr || {}, { + this._attr = _.defaults(handler._attr || {}, { interpolate: 'linear', xValue: function (d) { return d.x; }, yValue: function (d) { return d.y; } @@ -54,13 +54,13 @@ define(function (require) { LineChart.prototype.addCircles = function (svg, data) { var self = this; - var color = this.vis.data.getColorFunc(); - var xScale = this.vis.xAxis.xScale; - var yScale = this.vis.yAxis.yScale; - var ordered = this.vis.data.get('ordered'); + var color = this.handler.data.getColorFunc(); + var xScale = this.handler.xAxis.xScale; + var yScale = this.handler.yAxis.yScale; + var ordered = this.handler.data.get('ordered'); var circleRadius = 4; var circleStrokeWidth = 1; - var tooltip = this.vis.tooltip; + var tooltip = this.tooltip; var isTooltip = this._attr.addTooltip; var layer; var circles; @@ -121,11 +121,11 @@ define(function (require) { LineChart.prototype.addLines = function (svg, data) { var self = this; - var xScale = this.vis.xAxis.xScale; - var yScale = this.vis.yAxis.yScale; - var xAxisFormatter = this.vis.data.get('xAxisFormatter'); - var color = this.vis.data.getColorFunc(); - var ordered = this.vis.data.get('ordered'); + var xScale = this.handler.xAxis.xScale; + var yScale = this.handler.yAxis.yScale; + var xAxisFormatter = this.handler.data.get('xAxisFormatter'); + var color = this.handler.data.getColorFunc(); + var ordered = this.handler.data.get('ordered'); var interpolate = this._attr.interpolate; var line = d3.svg.line() .interpolate(interpolate) @@ -190,7 +190,7 @@ define(function (require) { var margin = this._attr.margin; var elWidth = this._attr.width = $elem.width(); var elHeight = this._attr.height = $elem.height(); - var xScale = this.vis.xAxis.xScale; + var xScale = this.handler.xAxis.xScale; var chartToSmallError = 'The height and/or width of this container is too small for this chart.'; var minWidth = 20; var minHeight = 20; diff --git a/src/kibana/components/vislib/visualizations/pie_chart.js b/src/kibana/components/vislib/visualizations/pie_chart.js index ae3ecd73685408..7bab0fafc2f83c 100644 --- a/src/kibana/components/vislib/visualizations/pie_chart.js +++ b/src/kibana/components/vislib/visualizations/pie_chart.js @@ -13,13 +13,13 @@ define(function (require) { * Column chart visualization => vertical bars, stacked bars */ _(PieChart).inherits(Chart); - function PieChart(vis, chartEl, chartData) { + function PieChart(handler, chartEl, chartData) { if (!(this instanceof PieChart)) { - return new PieChart(vis, chartEl, chartData); + return new PieChart(handler, chartEl, chartData); } PieChart.Super.apply(this, arguments); - this._attr = _.defaults(vis._attr || {}, { + this._attr = _.defaults(handler._attr || {}, { getSize: function (d) { return d.size; }, dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout') }); @@ -35,11 +35,11 @@ define(function (require) { .classed('hover', true) .style('cursor', 'pointer'); - dispatch.hover(events.eventResponse(d, i)); + dispatch.hover(events.pieResponse(d, i)); d3.event.stopPropagation(); }) .on('click.pie', function clickPie(d, i) { - dispatch.click(events.eventResponse(d, i)); + dispatch.click(events.pieResponse(d, i)); d3.event.stopPropagation(); }) .on('mouseout.pie', function mouseOutPie() { @@ -51,7 +51,7 @@ define(function (require) { PieChart.prototype.addPath = function (width, height, svg, slices) { var isDonut = this._attr.isDonut; var radius = Math.min(width, height) / 2; - var color = this.vis.data.getPieColorFunc(); + var color = this.handler.data.getPieColorFunc(); var partition = d3.layout.partition() .sort(null) .value(function (d) { @@ -80,7 +80,7 @@ define(function (require) { .outerRadius(function (d) { return Math.max(0, y(d.y + d.dy)); }); - var tooltip = this.vis.tooltip; + var tooltip = this.tooltip; var isTooltip = this._attr.addTooltip; var self = this; var path; @@ -100,8 +100,7 @@ define(function (require) { .style('fill', function (d) { if (d.depth === 0) { return 'none'; } return color(d.name); - }) - .attr('fill-rule', 'evenodd'); + }); // Add tooltip if (isTooltip) { diff --git a/src/kibana/utils/_mixins.js b/src/kibana/utils/_mixins.js index 35a5a51b3bb2bf..bff58654633c7c 100644 --- a/src/kibana/utils/_mixins.js +++ b/src/kibana/utils/_mixins.js @@ -159,6 +159,11 @@ define(function (require) { chunks[i] = arr.slice(start, start + size); } return chunks; + }, + repeat: function (string, times) { + var out = ''; + for (var i = 0; i < times; i++) out += string; + return out; } }); diff --git a/test/unit/index.html b/test/unit/index.html index d89eaaf654192f..1417fd1c3ac6b4 100644 --- a/test/unit/index.html +++ b/test/unit/index.html @@ -24,6 +24,7 @@ config: '/config', test_utils: '../../test/utils', fixtures: '../../test/unit/fixtures', + vislib_fixtures: '../../test/unit/specs/vislib/fixture', specs: '../../test/unit/specs', sinon: '../../test/utils/sinon', bluebird: 'bower_components/bluebird/js/browser/bluebird', diff --git a/test/unit/specs/vislib/fixture/mock_data/series/data0.js b/test/unit/specs/vislib/fixture/mock_data/series/data0.js new file mode 100644 index 00000000000000..d19981be0c21db --- /dev/null +++ b/test/unit/specs/vislib/fixture/mock_data/series/data0.js @@ -0,0 +1,412 @@ +define(function (require) { + var moment = require('moment'); + + return { + 'label': '', + 'xAxisLabel': '@timestamp per 30 sec', + 'ordered': { + 'date': true, + 'min': 1411761457636, + 'max': 1411762357636, + 'interval': 30000 + }, + 'yAxisLabel': 'Count of documents', + 'series': [ + { + 'values': [ + { + 'x': 1411761450000, + 'y': 21 + }, + { + 'x': 1411761480000, + 'y': 18 + }, + { + 'x': 1411761510000, + 'y': 22 + }, + { + 'x': 1411761540000, + 'y': 17 + }, + { + 'x': 1411761570000, + 'y': 17 + }, + { + 'x': 1411761600000, + 'y': 21 + }, + { + 'x': 1411761630000, + 'y': 16 + }, + { + 'x': 1411761660000, + 'y': 17 + }, + { + 'x': 1411761690000, + 'y': 15 + }, + { + 'x': 1411761720000, + 'y': 19 + }, + { + 'x': 1411761750000, + 'y': 11 + }, + { + 'x': 1411761780000, + 'y': 13 + }, + { + 'x': 1411761810000, + 'y': 24 + }, + { + 'x': 1411761840000, + 'y': 20 + }, + { + 'x': 1411761870000, + 'y': 20 + }, + { + 'x': 1411761900000, + 'y': 21 + }, + { + 'x': 1411761930000, + 'y': 17 + }, + { + 'x': 1411761960000, + 'y': 20 + }, + { + 'x': 1411761990000, + 'y': 13 + }, + { + 'x': 1411762020000, + 'y': 14 + }, + { + 'x': 1411762050000, + 'y': 25 + }, + { + 'x': 1411762080000, + 'y': 17 + }, + { + 'x': 1411762110000, + 'y': 14 + }, + { + 'x': 1411762140000, + 'y': 22 + }, + { + 'x': 1411762170000, + 'y': 14 + }, + { + 'x': 1411762200000, + 'y': 19 + }, + { + 'x': 1411762230000, + 'y': 22 + }, + { + 'x': 1411762260000, + 'y': 17 + }, + { + 'x': 1411762290000, + 'y': 8 + }, + { + 'x': 1411762320000, + 'y': 15 + }, + { + 'x': 1411762350000, + 'y': 4 + } + ] + } + ], + 'raw': { + 'splitColumns': [], + 'splitValStack': [], + 'columns': [ + { + 'categoryName': 'segment', + 'id': 'agg_12', + 'aggConfig': { + 'type': 'date_histogram', + 'schema': 'segment', + 'params': { + 'field': '@timestamp', + 'interval': 'auto', + 'min_doc_count': 1, + 'extended_bounds': {} + } + }, + 'aggType': { + 'name': 'date_histogram', + 'title': 'Date Histogram', + 'ordered': { + 'date': true + }, + 'hasNoDsl': false, + 'params': [ + { + 'name': 'field', + 'filterFieldTypes': 'date' + }, + { + 'name': 'interval', + 'default': 'auto', + 'options': [ + { + 'display': 'Auto', + 'val': 'auto' + }, + { + 'display': 'Second', + 'val': 'second', + 'ms': 1000 + }, + { + 'display': 'Minute', + 'val': 'minute', + 'ms': 60000 + }, + { + 'display': 'Hourly', + 'val': 'hour', + 'ms': 3600000 + }, + { + 'display': 'Daily', + 'val': 'day', + 'ms': 86400000 + }, + { + 'display': 'Weekly', + 'val': 'week', + 'ms': 604800000 + }, + { + 'display': 'Monthly', + 'val': 'month', + 'ms': 2592000000 + }, + { + 'display': 'Yearly', + 'val': 'year', + 'ms': 31536000000 + } + ], + 'editor': '
\n \n \n \n \n
\n' + }, + { + 'name': 'format' + }, + { + 'name': 'min_doc_count', + 'default': 1 + }, + { + 'name': 'extended_bounds', + 'default': {} + } + ], + 'type': 'buckets' + }, + 'field': { + 'type': 'date', + 'indexed': true, + 'analyzed': false, + 'doc_values': false, + 'name': '@timestamp', + 'count': 0 + }, + 'label': '@timestamp per 30 sec', + 'params': { + 'field': '@timestamp', + 'interval': '30000ms', + 'min_doc_count': 1, + 'extended_bounds': { + 'min': '2014-09-26T19:57:37.633Z', + 'max': '2014-09-26T20:12:37.633Z' + } + }, + 'metricScaleText': '30 sec' + }, + { + 'categoryName': 'metric', + 'id': 'agg_11', + 'aggConfig': { + 'type': 'count', + 'schema': 'metric', + 'params': {} + }, + 'aggType': { + 'name': 'count', + 'title': 'Count', + 'hasNoDsl': true, + 'params': [], + 'type': 'metrics' + }, + 'label': 'Count of documents', + 'params': {} + } + ], + 'rows': [ + [ + 1411761450000, + 21 + ], + [ + 1411761480000, + 18 + ], + [ + 1411761510000, + 22 + ], + [ + 1411761540000, + 17 + ], + [ + 1411761570000, + 17 + ], + [ + 1411761600000, + 21 + ], + [ + 1411761630000, + 16 + ], + [ + 1411761660000, + 17 + ], + [ + 1411761690000, + 15 + ], + [ + 1411761720000, + 19 + ], + [ + 1411761750000, + 11 + ], + [ + 1411761780000, + 13 + ], + [ + 1411761810000, + 24 + ], + [ + 1411761840000, + 20 + ], + [ + 1411761870000, + 20 + ], + [ + 1411761900000, + 21 + ], + [ + 1411761930000, + 17 + ], + [ + 1411761960000, + 20 + ], + [ + 1411761990000, + 13 + ], + [ + 1411762020000, + 14 + ], + [ + 1411762050000, + 25 + ], + [ + 1411762080000, + 17 + ], + [ + 1411762110000, + 14 + ], + [ + 1411762140000, + 22 + ], + [ + 1411762170000, + 14 + ], + [ + 1411762200000, + 19 + ], + [ + 1411762230000, + 22 + ], + [ + 1411762260000, + 17 + ], + [ + 1411762290000, + 8 + ], + [ + 1411762320000, + 15 + ], + [ + 1411762350000, + 4 + ] + ] + }, + 'hits': 533, + 'xAxisFormatter': function (thing) { + return moment(thing); + }, + 'tooltipFormatter': function (d) { + return d; + } + }; +}); diff --git a/test/unit/specs/vislib/fixture/vis_fixture.js b/test/unit/specs/vislib/fixture/vis_fixture.js new file mode 100644 index 00000000000000..f2c7fb727f9b48 --- /dev/null +++ b/test/unit/specs/vislib/fixture/vis_fixture.js @@ -0,0 +1,21 @@ +define(function (require) { + return function VisLibFixtures(Private) { + var $ = require('jquery'); + + return function (type) { + var Vis = Private(require('components/vislib/vis')); + var visChart = $('body').append('
'); + var $el = $('.visualize-chart'); + var config = { + shareYAxis: true, + addTooltip: true, + addLegend: true, + addEvents: true, + addBrushing: true, + type: type + }; + + return new Vis($el, config); + }; + }; +}); \ No newline at end of file diff --git a/test/unit/specs/vislib/tooltip.js b/test/unit/specs/vislib/tooltip.js index 27f50e60b291ad..2bf763cda61e33 100644 --- a/test/unit/specs/vislib/tooltip.js +++ b/test/unit/specs/vislib/tooltip.js @@ -6,38 +6,9 @@ define(function (require) { angular.module('TooltipFactory', ['kibana']); describe('Vislib Tooltip', function () { - var Tooltip; - var bars; - var tip; - var el; - var chart; - - var data = [ - { - x: 10, - y: 8 - }, - { - x: 11, - y: 23 - }, - { - x: 12, - y: 30 - }, - { - x: 13, - y: 28 - }, - { - x: 14, - y: 36 - }, - { - x: 15, - y: 30 - } - ]; + var vis; + var data; + var tooltips = []; beforeEach(function () { module('TooltipFactory'); @@ -45,55 +16,44 @@ define(function (require) { beforeEach(function () { inject(function (d3, Private) { - Tooltip = Private(require('components/vislib/lib/tooltip')); - - el = d3.select('body') - .append('div') - .attr('class', 'vis-col-wrapper') - .style('width', '40px') - .style('height', '40px'); + vis = Private(require('vislib_fixtures/vis_fixture'))('histogram'); + data = require('vislib_fixtures/mock_data/series/data0'); + require('css!components/vislib/styles/main'); - tip = new Tooltip(el[0][0], function (d) { - return 'd.x: ' + d.x + ', d.y: ' + d.y; + vis.render(data); + vis.handler.charts.forEach(function (chart) { + tooltips.push(chart.tooltip); }); - - chart = el.append('div').attr('class', 'chart'); - el.append('div').attr('class', 'y-axis-col-wrapper'); - el.append('div').attr('class', 'k4tip'); - - bars = chart.selectAll('div') - .data(data) - .enter() - .append('div') - .attr('class', 'bars') - .style('width', function (d) { - return d.y; - }) - .style('height', '10px') - .text(function (d) { - return d.y; - }); - - bars.call(tip.render()); - - // d3.select('.bars').on('mousemove.tip')(d3.select('.bars').node().__data__, 0); }); - - - }); + // Placeholder until we know better regarding garbage collection afterEach(function () { - el.remove(); + $(vis.el).remove(); + vis = null; }); - it('should be an object', function () { - expect(_.isObject(Tooltip)).to.be(true); - }); + describe('render Method', function () { + var isObject; + var isFunction; + + beforeEach(function () { + _.forEach(tooltips, function (tooltip) { + isObject = _.isObject(tooltip); + isFunction = _.isFunction(tooltip.render()); + }); + }); - it('should return a function', function () { - expect(typeof Tooltip).to.be('function'); + it('should be an object', function () { + expect(isObject).to.be(true); + }); + + it('should return a function', function () { + expect(isFunction).to.be(true); + }); }); + + describe('getOffsets Method', function () {}); }); });