mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
commit
07ecb1b1ee
11 changed files with 263 additions and 3 deletions
|
@ -102,6 +102,14 @@ define(function (require) {
|
|||
}
|
||||
};
|
||||
|
||||
Vis.prototype.hasSchemaAgg = function (schemaName, aggTypeName) {
|
||||
var aggs = this.aggs.bySchemaName[schemaName] || [];
|
||||
return aggs.some(function (agg) {
|
||||
if (!agg.type || !agg.type.name) return false;
|
||||
return agg.type.name === aggTypeName;
|
||||
});
|
||||
};
|
||||
|
||||
return Vis;
|
||||
};
|
||||
});
|
||||
|
|
|
@ -4,6 +4,7 @@ define(function (require) {
|
|||
var $ = require('jquery');
|
||||
|
||||
var PointSeriesChart = Private(require('components/vislib/visualizations/_point_series_chart'));
|
||||
var TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
|
||||
var errors = require('errors');
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
|
@ -266,6 +267,9 @@ define(function (require) {
|
|||
var yScale = this.handler.yAxis.yScale;
|
||||
var minWidth = 20;
|
||||
var minHeight = 20;
|
||||
var addTimeMarker = this._attr.addTimeMarker;
|
||||
var times = this._attr.times || [];
|
||||
var timeMarker;
|
||||
var div;
|
||||
var svg;
|
||||
var width;
|
||||
|
@ -283,6 +287,10 @@ define(function (require) {
|
|||
width = elWidth;
|
||||
height = elHeight - margin.top - margin.bottom;
|
||||
|
||||
if (addTimeMarker) {
|
||||
timeMarker = new TimeMarker(times, xScale, height);
|
||||
}
|
||||
|
||||
if (width < minWidth || height < minHeight) {
|
||||
throw new errors.ContainerTooSmall();
|
||||
}
|
||||
|
@ -333,6 +341,10 @@ define(function (require) {
|
|||
.style('stroke', '#ddd')
|
||||
.style('stroke-width', 1);
|
||||
|
||||
if (addTimeMarker) {
|
||||
timeMarker.render(svg);
|
||||
}
|
||||
|
||||
return svg;
|
||||
});
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ define(function (require) {
|
|||
var moment = require('moment');
|
||||
|
||||
var PointSeriesChart = Private(require('components/vislib/visualizations/_point_series_chart'));
|
||||
var TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
|
||||
var errors = require('errors');
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
|
@ -269,8 +270,12 @@ define(function (require) {
|
|||
var elHeight = this._attr.height = $elem.height();
|
||||
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 addTimeMarker = this._attr.addTimeMarker;
|
||||
var times = this._attr.times || [];
|
||||
var timeMarker;
|
||||
var div;
|
||||
var svg;
|
||||
var width;
|
||||
|
@ -285,6 +290,10 @@ define(function (require) {
|
|||
width = elWidth;
|
||||
height = elHeight - margin.top - margin.bottom;
|
||||
|
||||
if (addTimeMarker) {
|
||||
timeMarker = new TimeMarker(times, xScale, height);
|
||||
}
|
||||
|
||||
if (width < minWidth || height < minHeight) {
|
||||
throw new errors.ContainerTooSmall();
|
||||
}
|
||||
|
@ -325,6 +334,10 @@ define(function (require) {
|
|||
.style('stroke-width', 1);
|
||||
}
|
||||
|
||||
if (addTimeMarker) {
|
||||
timeMarker.render(svg);
|
||||
}
|
||||
|
||||
return svg;
|
||||
});
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ define(function (require) {
|
|||
var errors = require('errors');
|
||||
|
||||
var PointSeriesChart = Private(require('components/vislib/visualizations/_point_series_chart'));
|
||||
var TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
/**
|
||||
|
@ -258,10 +259,14 @@ define(function (require) {
|
|||
var elHeight = this._attr.height = $elem.height();
|
||||
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;
|
||||
|
@ -288,6 +293,10 @@ define(function (require) {
|
|||
width = elWidth - margin.left - margin.right;
|
||||
height = elHeight - margin.top - margin.bottom;
|
||||
|
||||
if (addTimeMarker) {
|
||||
timeMarker = new TimeMarker(times, xScale, height);
|
||||
}
|
||||
|
||||
if (width < minWidth || height < minHeight) {
|
||||
throw new errors.ContainerTooSmall();
|
||||
}
|
||||
|
@ -331,6 +340,10 @@ define(function (require) {
|
|||
.style('stroke', '#ddd')
|
||||
.style('stroke-width', lineStrokeWidth);
|
||||
|
||||
if (addTimeMarker) {
|
||||
timeMarker.render(svg);
|
||||
}
|
||||
|
||||
return svg;
|
||||
});
|
||||
};
|
||||
|
|
74
src/kibana/components/vislib/visualizations/time_marker.js
Normal file
74
src/kibana/components/vislib/visualizations/time_marker.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
define(function (require) {
|
||||
var datemath = require('utils/datemath');
|
||||
|
||||
return function TimeMarkerFactory(d3) {
|
||||
function TimeMarker(times, xScale, height) {
|
||||
if (!(this instanceof TimeMarker)) {
|
||||
return new TimeMarker(times, xScale, height);
|
||||
}
|
||||
|
||||
var currentTimeArr = [{
|
||||
'time': new Date().getTime(),
|
||||
'class': 'time-marker',
|
||||
'color': '#c80000',
|
||||
'opacity': 0.3,
|
||||
'width': 2
|
||||
}];
|
||||
|
||||
this.xScale = xScale;
|
||||
this.height = height;
|
||||
this.times = (times.length) ? times.map(function (d) {
|
||||
return {
|
||||
'time': datemath.parse(d.time),
|
||||
'class': d.class || 'time-marker',
|
||||
'color': d.color || '#c80000',
|
||||
'opacity': d.opacity || 0.3,
|
||||
'width': d.width || 2
|
||||
};
|
||||
}) : currentTimeArr;
|
||||
}
|
||||
|
||||
TimeMarker.prototype._isTimeBasedChart = function (selection) {
|
||||
var data = selection.data();
|
||||
return data.every(function (datum) {
|
||||
return (datum.ordered && datum.ordered.date);
|
||||
});
|
||||
};
|
||||
|
||||
TimeMarker.prototype.render = function (selection) {
|
||||
var self = this;
|
||||
|
||||
// return if not time based chart
|
||||
if (!self._isTimeBasedChart(selection)) return;
|
||||
|
||||
selection.each(function () {
|
||||
d3.select(this).selectAll('time-marker')
|
||||
.data(self.times)
|
||||
.enter().append('line')
|
||||
.attr('class', function (d) {
|
||||
return d.class;
|
||||
})
|
||||
.attr('pointer-events', 'none')
|
||||
.attr('stroke', function (d) {
|
||||
return d.color;
|
||||
})
|
||||
.attr('stroke-width', function (d) {
|
||||
return d.width;
|
||||
})
|
||||
.attr('stroke-opacity', function (d) {
|
||||
return d.opacity;
|
||||
})
|
||||
.attr('x1', function (d) {
|
||||
return self.xScale(d.time);
|
||||
})
|
||||
.attr('x2', function (d) {
|
||||
return self.xScale(d.time);
|
||||
})
|
||||
.attr('y1', self.height)
|
||||
.attr('y2', self.xScale.range()[0]);
|
||||
});
|
||||
};
|
||||
|
||||
return TimeMarker;
|
||||
};
|
||||
});
|
|
@ -484,6 +484,7 @@ define(function (require) {
|
|||
type: 'histogram',
|
||||
params: {
|
||||
addLegend: false,
|
||||
addTimeMarker: true
|
||||
},
|
||||
listeners: {
|
||||
click: function (e) {
|
||||
|
|
|
@ -17,4 +17,10 @@
|
|||
Scale Y-Axis to Data Bounds
|
||||
</label>
|
||||
</div>
|
||||
<div class="vis-option-item" ng-show="vis.hasSchemaAgg('segment', 'date_histogram')">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="vis.params.addTimeMarker" ng-checked="vis.params.addTimeMarker">
|
||||
Current time marker
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,7 +20,9 @@ define(function (require) {
|
|||
scale: 'linear',
|
||||
mode: 'stacked',
|
||||
interpolate: 'linear',
|
||||
defaultYExtents: false
|
||||
defaultYExtents: false,
|
||||
times: [],
|
||||
addTimeMarker: false
|
||||
},
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
modes: ['stacked', 'overlap', 'percentage', 'wiggle', 'silhouette'],
|
||||
|
|
|
@ -16,7 +16,9 @@ define(function (require) {
|
|||
addLegend: true,
|
||||
scale: 'linear',
|
||||
mode: 'stacked',
|
||||
defaultYExtents: false
|
||||
defaultYExtents: false,
|
||||
times: [],
|
||||
addTimeMarker: false
|
||||
},
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
modes: ['stacked', 'percentage', 'grouped'],
|
||||
|
|
|
@ -20,7 +20,9 @@ define(function (require) {
|
|||
drawLinesBetweenPoints: true,
|
||||
radiusRatio: 9,
|
||||
scale: 'linear',
|
||||
defaultYExtents: false
|
||||
defaultYExtents: false,
|
||||
times: [],
|
||||
addTimeMarker: false
|
||||
},
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
editor: require('text!plugins/vis_types/vislib/editors/line.html')
|
||||
|
|
127
test/unit/specs/vislib/visualizations/time_marker.js
Normal file
127
test/unit/specs/vislib/visualizations/time_marker.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
define(function (require) {
|
||||
var angular = require('angular');
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
var fixtures = require('fixtures/fake_hierarchical_data');
|
||||
var series = require('vislib_fixtures/mock_data/date_histogram/_series');
|
||||
var terms = require('vislib_fixtures/mock_data/terms/_columns');
|
||||
|
||||
angular.module('TimeMarkerFactory', ['kibana']);
|
||||
describe('VisLib Time Marker Test Suite', function () {
|
||||
var height = 50;
|
||||
var color = '#ff0000';
|
||||
var opacity = 0.5;
|
||||
var width = 3;
|
||||
var customClass = 'custom-time-marker';
|
||||
var dateMathTimes = ['now-1m', 'now-5m', 'now-15m'];
|
||||
var myTimes = dateMathTimes.map(function (dateMathString) {
|
||||
return {
|
||||
time: dateMathString,
|
||||
class: customClass,
|
||||
color: color,
|
||||
opacity: opacity,
|
||||
width: width
|
||||
};
|
||||
});
|
||||
var getExtent = function (dataArray, func) {
|
||||
return func(dataArray, function (obj) {
|
||||
return func(obj.values, function (d) {
|
||||
return d.x;
|
||||
});
|
||||
});
|
||||
};
|
||||
var times = [];
|
||||
var TimeMarker;
|
||||
var defaultMarker;
|
||||
var customMarker;
|
||||
var selection;
|
||||
var xScale;
|
||||
var minDomain;
|
||||
var maxDomain;
|
||||
var domain;
|
||||
|
||||
beforeEach(function () {
|
||||
module('TimeMarkerFactory');
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (d3, Private) {
|
||||
TimeMarker = Private(require('components/vislib/visualizations/time_marker'));
|
||||
minDomain = getExtent(series.series, d3.min);
|
||||
maxDomain = getExtent(series.series, d3.max);
|
||||
domain = [minDomain, maxDomain];
|
||||
xScale = d3.time.scale().domain(domain).range([0, 500]);
|
||||
defaultMarker = new TimeMarker(times, xScale, height);
|
||||
customMarker = new TimeMarker(myTimes, xScale, height);
|
||||
|
||||
selection = d3.select('body').append('div').attr('class', 'marker');
|
||||
selection.datum(series);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
selection.remove('*');
|
||||
selection = null;
|
||||
defaultMarker = null;
|
||||
});
|
||||
|
||||
describe('_isTimeBaseChart method', function () {
|
||||
var boolean;
|
||||
var newSelection;
|
||||
|
||||
it('should return true when data is time based', function () {
|
||||
boolean = defaultMarker._isTimeBasedChart(selection);
|
||||
expect(boolean).to.be(true);
|
||||
});
|
||||
|
||||
it('should return false when data is not time based', function () {
|
||||
newSelection = selection.datum(terms);
|
||||
boolean = defaultMarker._isTimeBasedChart(newSelection);
|
||||
expect(boolean).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('render method', function () {
|
||||
var lineArray;
|
||||
|
||||
beforeEach(function () {
|
||||
defaultMarker.render(selection);
|
||||
customMarker.render(selection);
|
||||
lineArray = document.getElementsByClassName('custom-time-marker');
|
||||
});
|
||||
|
||||
it('should render the default line', function () {
|
||||
expect(!!$('line.time-marker').length).to.be(true);
|
||||
});
|
||||
|
||||
it('should render the custom (user defined) lines', function () {
|
||||
expect($('line.custom-time-marker').length).to.be(myTimes.length);
|
||||
});
|
||||
|
||||
it('should set the class', function () {
|
||||
Array.prototype.forEach.call(lineArray, function (line) {
|
||||
expect(line.getAttribute('class')).to.be(customClass);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the stroke', function () {
|
||||
Array.prototype.forEach.call(lineArray, function (line) {
|
||||
expect(line.getAttribute('stroke')).to.be(color);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the stroke-opacity', function () {
|
||||
Array.prototype.forEach.call(lineArray, function (line) {
|
||||
expect(+line.getAttribute('stroke-opacity')).to.be(opacity);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the stroke-width', function () {
|
||||
Array.prototype.forEach.call(lineArray, function (line) {
|
||||
expect(+line.getAttribute('stroke-width')).to.be(width);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue