mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Merge branch 'master' into pinned-filters
This commit is contained in:
commit
b5b406ffb5
36 changed files with 626 additions and 166 deletions
|
@ -45,7 +45,7 @@ define(function (require) {
|
|||
queue.forEach(function (q) { q.reject(err); });
|
||||
})
|
||||
.finally(function () {
|
||||
$rootScope.$emit('change:config', updated.concat(deleted));
|
||||
$rootScope.$broadcast('change:config', updated.concat(deleted));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -70,7 +70,7 @@ define(function (require) {
|
|||
var defer = Promise.defer();
|
||||
queue.push(defer);
|
||||
notify.log('config change: ' + key + ': ' + oldVal + ' -> ' + newVal);
|
||||
$rootScope.$emit('change:config.' + key, newVal, oldVal);
|
||||
$rootScope.$broadcast('change:config.' + key, newVal, oldVal);
|
||||
|
||||
// reset the fire timer
|
||||
clearTimeout(timer);
|
||||
|
@ -80,4 +80,4 @@ define(function (require) {
|
|||
};
|
||||
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,7 +19,7 @@ define(function (require) {
|
|||
|
||||
var angular = require('angular');
|
||||
var _ = require('lodash');
|
||||
var defaults = require('components/config/defaults');
|
||||
var defaults = Private(require('components/config/defaults'));
|
||||
var DelayedUpdater = Private(require('components/config/_delayed_updater'));
|
||||
var vals = Private(require('components/config/_vals'));
|
||||
|
||||
|
@ -123,6 +123,29 @@ define(function (require) {
|
|||
if (updater) updater.fire();
|
||||
};
|
||||
|
||||
/**
|
||||
* A little helper for binding config variables to $scopes
|
||||
*
|
||||
* @param {Scope} $scope - an angular $scope object
|
||||
* @param {string} key - the config key to bind to
|
||||
* @param {string} [property] - optional property name where the value should
|
||||
* be stored. Defaults to the config key
|
||||
* @return {function} - an unbind function
|
||||
*/
|
||||
config.$bind = function ($scope, key, property) {
|
||||
if (!property) property = key;
|
||||
|
||||
var update = function () {
|
||||
$scope[property] = config.get(key);
|
||||
};
|
||||
|
||||
update();
|
||||
return _.partial(_.invoke, [
|
||||
$scope.$on('change:config.' + key, update),
|
||||
$scope.$on('init:config', update)
|
||||
], 'call');
|
||||
};
|
||||
|
||||
/*****
|
||||
* PRIVATE API
|
||||
*****/
|
||||
|
|
|
@ -1,86 +1,93 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function () {
|
||||
var _ = require('lodash');
|
||||
|
||||
return {
|
||||
'query:queryString:options': {
|
||||
value: '{ "analyze_wildcard": true }',
|
||||
description: 'Options for the lucene query string parser',
|
||||
type: 'json'
|
||||
},
|
||||
'dateFormat': {
|
||||
value: 'MMMM Do YYYY, HH:mm:ss.SSS',
|
||||
description: 'When displaying a pretty formatted date, use this format',
|
||||
},
|
||||
'dateFormat:scaled': {
|
||||
type: 'json',
|
||||
value:
|
||||
'[\n' +
|
||||
' ["", "hh:mm:ss.SSS"],\n' +
|
||||
' ["PT1S", "HH:mm:ss"],\n' +
|
||||
' ["PT1M", "HH:mm"],\n' +
|
||||
' ["PT1H",\n' +
|
||||
' "YYYY-MM-DD HH:mm"],\n' +
|
||||
' ["P1DT", "YYYY-MM-DD"],\n' +
|
||||
' ["P1YT", "YYYY"]\n' +
|
||||
']',
|
||||
description: 'Values that define the format used in situations where timebased' +
|
||||
' data is rendered in order, and formatted timestamps should adapt to the' +
|
||||
' interval between measurements. Keys are ISO 8601 intervals:' +
|
||||
' http://en.wikipedia.org/wiki/ISO_8601#Time_intervals'
|
||||
},
|
||||
'defaultIndex': {
|
||||
value: null,
|
||||
description: 'The index to access if no index is set',
|
||||
},
|
||||
'metaFields': {
|
||||
value: ['_source', '_id', '_type', '_index'],
|
||||
description: 'Fields that exist outside of _source to merge into our document when displaying it',
|
||||
},
|
||||
'discover:sampleSize': {
|
||||
value: 500,
|
||||
description: 'The number of rows to show in the table',
|
||||
},
|
||||
'fields:popularLimit': {
|
||||
value: 10,
|
||||
description: 'The top N most popular fields to show',
|
||||
},
|
||||
'format:numberPrecision': {
|
||||
value: 3,
|
||||
description: 'Round numbers to this many decimal places',
|
||||
},
|
||||
'histogram:barTarget': {
|
||||
value: 50,
|
||||
description: 'Attempt to generate around this many bar when using "auto" interval in date histograms',
|
||||
},
|
||||
'histogram:maxBars': {
|
||||
value: 100,
|
||||
description: 'Never show more than this many bar in date histograms, scale values if needed',
|
||||
},
|
||||
'visualization:tileMap:maxPrecision': {
|
||||
value: 7,
|
||||
description: 'The maximum geoHash precision displayed on tile maps: 7 is high, 10 is very high, ' +
|
||||
'12 is the max. Explanation of cell dimensions: http://www.elastic.co/guide/en/elasticsearch/reference/current/' +
|
||||
'search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator',
|
||||
},
|
||||
'csv:separator': {
|
||||
value: ',',
|
||||
description: 'Separate exported values with this string',
|
||||
},
|
||||
'csv:quoteValues': {
|
||||
value: true,
|
||||
description: 'Should values be quoted in csv exports?',
|
||||
},
|
||||
'history:limit': {
|
||||
value: 10,
|
||||
description: 'In fields that have history (e.g. query inputs), show this many recent values',
|
||||
},
|
||||
'shortDots:enable': {
|
||||
value: false,
|
||||
description: 'Shorten long fields, for example, instead of foo.bar.baz, show f.b.baz',
|
||||
},
|
||||
'truncate:maxHeight': {
|
||||
value: 115,
|
||||
description: 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.'
|
||||
}
|
||||
return {
|
||||
'query:queryString:options': {
|
||||
value: '{ "analyze_wildcard": true }',
|
||||
description: 'Options for the lucene query string parser',
|
||||
type: 'json'
|
||||
},
|
||||
'dateFormat': {
|
||||
value: 'MMMM Do YYYY, HH:mm:ss.SSS',
|
||||
description: 'When displaying a pretty formatted date, use this format',
|
||||
},
|
||||
'dateFormat:scaled': {
|
||||
type: 'json',
|
||||
value:
|
||||
'[\n' +
|
||||
' ["", "hh:mm:ss.SSS"],\n' +
|
||||
' ["PT1S", "HH:mm:ss"],\n' +
|
||||
' ["PT1M", "HH:mm"],\n' +
|
||||
' ["PT1H",\n' +
|
||||
' "YYYY-MM-DD HH:mm"],\n' +
|
||||
' ["P1DT", "YYYY-MM-DD"],\n' +
|
||||
' ["P1YT", "YYYY"]\n' +
|
||||
']',
|
||||
description: 'Values that define the format used in situations where timebased' +
|
||||
' data is rendered in order, and formatted timestamps should adapt to the' +
|
||||
' interval between measurements. Keys are ISO 8601 intervals:' +
|
||||
' http://en.wikipedia.org/wiki/ISO_8601#Time_intervals'
|
||||
},
|
||||
'defaultIndex': {
|
||||
value: null,
|
||||
description: 'The index to access if no index is set',
|
||||
},
|
||||
'metaFields': {
|
||||
value: ['_source', '_id', '_type', '_index'],
|
||||
description: 'Fields that exist outside of _source to merge into our document when displaying it',
|
||||
},
|
||||
'discover:sampleSize': {
|
||||
value: 500,
|
||||
description: 'The number of rows to show in the table',
|
||||
},
|
||||
'fields:popularLimit': {
|
||||
value: 10,
|
||||
description: 'The top N most popular fields to show',
|
||||
},
|
||||
'format:numberPrecision': {
|
||||
value: 3,
|
||||
description: 'Round numbers to this many decimal places',
|
||||
},
|
||||
'histogram:barTarget': {
|
||||
value: 50,
|
||||
description: 'Attempt to generate around this many bar when using "auto" interval in date histograms',
|
||||
},
|
||||
'histogram:maxBars': {
|
||||
value: 100,
|
||||
description: 'Never show more than this many bar in date histograms, scale values if needed',
|
||||
},
|
||||
'visualization:tileMap:maxPrecision': {
|
||||
value: 7,
|
||||
description: 'The maximum geoHash precision displayed on tile maps: 7 is high, 10 is very high, ' +
|
||||
'12 is the max. Explanation of cell dimensions: http://www.elastic.co/guide/en/elasticsearch/reference/current/' +
|
||||
'search-aggregations-bucket-geohashgrid-aggregation.html#_cell_dimensions_at_the_equator',
|
||||
},
|
||||
'csv:separator': {
|
||||
value: ',',
|
||||
description: 'Separate exported values with this string',
|
||||
},
|
||||
'csv:quoteValues': {
|
||||
value: true,
|
||||
description: 'Should values be quoted in csv exports?',
|
||||
},
|
||||
'history:limit': {
|
||||
value: 10,
|
||||
description: 'In fields that have history (e.g. query inputs), show this many recent values',
|
||||
},
|
||||
'shortDots:enable': {
|
||||
value: false,
|
||||
description: 'Shorten long fields, for example, instead of foo.bar.baz, show f.b.baz',
|
||||
},
|
||||
'truncate:maxHeight': {
|
||||
value: 115,
|
||||
description: 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.'
|
||||
},
|
||||
'indexPattern:fieldMapping:lookBack': {
|
||||
value: 5,
|
||||
description: 'For index patterns containing timestamps in their names, look for this many recent matching ' +
|
||||
'patterns from which to query the field mapping.'
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<th width="1%"></th>
|
||||
<th ng-if="indexPattern.timeFieldName">
|
||||
<span ng-click="sort(indexPattern.timeFieldName)" tooltip="Sort by time">Time <i ng-class="headerClass(indexPattern.timeFieldName)"></i></span>
|
||||
<span>Time <i ng-class="headerClass(indexPattern.timeFieldName)" ng-click="sort(indexPattern.timeFieldName)" tooltip="Sort by time"></i></span>
|
||||
</th>
|
||||
<th ng-repeat="name in columns">
|
||||
<span class="table-header-name">
|
||||
|
@ -11,4 +11,4 @@
|
|||
<i ng-click="moveLeft(name)" class="fa fa-angle-double-left" ng-show="!$first" tooltip="Move column to the left" tooltip-append-to-body="1"></i>
|
||||
<i ng-click="moveRight(name)" class="fa fa-angle-double-right" ng-show="!$last" tooltip="Move column to the right" tooltip-append-to-body="1"></i>
|
||||
</span>
|
||||
</th>
|
||||
</th>
|
||||
|
|
|
@ -12,7 +12,7 @@ define(function (require) {
|
|||
require('filters/short_dots');
|
||||
|
||||
|
||||
// guestimate at the minimum number of chars wide cells in the table should be
|
||||
// guesstimate at the minimum number of chars wide cells in the table should be
|
||||
var MIN_LINE_LENGTH = 20;
|
||||
|
||||
/**
|
||||
|
@ -235,4 +235,4 @@ define(function (require) {
|
|||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -49,9 +49,7 @@
|
|||
tooltip-placement="top"
|
||||
tooltip="Objects in arrays are not well supported."
|
||||
class="fa fa-warning text-color-warning ng-scope doc-viewer-object-array"></i>
|
||||
<span class="doc-viewer-value" ng-bind-html="(typeof(formatted[field]) === 'undefined' ? hit[field] : formatted[field]) | highlight : hit.highlight[field] | trustAsHtml"></span>
|
||||
|
||||
|
||||
<div class="doc-viewer-value" ng-bind-html="(typeof(formatted[field]) === 'undefined' ? hit[field] : formatted[field]) | highlight : hit.highlight[field] | trustAsHtml"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
define(function (require) {
|
||||
return function MapperService(Private, Promise, es, configFile) {
|
||||
return function MapperService(Private, Promise, es, configFile, config) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
|
||||
|
@ -51,7 +51,7 @@ define(function (require) {
|
|||
promise = self.getIndicesForIndexPattern(indexPattern)
|
||||
.then(function (existing) {
|
||||
if (existing.matches.length === 0) throw new IndexPatternMissingIndices();
|
||||
return existing.matches.slice(-5); // Grab the most recent 5
|
||||
return existing.matches.slice(-config.get('indexPattern:fieldMapping:lookBack')); // Grab the most recent
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ define(function (require) {
|
|||
|
||||
if (self.shouldAutoReload(next, prev)) {
|
||||
var appState = getAppState();
|
||||
appState.destroy();
|
||||
if (appState) appState.destroy();
|
||||
|
||||
reloading = $rootScope.$on('$locationChangeSuccess', function () {
|
||||
// call the "unlisten" function returned by $on
|
||||
reloading();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
});
|
||||
|
|
|
@ -512,30 +512,24 @@ define(function (require) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Checks whether all pie slices have zero values.
|
||||
* If so, an error is thrown.
|
||||
* Removes zeros from pie chart data
|
||||
* @param slices
|
||||
* @returns {*}
|
||||
*/
|
||||
Data.prototype._validatePieData = function () {
|
||||
var visData = this.getVisData();
|
||||
Data.prototype._removeZeroSlices = function (slices) {
|
||||
var self = this;
|
||||
|
||||
visData.forEach(function (chartData) {
|
||||
chartData.slices = (function withoutZeroSlices(slices) {
|
||||
if (!slices.children) return slices;
|
||||
if (!slices.children) return slices;
|
||||
|
||||
slices = _.clone(slices);
|
||||
slices.children = slices.children.reduce(function (children, child) {
|
||||
if (child.size !== 0) {
|
||||
children.push(withoutZeroSlices(child));
|
||||
}
|
||||
return children;
|
||||
}, []);
|
||||
return slices;
|
||||
}(chartData.slices));
|
||||
|
||||
if (chartData.slices.children.length === 0) {
|
||||
throw new errors.PieContainsAllZeros();
|
||||
slices = _.clone(slices);
|
||||
slices.children = slices.children.reduce(function (children, child) {
|
||||
if (child.size !== 0) {
|
||||
children.push(self._removeZeroSlices(child));
|
||||
}
|
||||
});
|
||||
return children;
|
||||
}, []);
|
||||
|
||||
return slices;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -547,12 +541,12 @@ define(function (require) {
|
|||
*/
|
||||
Data.prototype.pieNames = function () {
|
||||
var self = this;
|
||||
var data = this.getVisData();
|
||||
var names = [];
|
||||
|
||||
this._validatePieData();
|
||||
|
||||
_.forEach(this.getVisData(), function (obj) {
|
||||
_.forEach(data, function (obj) {
|
||||
var columns = obj.raw ? obj.raw.columns : undefined;
|
||||
obj.slices = self._removeZeroSlices(obj.slices);
|
||||
|
||||
_.forEach(self.getNames(obj, columns), function (name) {
|
||||
names.push(name);
|
||||
|
|
|
@ -138,14 +138,14 @@ define(function (require) {
|
|||
// legend
|
||||
legendDiv.selectAll('li')
|
||||
.filter(function (d) {
|
||||
return this.getAttribute('data-label') !== label;
|
||||
return this.getAttribute('data-label') !== label.toString();
|
||||
})
|
||||
.classed('blur_shape', true);
|
||||
|
||||
// all data-label attribute
|
||||
charts.selectAll('[data-label]')
|
||||
.filter(function (d) {
|
||||
return this.getAttribute('data-label') !== label;
|
||||
return this.getAttribute('data-label') !== label.toString();
|
||||
})
|
||||
.classed('blur_shape', true);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
define(function (require) {
|
||||
return function ChartBaseClass(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
var errors = require('errors');
|
||||
|
||||
var Dispatch = Private(require('components/vislib/lib/dispatch'));
|
||||
var Tooltip = Private(require('components/vislib/components/tooltip/tooltip'));
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
};
|
||||
|
|
|
@ -24,11 +24,26 @@ define(function (require) {
|
|||
}
|
||||
PieChart.Super.apply(this, arguments);
|
||||
|
||||
var charts = this.handler.data.getVisData();
|
||||
this._validatePieData(charts);
|
||||
|
||||
this._attr = _.defaults(handler._attr || {}, {
|
||||
isDonut: handler._attr.isDonut || false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether pie slices have all zero values.
|
||||
* If so, an error is thrown.
|
||||
*/
|
||||
PieChart.prototype._validatePieData = function (charts) {
|
||||
var isAllZeros = charts.every(function (chart) {
|
||||
return chart.slices.children.length === 0;
|
||||
});
|
||||
|
||||
if (isAllZeros) { throw new errors.PieContainsAllZeros(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds Events to SVG paths
|
||||
*
|
||||
|
@ -150,6 +165,15 @@ define(function (require) {
|
|||
return path;
|
||||
};
|
||||
|
||||
PieChart.prototype._validateContainerSize = function (width, height) {
|
||||
var minWidth = 20;
|
||||
var minHeight = 20;
|
||||
|
||||
if (width <= minWidth || height <= minHeight) {
|
||||
throw new errors.ContainerTooSmall();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders d3 visualization
|
||||
*
|
||||
|
@ -162,17 +186,15 @@ define(function (require) {
|
|||
return function (selection) {
|
||||
selection.each(function (data) {
|
||||
var slices = data.slices;
|
||||
var el = this;
|
||||
var div = d3.select(el);
|
||||
var width = $(el).width();
|
||||
var height = $(el).height();
|
||||
var minWidth = 20;
|
||||
var minHeight = 20;
|
||||
var div = d3.select(this);
|
||||
var width = $(this).width();
|
||||
var height = $(this).height();
|
||||
var path;
|
||||
|
||||
if (width <= minWidth || height <= minHeight) {
|
||||
throw new errors.ContainerTooSmall();
|
||||
}
|
||||
if (!slices.children.length) return;
|
||||
|
||||
self.convertToPercentage(slices);
|
||||
self._validateContainerSize(width, height);
|
||||
|
||||
var svg = div.append('svg')
|
||||
.attr('width', width)
|
||||
|
@ -180,7 +202,6 @@ define(function (require) {
|
|||
.append('g')
|
||||
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
||||
|
||||
self.convertToPercentage(slices);
|
||||
path = self.addPath(width, height, svg, slices);
|
||||
self.addPathEvents(path);
|
||||
|
||||
|
|
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;
|
||||
};
|
||||
});
|
|
@ -485,6 +485,7 @@ define(function (require) {
|
|||
type: 'histogram',
|
||||
params: {
|
||||
addLegend: false,
|
||||
addTimeMarker: true
|
||||
},
|
||||
listeners: {
|
||||
click: function (e) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var configDefaults = require('components/config/defaults');
|
||||
|
||||
require('modules').get('apps/settings')
|
||||
.directive('advancedRow', function (config, Notifier, Private) {
|
||||
|
@ -13,6 +12,7 @@ define(function (require) {
|
|||
configs: '='
|
||||
},
|
||||
link: function ($scope) {
|
||||
var configDefaults = Private(require('components/config/defaults'));
|
||||
var notify = new Notifier();
|
||||
var keyCodes = {
|
||||
ESC: 27
|
||||
|
@ -66,4 +66,4 @@ define(function (require) {
|
|||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var configDefaults = require('components/config/defaults');
|
||||
var getValType = require('plugins/settings/sections/advanced/lib/get_val_type');
|
||||
|
||||
|
||||
|
@ -16,6 +15,7 @@ define(function (require) {
|
|||
return {
|
||||
restrict: 'E',
|
||||
link: function ($scope) {
|
||||
var configDefaults = Private(require('components/config/defaults'));
|
||||
var keyCodes = {
|
||||
ESC: 27
|
||||
};
|
||||
|
@ -70,4 +70,4 @@ define(function (require) {
|
|||
display: 'Advanced',
|
||||
url: '#/settings/advanced'
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,11 +22,8 @@ define(function (require) {
|
|||
template: require('text!plugins/settings/sections/indices/index.html'),
|
||||
link: function ($scope) {
|
||||
$scope.edittingId = $route.current.params.id;
|
||||
$scope.defaultIndex = config.get('defaultIndex');
|
||||
$rootScope.$on('change:config.defaultIndex', function () {
|
||||
$scope.defaultIndex = config.get('defaultIndex');
|
||||
});
|
||||
|
||||
config.$bind($scope, 'defaultIndex');
|
||||
$scope.$watch('defaultIndex', function (defaultIndex) {
|
||||
$scope.indexPatternList = _($route.current.locals.indexPatternIds)
|
||||
.map(function (id) {
|
||||
|
@ -50,4 +47,4 @@ define(function (require) {
|
|||
display: 'Indices',
|
||||
url: '#/settings/indices',
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -15,19 +15,19 @@ kbn-table, .kbn-table, tbody[kbn-rows] {
|
|||
dl.source {
|
||||
margin-bottom: 0;
|
||||
line-height: 2em;
|
||||
word-break: break-all;
|
||||
|
||||
dt, dd {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
dt {
|
||||
display: inline;
|
||||
background: @gray-lighter;
|
||||
padding: @padding-xs-vertical @padding-xs-horizontal;
|
||||
margin-right: @padding-xs-horizontal;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
dd {
|
||||
display: inline;
|
||||
word-break: break-all;
|
||||
word-break: normal;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ define(function (require) {
|
|||
'=' : '-equal-'
|
||||
};
|
||||
_.each(trans, function (val, key) {
|
||||
var regex = new RegExp(key);
|
||||
var regex = new RegExp(key, 'g');
|
||||
id = id.replace(regex, val);
|
||||
});
|
||||
id = id.replace(/[\s]+/g, '-');
|
||||
|
|
|
@ -16,6 +16,17 @@ function checkPath(path) {
|
|||
}
|
||||
}
|
||||
|
||||
// Set defaults for config file stuff
|
||||
kibana.port = kibana.port || 5601;
|
||||
kibana.host = kibana.host || '0.0.0.0';
|
||||
kibana.elasticsearch_url = kibana.elasticsearch_url || 'http://localhost:9200';
|
||||
kibana.maxSockets = kibana.maxSockets || Infinity;
|
||||
kibana.log_file = kibana.log_file || null;
|
||||
|
||||
kibana.request_timeout = kibana.startup_timeout == null ? 0 : kibana.request_timeout;
|
||||
kibana.ping_timeout = kibana.ping_timeout == null ? kibana.request_timeout : kibana.ping_timeout;
|
||||
kibana.startup_timeout = kibana.startup_timeout == null ? 5000 : kibana.startup_timeout;
|
||||
|
||||
// Check if the local public folder is present. This means we are running in
|
||||
// the NPM module. If it's not there then we are running in the git root.
|
||||
var public_folder = path.resolve(__dirname, '..', 'public');
|
||||
|
@ -33,13 +44,10 @@ try {
|
|||
packagePath = path.resolve(__dirname, '..', '..', '..', 'package.json');
|
||||
}
|
||||
|
||||
var requestTimeout = kibana.request_timeout || 0;
|
||||
var pingTimeout = kibana.ping_timeout == null ? requestTimeout : kibana.ping_timeout;
|
||||
|
||||
var config = module.exports = {
|
||||
port : kibana.port || 5601,
|
||||
host : kibana.host || '0.0.0.0',
|
||||
elasticsearch : kibana.elasticsearch_url || 'http://localhost:9200',
|
||||
port : kibana.port,
|
||||
host : kibana.host,
|
||||
elasticsearch : kibana.elasticsearch_url,
|
||||
root : path.normalize(path.join(__dirname, '..')),
|
||||
quiet : false,
|
||||
public_folder : public_folder,
|
||||
|
@ -49,10 +57,10 @@ var config = module.exports = {
|
|||
package : require(packagePath),
|
||||
htpasswd : htpasswdPath,
|
||||
buildNum : '@@buildNum',
|
||||
maxSockets : kibana.maxSockets || Infinity,
|
||||
log_file : kibana.log_file || null,
|
||||
request_timeout : requestTimeout,
|
||||
ping_timeout : pingTimeout
|
||||
maxSockets : kibana.maxSockets,
|
||||
log_file : kibana.log_file,
|
||||
request_timeout : kibana.request_timeout,
|
||||
ping_timeout : kibana.ping_timeout
|
||||
};
|
||||
|
||||
config.plugins = listPlugins(config);
|
||||
|
|
|
@ -45,6 +45,9 @@ request_timeout: 300000
|
|||
# Set to 0 to disable.
|
||||
shard_timeout: 0
|
||||
|
||||
# Time in milliseconds to wait for Elasticsearch at Kibana startup before retrying
|
||||
# startup_timeout: 5000
|
||||
|
||||
# Set to false to have a complete disregard for the validity of the SSL
|
||||
# certificate.
|
||||
verify_ssl: true
|
||||
|
|
|
@ -6,7 +6,7 @@ var logger = require('./logger');
|
|||
var config = require('../config');
|
||||
|
||||
function waitForPong() {
|
||||
return client.ping()
|
||||
return client.ping({requestTimeout: config.kibana.startup_timeout})
|
||||
.catch(function (err) {
|
||||
if (!(err instanceof NoConnections)) throw err;
|
||||
|
||||
|
|
74
test/unit/specs/components/config.js
Normal file
74
test/unit/specs/components/config.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
define(function (require) {
|
||||
describe('config component', function () {
|
||||
var $scope;
|
||||
var config;
|
||||
var defaults;
|
||||
var configFile;
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function ($injector, Private) {
|
||||
config = $injector.get('config');
|
||||
$scope = $injector.get('$rootScope');
|
||||
configFile = $injector.get('configFile');
|
||||
defaults = Private(require('components/config/defaults'));
|
||||
}));
|
||||
|
||||
it('exposes the configFile', function () {
|
||||
expect(config.file).to.be(configFile);
|
||||
});
|
||||
|
||||
describe('#get', function () {
|
||||
|
||||
it('gives access to config values', function () {
|
||||
expect(config.get('dateFormat')).to.be.a('string');
|
||||
});
|
||||
|
||||
it('reads from the defaults', function () {
|
||||
var initial = config.get('dateFormat');
|
||||
var newDefault = initial + '- new';
|
||||
defaults.dateFormat.value = newDefault;
|
||||
expect(config.get('dateFormat')).to.be(newDefault);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#set', function () {
|
||||
|
||||
it('stores a value in the config val set', function () {
|
||||
var initial = config.get('dateFormat');
|
||||
config.set('dateFormat', 'notaformat');
|
||||
expect(config.get('dateFormat')).to.be('notaformat');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#$bind', function () {
|
||||
|
||||
it('binds a config key to a $scope property', function () {
|
||||
var dateFormat = config.get('dateFormat');
|
||||
config.$bind($scope, 'dateFormat');
|
||||
expect($scope).to.have.property('dateFormat', dateFormat);
|
||||
});
|
||||
|
||||
it('alows overriding the property name', function () {
|
||||
var dateFormat = config.get('dateFormat');
|
||||
config.$bind($scope, 'dateFormat', 'defaultDateFormat');
|
||||
expect($scope).to.not.have.property('dateFormat');
|
||||
expect($scope).to.have.property('defaultDateFormat', dateFormat);
|
||||
});
|
||||
|
||||
it('keeps the property up to date', function () {
|
||||
var dateFormat = config.get('dateFormat');
|
||||
var newDateFormat = dateFormat + ' NEW NEW NEW!';
|
||||
config.$bind($scope, 'dateFormat');
|
||||
|
||||
expect($scope).to.have.property('dateFormat', dateFormat);
|
||||
config.set('dateFormat', newDateFormat);
|
||||
expect($scope).to.have.property('dateFormat', newDateFormat);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -16,7 +16,11 @@ define(function (require) {
|
|||
['test / ^test', 'test-slash-^test'],
|
||||
['test ? test', 'test-questionmark-test'],
|
||||
['test = test', 'test-equal-test'],
|
||||
['test & test', 'test-ampersand-test']
|
||||
['test & test', 'test-ampersand-test'],
|
||||
['test/test/test', 'test-slash-test-slash-test'],
|
||||
['test?test?test', 'test-questionmark-test-questionmark-test'],
|
||||
['test&test&test', 'test-ampersand-test-ampersand-test'],
|
||||
['test=test=test', 'test-equal-test-equal-test']
|
||||
];
|
||||
|
||||
_.each(fixtures, function (fixture) {
|
||||
|
|
|
@ -205,6 +205,37 @@ define(function (require) {
|
|||
|
||||
});
|
||||
|
||||
describe('_removeZeroSlices', function () {
|
||||
var pieData = {
|
||||
slices: {
|
||||
children: [
|
||||
{size: 30},
|
||||
{size: 20},
|
||||
{size: 0}
|
||||
]
|
||||
}
|
||||
};
|
||||
var DataFactory;
|
||||
var data;
|
||||
|
||||
beforeEach(function () {
|
||||
module('DataFactory');
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
inject(function (Private) {
|
||||
DataFactory = Private(require('components/vislib/lib/data'));
|
||||
data = new DataFactory(pieData, {});
|
||||
data._removeZeroSlices(pieData.slices);
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove zero values', function () {
|
||||
var slices = data.data.slices;
|
||||
expect(slices.children.length).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Data.flatten', function () {
|
||||
var DataFactory;
|
||||
var serIn;
|
||||
|
|
|
@ -5,17 +5,20 @@ define(function (require) {
|
|||
|
||||
var slices = require('vislib_fixtures/mock_data/histogram/_slices');
|
||||
var stackedSeries = require('vislib_fixtures/mock_data/date_histogram/_stacked_series');
|
||||
var histogramSlices = require('vislib_fixtures/mock_data/histogram/_slices');
|
||||
|
||||
var dataArray = [
|
||||
stackedSeries,
|
||||
slices,
|
||||
histogramSlices,
|
||||
stackedSeries,
|
||||
stackedSeries,
|
||||
stackedSeries
|
||||
];
|
||||
|
||||
var chartTypes = [
|
||||
'histogram',
|
||||
'pie',
|
||||
'pie',
|
||||
'area',
|
||||
'line'
|
||||
];
|
||||
|
@ -24,7 +27,7 @@ define(function (require) {
|
|||
histogram: '.chart rect',
|
||||
pie: '.chart path',
|
||||
area: '.chart path',
|
||||
line: '.chart circle',
|
||||
line: '.chart circle'
|
||||
};
|
||||
|
||||
angular.module('LegendFactory', ['kibana']);
|
||||
|
|
|
@ -118,6 +118,41 @@ define(function (require) {
|
|||
expect($(chart1.el).find('.y-axis-chart-title').length).to.be(1);
|
||||
expect($(chart2.el).find('.x-axis-chart-title').length).to.be(1);
|
||||
});
|
||||
|
||||
describe('_validatePieData method', function () {
|
||||
var allZeros = [
|
||||
{ slices: { children: [] } },
|
||||
{ slices: { children: [] } },
|
||||
{ slices: { children: [] } }
|
||||
];
|
||||
|
||||
var someZeros = [
|
||||
{ slices: { children: [{}] } },
|
||||
{ slices: { children: [{}] } },
|
||||
{ slices: { children: [] } }
|
||||
];
|
||||
|
||||
var noZeros = [
|
||||
{ slices: { children: [{}] } },
|
||||
{ slices: { children: [{}] } },
|
||||
{ slices: { children: [{}] } }
|
||||
];
|
||||
|
||||
it('should throw an error when all charts contain zeros', function () {
|
||||
expect(function () {
|
||||
chart1.ChartClass.prototype._validatePieData(allZeros);
|
||||
}).to.throwError();
|
||||
});
|
||||
|
||||
it('should not throw an error when only some or no charts contain zeros', function () {
|
||||
expect(function () {
|
||||
chart1.ChartClass.prototype._validatePieData(someZeros);
|
||||
}).to.not.throwError();
|
||||
expect(function () {
|
||||
chart1.ChartClass.prototype._validatePieData(noZeros);
|
||||
}).to.not.throwError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
aggArray.forEach(function (dataAgg, i) {
|
||||
|
|
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