UNPKG

kibana-with-account

Version:

kibana-with-account is develop based kibana project

358 lines (313 loc) 10.7 kB
define(function (require) { return function LineChartFactory(Private) { var d3 = require('d3'); var _ = require('lodash'); var $ = require('jquery'); var errors = require('ui/errors'); var PointSeriesChart = Private(require('ui/vislib/visualizations/_point_series_chart')); var TimeMarker = Private(require('ui/vislib/visualizations/time_marker')); /** * Line Chart Visualization * * @class LineChart * @constructor * @extends Chart * @param handler {Object} Reference to the Handler Class Constructor * @param el {HTMLElement} HTML element to which the chart will be appended * @param chartData {Object} Elasticsearch query results for this specific chart */ _.class(LineChart).inherits(PointSeriesChart); function LineChart(handler, chartEl, chartData) { if (!(this instanceof LineChart)) { return new LineChart(handler, chartEl, chartData); } LineChart.Super.apply(this, arguments); // Line chart specific attributes this._attr = _.defaults(handler._attr || {}, { interpolate: 'linear', xValue: function (d) { return d.x; }, yValue: function (d) { return d.y; } }); } /** * Adds Events to SVG circle * * @method addCircleEvents * @param element{D3.UpdateSelection} Reference to SVG circle * @returns {D3.Selection} SVG circles with event listeners attached */ LineChart.prototype.addCircleEvents = function (element, svg) { var events = this.events; var isBrushable = events.isBrushable(); var brush = isBrushable ? events.addBrushEvent(svg) : undefined; var hover = events.addHoverEvent(); var mouseout = events.addMouseoutEvent(); var click = events.addClickEvent(); var attachedEvents = element.call(hover).call(mouseout).call(click); if (isBrushable) { attachedEvents.call(brush); } return attachedEvents; }; /** * Adds circles to SVG * * @method addCircles * @param svg {HTMLElement} SVG to which rect are appended * @param data {Array} Array of object data points * @returns {D3.UpdateSelection} SVG with circles added */ LineChart.prototype.addCircles = function (svg, data) { var self = this; var showCircles = this._attr.showCircles; 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 tooltip = this.tooltip; var isTooltip = this._attr.addTooltip; var radii = _(data) .map(function (series) { return _.pluck(series, '_input.z'); }) .flattenDeep() .reduce(function (result, val) { if (result.min > val) result.min = val; if (result.max < val) result.max = val; return result; }, { min: Infinity, max: -Infinity }); var radiusStep = ((radii.max - radii.min) || (radii.max * 100)) / Math.pow(this._attr.radiusRatio, 2); var layer = svg.selectAll('.points') .data(data) .enter() .append('g') .attr('class', 'points line'); var circles = layer .selectAll('circle') .data(function appendData(data) { return data.filter(function (d) { return !_.isNull(d.y); }); }); circles .exit() .remove(); function cx(d) { if (ordered && ordered.date) { return xScale(d.x); } return xScale(d.x) + xScale.rangeBand() / 2; } function cy(d) { return yScale(d.y); } function cColor(d) { return color(d.label); } function colorCircle(d) { var parent = d3.select(this).node().parentNode; var lengthOfParent = d3.select(parent).data()[0].length; var isVisible = (lengthOfParent === 1); // If only 1 point exists, show circle if (!showCircles && !isVisible) return 'none'; return cColor(d); } function getCircleRadiusFn(modifier) { return function getCircleRadius(d) { var margin = self._attr.margin; var width = self._attr.width - margin.left - margin.right; var height = self._attr.height - margin.top - margin.bottom; var circleRadius = (d._input.z - radii.min) / radiusStep; return _.min([Math.sqrt((circleRadius || 2) + 2), width, height]) + (modifier || 0); }; } circles .enter() .append('circle') .attr('r', getCircleRadiusFn()) .attr('fill-opacity', (this._attr.drawLinesBetweenPoints ? 1 : 0.7)) .attr('cx', cx) .attr('cy', cy) .attr('class', 'circle-decoration') .call(this._addIdentifier) .attr('fill', colorCircle); circles .enter() .append('circle') .attr('r', getCircleRadiusFn(10)) .attr('cx', cx) .attr('cy', cy) .attr('fill', 'transparent') .attr('class', 'circle') .call(this._addIdentifier) .attr('stroke', cColor) .attr('stroke-width', 0); if (isTooltip) { circles.call(tooltip.render()); } return circles; }; /** * Adds path to SVG * * @method addLines * @param svg {HTMLElement} SVG to which path are appended * @param data {Array} Array of object data points * @returns {D3.UpdateSelection} SVG with paths added */ LineChart.prototype.addLines = function (svg, data) { var self = this; 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.smoothLines) ? 'cardinal' : this._attr.interpolate; var line = d3.svg.line() .defined(function (d) { return !_.isNull(d.y); }) .interpolate(interpolate) .x(function x(d) { if (ordered && ordered.date) { return xScale(d.x); } return xScale(d.x) + xScale.rangeBand() / 2; }) .y(function y(d) { return yScale(d.y); }); var lines; lines = svg .selectAll('.lines') .data(data) .enter() .append('g') .attr('class', 'pathgroup lines'); lines.append('path') .call(this._addIdentifier) .attr('d', function lineD(d) { return line(d.values); }) .attr('fill', 'none') .attr('stroke', function lineStroke(d) { return color(d.label); }) .attr('stroke-width', 2); return lines; }; /** * Adds SVG clipPath * * @method addClipPath * @param svg {HTMLElement} SVG to which clipPath is appended * @param width {Number} SVG width * @param height {Number} SVG height * @returns {D3.UpdateSelection} SVG with clipPath added */ LineChart.prototype.addClipPath = function (svg, width, height) { var clipPathBuffer = 5; var startX = 0; var startY = 0 - clipPathBuffer; var id = 'chart-area' + _.uniqueId(); return svg .attr('clip-path', 'url(#' + id + ')') .append('clipPath') .attr('id', id) .append('rect') .attr('x', startX) .attr('y', startY) .attr('width', width) // Adding clipPathBuffer to height so it doesn't // cutoff the lower part of the chart .attr('height', height + clipPathBuffer); }; /** * Renders d3 visualization * * @method draw * @returns {Function} Creates the line chart */ LineChart.prototype.draw = function () { var self = this; var $elem = $(this.chartEl); var margin = this._attr.margin; var elWidth = this._attr.width = $elem.width(); var elHeight = this._attr.height = $elem.height(); var scaleType = this.handler.yAxis.getScaleType(); var yMin = this.handler.yAxis.yMin; var yScale = this.handler.yAxis.yScale; var xScale = this.handler.xAxis.xScale; var minWidth = 20; var minHeight = 20; var startLineX = 0; var lineStrokeWidth = 1; var addTimeMarker = this._attr.addTimeMarker; var times = this._attr.times || []; var timeMarker; var div; var svg; var width; var height; var lines; var circles; return function (selection) { selection.each(function (data) { var el = this; var layers = data.series.map(function mapSeries(d) { var label = d.label; return d.values.map(function mapValues(e, i) { return { _input: e, label: label, x: self._attr.xValue.call(d.values, e, i), y: self._attr.yValue.call(d.values, e, i) }; }); }); width = elWidth - margin.left - margin.right; height = elHeight - margin.top - margin.bottom; if (addTimeMarker) { timeMarker = new TimeMarker(times, xScale, height); } if (self._attr.scale === 'log' && self._invalidLogScaleValues(data)) { throw new errors.InvalidLogScaleValues(); } if (width < minWidth || height < minHeight) { throw new errors.ContainerTooSmall(); } div = d3.select(el); svg = div.append('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .append('g') .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); self.addClipPath(svg, width, height); if (self._attr.drawLinesBetweenPoints) { lines = self.addLines(svg, data.series); } circles = self.addCircles(svg, layers); self.addCircleEvents(circles, svg); self.createEndZones(svg); var scale = (scaleType === 'log') ? yScale(1) : yScale(0); if (scale) { svg.append('line') .attr('class', 'base-line') .attr('x1', startLineX) .attr('y1', scale) .attr('x2', width) .attr('y2', scale) .style('stroke', '#ddd') .style('stroke-width', lineStrokeWidth); } if (addTimeMarker) { timeMarker.render(svg); } return svg; }); }; }; return LineChart; }; });