mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Merge branch 'master' into truncate_by_height
Conflicts: src/kibana/components/config/defaults.js
This commit is contained in:
commit
aec35efd33
69 changed files with 1451 additions and 386 deletions
4
TODOS.md
4
TODOS.md
|
@ -443,6 +443,10 @@
|
|||
- Now that all calls to _data and _removeData have been replaced
|
||||
- **[src/kibana/components/index_patterns/_mapper.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/index_patterns/_mapper.js)**
|
||||
- Change index to be the resolved in some way, last three months, last hour, last year, whatever
|
||||
- **[src/kibana/components/vis_types/converters/pie.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vis_types/converters/pie.js)**
|
||||
- refactor this code to simplify and possibly merge with data converter code below
|
||||
- **[src/kibana/components/vislib/lib/data.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vislib/lib/data.js)**
|
||||
- need to make this more generic
|
||||
- **[src/kibana/components/vislib/vis.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vislib/vis.js)**
|
||||
- need to come up with a solution for resizing when no data is available
|
||||
- **[src/kibana/components/vislib/visualizations/column_chart.js](https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/vislib/visualizations/column_chart.js)**
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
<div ng-show="!state.panels.length" class="text-center start-screen">
|
||||
<h2>Ready to get started?</h2>
|
||||
<p>Click the <i class="fa fa-plus" ng-click="openAdd()"></i> button in the menu bar above to add a visualization to the dashboard. <br/>If you haven't setup a visualization yet visit the <a href="#/visualize">"Visualize"</a> tab to create your first visualization.</p>
|
||||
<p>Click the <a class="btn btn-xs navbtn-inverse" ng-click="openAdd()"><i class="fa fa-plus"></i></a> button in the menu bar above to add a visualization to the dashboard. <br/>If you haven't setup a visualization yet visit the <a href="#/visualize">"Visualize"</a> tab to create your first visualization.</p>
|
||||
</div>
|
||||
|
||||
<dashboard-grid></dashboard-grid>
|
||||
|
|
|
@ -55,7 +55,7 @@ define(function (require) {
|
|||
var stateDefaults = {
|
||||
title: dash.title,
|
||||
panels: dash.panelsJSON ? JSON.parse(dash.panelsJSON) : [],
|
||||
query: ''
|
||||
query: {query_string: {query: '*'}}
|
||||
};
|
||||
|
||||
var $state = $scope.state = appStateFactory.create(stateDefaults);
|
||||
|
@ -95,7 +95,7 @@ define(function (require) {
|
|||
}
|
||||
|
||||
$scope.newDashboard = function () {
|
||||
$location.url('/dashboard');
|
||||
kbnUrl.change('/dashboard', {}, true);
|
||||
};
|
||||
|
||||
$scope.filterResults = function () {
|
||||
|
|
|
@ -19,12 +19,6 @@ dashboard-grid {
|
|||
margin: 20px;
|
||||
background-color: @gray-lighter;
|
||||
padding: 20px;
|
||||
|
||||
i {
|
||||
padding: 4px 8px;
|
||||
background-color: #3d636b;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.gridster {
|
||||
|
|
|
@ -38,12 +38,12 @@
|
|||
|
||||
<div ng-show="field.indexed && !field.analyzed"
|
||||
ng-click="runAgg(field)"
|
||||
tooltip="Doc_values are not enabled on this field. This operation may be dangerous."
|
||||
tooltip="Doc_values are not enabled on this field. This may lead to excess heap consumption"
|
||||
class="sidebar-item-button warning">Visualize</div>
|
||||
|
||||
<div ng-show="field.indexed && field.analyzed"
|
||||
ng-click="runAgg(field)"
|
||||
tooltip="Analyzed fields may require more memory to visualize. This operation may be dangerous."
|
||||
tooltip="Analyzed fields may require more memory to visualize and may not give you the results you expect."
|
||||
class="sidebar-item-button danger">Visualize</div>
|
||||
|
||||
<div ng-show="!field.indexed"
|
||||
|
|
|
@ -45,7 +45,7 @@ define(function (require) {
|
|||
}
|
||||
});
|
||||
|
||||
app.controller('discover', function ($scope, config, courier, $route, $window, savedSearches, savedVisualizations,
|
||||
app.controller('discover', function ($scope, config, courier, $route, $window, $q, savedSearches, savedVisualizations,
|
||||
Notifier, $location, globalState, appStateFactory, timefilter, Promise, Private, kbnUrl) {
|
||||
|
||||
var Vis = Private(require('components/vis/vis'));
|
||||
|
@ -57,6 +57,8 @@ define(function (require) {
|
|||
location: 'Discover'
|
||||
});
|
||||
|
||||
$scope.timefilter = timefilter;
|
||||
|
||||
// the saved savedSearch
|
||||
var savedSearch = $route.current.locals.savedSearch;
|
||||
$scope.$on('$destroy', savedSearch.destroy);
|
||||
|
@ -209,11 +211,17 @@ define(function (require) {
|
|||
notify.error('An error occured with your request. Reset your inputs and try again.');
|
||||
}).catch(notify.fatal);
|
||||
|
||||
return setupVisualization().then(function () {
|
||||
$scope.updateTime();
|
||||
if ($scope.opts.timefield) {
|
||||
setupVisualization().then(function () {
|
||||
$scope.updateTime();
|
||||
init.complete = true;
|
||||
$scope.$emit('application.load');
|
||||
});
|
||||
} else {
|
||||
init.complete = true;
|
||||
$scope.$emit('application.load');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -582,6 +590,8 @@ define(function (require) {
|
|||
|
||||
var loadingVis;
|
||||
var setupVisualization = function () {
|
||||
// If we're not setting anything up we need to return an empty promise
|
||||
if (!$scope.opts.timefield) return $q.when();
|
||||
if (loadingVis) return loadingVis;
|
||||
|
||||
|
||||
|
|
|
@ -51,12 +51,45 @@
|
|||
|
||||
<!-- no results -->
|
||||
<div class="col-md-10" ng-show="resultState === 'none'">
|
||||
<div class="discover-overlay">
|
||||
<h2>No results found <i class="fa fa-meh-o"></i></h2>
|
||||
<div class="col-md-12">
|
||||
Unfortunately I could not find any results matching your search. I tried really hard. I looked all over the place. Try expanding your search, or increasing your time window if searching by time. I really want to make this work for you. Help me, help you.
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
<h1>No results found <i class="fa fa-meh-o"></i></h1>
|
||||
|
||||
<p>
|
||||
Unfortunately I could not find any results matching your search. I tried really hard. I looked all over the place and frankly, I just couldn't find anything good. Help me, help you. Here's some ideas:
|
||||
</p>
|
||||
|
||||
<div ng-show="opts.timefield">
|
||||
<p>
|
||||
<h3>Expand your time range</h3>
|
||||
<p>I see you are looking at an index with a date field. It is possible your query does not match anything in the current time range, or that there is not data at all in the currently selected time range. Click the button below to open the time picker. For future reference you can open the time picker by clicking the <a class="btn btn-xs navbtn" ng-click="toggleTimepicker()">time picker <i class="fa fa-clock-o"></i></a> in the top right corner of your screen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3>Refine your query</h3>
|
||||
<p>
|
||||
The search bar at the top allows Kibana uses Elasticsearch's support for Lucene Query String syntax. Let's say we're searching web server logs that have been parsed into a few fields.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
<h4>Examples:</h4>
|
||||
Find requests that contain the number 200, in any field:
|
||||
<pre>200</pre>
|
||||
|
||||
Or we can search in a specific field. Find 200 in the status field:
|
||||
<pre>status:200</pre>
|
||||
|
||||
Find all status codes between 400-499:
|
||||
<pre>status:[400 TO 499]</pre>
|
||||
|
||||
Find status codes 400-499 with the extension php:
|
||||
<pre>status:[400 TO 499] AND extension:PHP</pre>
|
||||
|
||||
Or HTML
|
||||
<pre>status:[400 TO 499] AND (extension:php OR extension:html)</pre>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- loading -->
|
||||
|
@ -74,7 +107,7 @@
|
|||
{{ opts.savedSearch.title }}
|
||||
<i tooltip="Reload saved query" ng-click="resetQuery();" class="fa fa-undo smallest small"></i>
|
||||
</h3>
|
||||
<div class="discover-timechart" >
|
||||
<div class="discover-timechart" ng-if="opts.timefield">
|
||||
<center class="small">
|
||||
<span tooltip="To change the time, click the clock icon in the navigation bar">{{timeRange.from | moment}} - {{timeRange.to | moment}}</span>
|
||||
<!-- TODO: Currently no way to apply this setting to the visualization -->
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="conf in configs | filter:advancedFilter" ng-class="conf.value === undefined ? 'default' : 'custom'">
|
||||
<td class="name">{{conf.name}}</td>
|
||||
<td class="name">
|
||||
<b>{{conf.name}}</b><br>
|
||||
<span class="smaller">{{conf.description}}</span>
|
||||
</td>
|
||||
<td class="value">
|
||||
<form
|
||||
ng-if="conf.editting"
|
||||
|
|
|
@ -49,10 +49,11 @@ define(function (require) {
|
|||
.catch(notify.fatal);
|
||||
};
|
||||
|
||||
$scope.configs = _.map(configDefaults, function (defVal, name) {
|
||||
$scope.configs = _.map(configDefaults, function (def, name) {
|
||||
var conf = {
|
||||
name: name,
|
||||
defVal: defVal,
|
||||
defVal: def.value,
|
||||
description: def.description,
|
||||
value: configVals[name]
|
||||
};
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
<kbn-settings-app section="objects">
|
||||
<kbn-settings-objects class="container">
|
||||
<h2>Edit Saved Objects</h2>
|
||||
<div class="bs-callout bs-callout-warning">
|
||||
<h4>Caution: You can break stuff here</h4>
|
||||
Be careful in here, these setting are for very advanced users only. Tweaks you make here can break large poritions of Kibana.
|
||||
Some of these settings may be undocumented, unsupported or experimental. Seriously, if you thought the "Advance" tab was dangerous this is even more extreme!
|
||||
</div>
|
||||
<p>
|
||||
From here you can delete saved objects, such as saved searches. You can also edit the raw data of saved objects. Typically objects are only modified via their associated application, which is probably what you should use instead of this screen.
|
||||
</p>
|
||||
<form>
|
||||
<input ng-model="advancedFilter" class="form-control span12" type="text" placeholder="Filter"/>
|
||||
</form>
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
</div>
|
||||
<h1>Edit {{ title }} Object</h1>
|
||||
<div class="bs-callout bs-callout-warning">
|
||||
<h4>Caution: You can break stuff here</h4>
|
||||
Be careful in here, these setting are for very advanced users only. Tweaks you make here can break large poritions of Kibana.
|
||||
Some of these settings may be undocumented, unsupported or experimental. Seriously, if you thought the "Advance" tab was dangerous this is even more extreme!
|
||||
<h4>Proceed with caution</h4>
|
||||
Modifying objects is for advanced users only. Object properties are not validated and invalid objects could cause errors, data loss, or worse. Unless someone with intimate knowledge of the code told you to be in here, you probably shouldn't be.
|
||||
</div>
|
||||
</div>
|
||||
<form name="objectForm" ng-submit="submit()">
|
||||
|
|
|
@ -24,13 +24,13 @@
|
|||
<div class="input-group"
|
||||
ng-class="queryInput.$invalid ? 'has-error' : ''">
|
||||
<input
|
||||
ng-model="state.query"
|
||||
query-input="savedVis.searchSource"
|
||||
input-focus
|
||||
kbn-typeahead-input
|
||||
placeholder="Search..."
|
||||
type="text"
|
||||
class="form-control"
|
||||
ng-model="state.query">
|
||||
class="form-control">
|
||||
|
||||
<button
|
||||
class="btn btn-default" type="submit"
|
||||
|
|
|
@ -41,7 +41,7 @@ define(function (require) {
|
|||
'kibana/notify',
|
||||
'kibana/courier'
|
||||
])
|
||||
.controller('VisEditor', function ($scope, $route, timefilter, appStateFactory, $location, kbnUrl, $timeout) {
|
||||
.controller('VisEditor', function ($scope, $route, timefilter, appStateFactory, $location, kbnUrl, $timeout, courier) {
|
||||
|
||||
var _ = require('lodash');
|
||||
var angular = require('angular');
|
||||
|
@ -98,6 +98,7 @@ define(function (require) {
|
|||
delete $state.query;
|
||||
} else {
|
||||
$state.query = $state.query || searchSource.get('query');
|
||||
courier.setRootSearchSource(searchSource);
|
||||
searchSource.set('query', $state.query);
|
||||
}
|
||||
|
||||
|
@ -139,11 +140,13 @@ define(function (require) {
|
|||
}
|
||||
|
||||
$scope.fetch = function () {
|
||||
$state.save();
|
||||
if (!$scope.linked) searchSource.set('query', $state.query);
|
||||
searchSource.fetch();
|
||||
};
|
||||
|
||||
$scope.startOver = function () {
|
||||
$location.url('/visualize');
|
||||
kbnUrl.change('/visualize', {}, true);
|
||||
};
|
||||
|
||||
$scope.doSave = function () {
|
||||
|
|
|
@ -62,12 +62,6 @@
|
|||
> span {
|
||||
width: @vis-editor-nesting-width;
|
||||
background-color: @brand-success;
|
||||
|
||||
.transition(width .3s ease-out);
|
||||
|
||||
&.expand {
|
||||
width: @vis-editor-nesting-expand-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,29 +22,6 @@ define(function (require) {
|
|||
};
|
||||
}());
|
||||
|
||||
var allIndicators = [];
|
||||
allIndicators.expanded = false;
|
||||
allIndicators.expand = toggler(true);
|
||||
allIndicators.contract = toggler(false, 150);
|
||||
|
||||
function toggler(on, delay) {
|
||||
var all = allIndicators;
|
||||
var work = function () {
|
||||
if (delay && all.expanded !== on) return;
|
||||
all.forEach(function ($scope) {
|
||||
if (!$scope.bars) return;
|
||||
$scope.bars.forEach(function ($el) {
|
||||
$el.toggleClass('expand', on);
|
||||
});
|
||||
});
|
||||
};
|
||||
return function () {
|
||||
all.expanded = on;
|
||||
if (!delay) work();
|
||||
else setTimeout(work, delay);
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
|
@ -53,16 +30,6 @@ define(function (require) {
|
|||
},
|
||||
link: function ($scope, $el, attr) {
|
||||
|
||||
allIndicators.push($scope);
|
||||
$el.on('mouseenter', allIndicators.expand);
|
||||
$el.on('mouseleave', allIndicators.contract);
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
_.pull(allIndicators, $scope);
|
||||
$el.off('mouseenter', allIndicators.expand);
|
||||
$el.off('mouseleave', allIndicators.contract);
|
||||
});
|
||||
|
||||
$scope.$watchCollection('list', function () {
|
||||
if (!$scope.list || !$scope.item) return;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
ng-repeat="type in visTypes"
|
||||
ng-href="{{ visTypeUrl(type) }}">
|
||||
<li>
|
||||
<i ng-class="type.icon"></i>{{type.name}}
|
||||
<i ng-class="type.icon"></i>{{type.title}}
|
||||
</li>
|
||||
</a>
|
||||
</ul>
|
|
@ -75,7 +75,7 @@ define(function (require) {
|
|||
config.get = function (key, defaultVal) {
|
||||
if (vals[key] == null) {
|
||||
if (defaultVal == null) {
|
||||
return defaults[key];
|
||||
return defaults[key].value;
|
||||
} else {
|
||||
return _.cloneDeep(defaultVal);
|
||||
}
|
||||
|
|
|
@ -1,25 +1,54 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
return _.flattenWith('.', {
|
||||
dateFormat: 'MMMM Do YYYY, HH:mm:ss.SSS',
|
||||
defaultIndex: null,
|
||||
refreshInterval: 10000,
|
||||
metaFields: ['_source', '_id', '_type', '_index'],
|
||||
|
||||
'discover:sampleSize': 500,
|
||||
'fields:popularLimit': 10,
|
||||
|
||||
'truncate:maxHeight': 100,
|
||||
|
||||
'histogram:barTarget': 50,
|
||||
'histogram:maxBars': 100,
|
||||
|
||||
'csv:separator': ',',
|
||||
'csv:quoteValues': true,
|
||||
|
||||
'history:limit': 10,
|
||||
|
||||
'shortDots:enable': false
|
||||
});
|
||||
return {
|
||||
'dateFormat': {
|
||||
value: 'MMMM Do YYYY, HH:mm:ss.SSS',
|
||||
description: 'When displaying a pretty formatted date, use this format',
|
||||
},
|
||||
'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',
|
||||
},
|
||||
'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',
|
||||
},
|
||||
'csv:separator': {
|
||||
value: ',',
|
||||
description: 'Seperate 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 (eg 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: 100,
|
||||
description: 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.'
|
||||
}
|
||||
};
|
||||
});
|
|
@ -34,7 +34,15 @@ define(function (require) {
|
|||
*/
|
||||
function setAppSource(source) {
|
||||
appSource = source;
|
||||
appSource.inherits(globalSource);
|
||||
|
||||
// walk the parent chain until we get to the global source or nothing
|
||||
// that's where we will attach to the globalSource
|
||||
var literalRoot = source;
|
||||
while (literalRoot._parent && literalRoot._parent !== globalSource) {
|
||||
literalRoot = literalRoot._parent;
|
||||
}
|
||||
|
||||
literalRoot.inherits(globalSource);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<span>"{{ filter.value }}"</span>
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<a class="filter-toggle" ng-click="toggleFilter(filter)">toggle</a>
|
||||
<a class="filter-toggle" ng-click="toggleFilter(filter)"><span ng-show="filter.disabled">enable</span><span ng-hide="filter.disabled">disable</span></a>
|
||||
<a class="filter-remove" ng-click="removeFilter(filter)">remove</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@ define(function (require) {
|
|||
return function (chart, columns, rows) {
|
||||
// index of color
|
||||
var iColor = _.findIndex(columns, { categoryName: 'group' });
|
||||
var hasColor = iColor !== -1;
|
||||
var colColor = columns[iColor];
|
||||
|
||||
/*****
|
||||
* Get values related to the X-Axis
|
||||
|
@ -79,20 +79,22 @@ define(function (require) {
|
|||
|
||||
|
||||
// setup the formatter for the label
|
||||
chart.tooltipFormatter = function (datapoint) {
|
||||
var datum = _.clone(datapoint);
|
||||
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];
|
||||
|
||||
if (colX.field) datum.x = colX.field.format.convert(datum.x);
|
||||
if (colY.field) datum.y = colY.field.format.convert(datum.y);
|
||||
var name = (col.field && col.field.name) || col.label || axis;
|
||||
if (col.field) val = col.field.format.convert(val);
|
||||
|
||||
if (colX.metricScaleText) {
|
||||
datum.y += ' per ' + colX.metricScaleText;
|
||||
}
|
||||
return name + ': ' + val;
|
||||
}).join('<br>');
|
||||
|
||||
|
||||
var out = datum.label ? datum.label + '\n' : '';
|
||||
out += datum.x + '\n';
|
||||
out += datum.y;
|
||||
var out = '';
|
||||
if (datum.label) out += colColor.field.name + ': ' + datum.label + '<br>';
|
||||
out += vals;
|
||||
|
||||
return out;
|
||||
};
|
||||
|
@ -101,12 +103,12 @@ define(function (require) {
|
|||
var seriesByLabel = {};
|
||||
|
||||
rows.forEach(function (row) {
|
||||
var seriesLabel = hasColor && row[iColor];
|
||||
var s = hasColor ? seriesByLabel[seriesLabel] : series[0];
|
||||
var seriesLabel = colColor && row[iColor];
|
||||
var s = colColor ? seriesByLabel[seriesLabel] : series[0];
|
||||
|
||||
if (!s) {
|
||||
// I know this could be simplified but I wanted to keep the key order
|
||||
if (hasColor) {
|
||||
if (colColor) {
|
||||
s = {
|
||||
label: seriesLabel,
|
||||
values: []
|
||||
|
@ -125,6 +127,9 @@ define(function (require) {
|
|||
y: row[iY === -1 ? row.length - 1 : iY] // y-axis value
|
||||
};
|
||||
|
||||
// skip this datum
|
||||
if (datum.y == null) return;
|
||||
|
||||
if (colX.metricScale) {
|
||||
// support scaling response values to represent an average value on the y-axis
|
||||
datum.y = datum.y * colX.metricScale;
|
||||
|
|
145
src/kibana/components/vis_types/converters/pie.js
Normal file
145
src/kibana/components/vis_types/converters/pie.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
define(function (require) {
|
||||
return function HistogramConverterFn(Private, timefilter) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var interval = require('utils/interval');
|
||||
|
||||
return function (chart, columns, rows) {
|
||||
|
||||
// Checks for obj.parent.name and
|
||||
// Returns an array of parent names
|
||||
// if they exist.
|
||||
function checkForParentName(datum) {
|
||||
var parentNames = [];
|
||||
|
||||
parentNames.push(datum.name);
|
||||
|
||||
if (datum.parent.name) {
|
||||
_.forEach(checkForParentName(datum.parent), function (name) {
|
||||
return parentNames.push(name);
|
||||
});
|
||||
}
|
||||
|
||||
return parentNames;
|
||||
}
|
||||
|
||||
// tooltip formatter for pie charts
|
||||
chart.tooltipFormatter = function (datum) {
|
||||
function sumValue(sum, cur) {
|
||||
return sum + cur.value;
|
||||
}
|
||||
|
||||
// find the root datum
|
||||
var root = datum;
|
||||
while (root.parent) root = root.parent;
|
||||
|
||||
// the value of the root datum is the sum of every row. coincidental? not certain
|
||||
var sum = root.value;
|
||||
|
||||
var labels = [];
|
||||
for (var cur = datum; cur.parent; cur = cur.parent) {
|
||||
var label = cur.name + ': ' + cur.value;
|
||||
label += ' (' + Math.round((cur.value / sum) * 100) + '%)';
|
||||
|
||||
if (cur === datum) {
|
||||
label = '<b>' + label + '</b>';
|
||||
}
|
||||
|
||||
labels.unshift(label);
|
||||
}
|
||||
|
||||
return labels.join('<br>');
|
||||
};
|
||||
|
||||
|
||||
// TODO: refactor this code to simplify and possibly merge with data converter code below
|
||||
// Creates a collection of all the labels
|
||||
// and their index value
|
||||
var sliceLabels = {};
|
||||
|
||||
rows.forEach(function (row, i) {
|
||||
var startIndex = 0;
|
||||
var stopIndex = row.length - 1;
|
||||
row = row.slice(startIndex, stopIndex);
|
||||
|
||||
// if no label available, return _all
|
||||
if (row.length === 0) {
|
||||
return sliceLabels['_all'] = i;
|
||||
}
|
||||
|
||||
row.forEach(function (name, i) {
|
||||
if (!sliceLabels[name]) {
|
||||
return sliceLabels[name] = i;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// An array of all the labels sorted by their index number
|
||||
chart.names = _(sliceLabels)
|
||||
.pairs()
|
||||
.sortBy(function (d) {
|
||||
return d[1];
|
||||
})
|
||||
.pluck(function (d) {
|
||||
return d[0];
|
||||
})
|
||||
.value();
|
||||
|
||||
|
||||
// Pie Data Converter
|
||||
var slices = chart.slices = {};
|
||||
var children = slices.children = [];
|
||||
|
||||
// appends new object (slice) to children array
|
||||
function appendSlice(array, name) {
|
||||
return array.push({
|
||||
name: name,
|
||||
children: []
|
||||
});
|
||||
}
|
||||
|
||||
rows.forEach(function (row) {
|
||||
var rowLength = row.length;
|
||||
|
||||
// Name is always the second to last value in the array
|
||||
// Size is always the last value in the array
|
||||
var iName = rowLength - 2;
|
||||
var iSize = rowLength - 1;
|
||||
|
||||
// Wrap up the name and size values into an object
|
||||
var datum = {
|
||||
name: (row[iName] == null && rowLength >= 2) ? row[iName - 1] : rowLength < 2 ? '_all' : row[iName],
|
||||
size: row[iSize]
|
||||
};
|
||||
|
||||
// Create an array of the labels (names) that should append a slice
|
||||
// i.e. { names: '', children: [] }
|
||||
var startIndex = 0;
|
||||
var stopIndex = rowLength - 2;
|
||||
var names = (row[iName] == null) ? row.slice(startIndex, stopIndex - 1) : row.slice(startIndex, stopIndex);
|
||||
|
||||
// Keep track of the current children array
|
||||
var currentArray = children;
|
||||
|
||||
// For each name in the names array, append an empty slice if the
|
||||
// named object is not present, else return
|
||||
names.forEach(function (name) {
|
||||
// Find the index of the name in the current children array
|
||||
var currentNameIndex = _.findIndex(currentArray, { name: name });
|
||||
|
||||
// If not present, append an empty slice
|
||||
if (currentNameIndex === -1) {
|
||||
appendSlice(currentArray, name);
|
||||
}
|
||||
|
||||
// Update the current array
|
||||
currentNameIndex = _.findIndex(currentArray, { name: name });
|
||||
currentArray = currentArray[currentNameIndex].children;
|
||||
});
|
||||
|
||||
// Append datum
|
||||
currentArray.push(datum);
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
|
@ -5,12 +5,14 @@ define(function (require) {
|
|||
|
||||
return new VisType({
|
||||
name: 'histogram',
|
||||
title: 'Vertical bar chart',
|
||||
icon: 'icon-chart-bar',
|
||||
vislibParams: {
|
||||
shareYAxis: true,
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
addBrushing: false,
|
||||
addEvents: true,
|
||||
addBrushing: true
|
||||
},
|
||||
schemas: new Schemas([
|
||||
{
|
||||
|
|
|
@ -7,8 +7,8 @@ define(function (require) {
|
|||
index: ['name'],
|
||||
initialSet: [
|
||||
Private(require('components/vis_types/histogram')),
|
||||
// Private(require('components/vis_types/line')),
|
||||
// Private(require('components/vis_types/pie'))
|
||||
Private(require('components/vis_types/line')),
|
||||
Private(require('components/vis_types/pie'))
|
||||
]
|
||||
});
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ define(function (require) {
|
|||
|
||||
return new VisType({
|
||||
name: 'line',
|
||||
title: 'Line chart',
|
||||
icon: 'icon-chart-bar',
|
||||
vislibParams: {
|
||||
shareYAxis: true,
|
||||
|
@ -17,7 +18,10 @@ define(function (require) {
|
|||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
max: 1,
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
|
|
|
@ -2,35 +2,42 @@ define(function (require) {
|
|||
return function HistogramVisType(Private) {
|
||||
var VisType = Private(require('components/vis_types/_vis_type'));
|
||||
var Schemas = Private(require('components/vis_types/_schemas'));
|
||||
var PieConverter = Private(require('components/vis_types/converters/pie'));
|
||||
|
||||
return new VisType({
|
||||
name: 'pie',
|
||||
title: 'Pie chart',
|
||||
icon: 'icon-chart-bar',
|
||||
vislibParams: {
|
||||
addEvents: true,
|
||||
addTooltip: true,
|
||||
addLegend: true
|
||||
},
|
||||
responseConverter: PieConverter,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Slice Size',
|
||||
min: 1,
|
||||
max: 1
|
||||
max: 1,
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
icon: 'fa fa-scissors',
|
||||
title: 'Slices',
|
||||
title: 'Create/Split Slices',
|
||||
min: 0,
|
||||
max: 1
|
||||
max: Infinity
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
icon: 'fa fa-th',
|
||||
title: 'Rows & Columns',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1
|
||||
}
|
||||
|
|
|
@ -9,11 +9,18 @@ define(function (require) {
|
|||
|
||||
// Returns an array x axis values
|
||||
return _.chain(objKeys)
|
||||
.pairs()
|
||||
.map(function (d) {
|
||||
return d[1].isNumber ? +d[0] : d[0];
|
||||
})
|
||||
.value();
|
||||
.pairs()
|
||||
.sortBy(function (d) {
|
||||
// sort by number
|
||||
if (d[1].isNumber) {
|
||||
return +d[0];
|
||||
}
|
||||
return;
|
||||
})
|
||||
.map(function (d) {
|
||||
return d[1].isNumber ? +d[0] : d[0];
|
||||
})
|
||||
.value();
|
||||
};
|
||||
};
|
||||
});
|
|
@ -13,10 +13,10 @@ define(function (require) {
|
|||
flattenedData.forEach(function (d, i) {
|
||||
var key = d.x;
|
||||
uniqueXValues[key] = uniqueXValues[key] === void 0 ?
|
||||
{ index: i, isNumber: _.isNumber(key) } : { index: Math.max(i, uniqueXValues[key]), isNumber: _.isNumber(key) };
|
||||
{ index: i, isNumber: _.isNumber(key) } : { index: Math.max(i, uniqueXValues[key].index), isNumber: _.isNumber(key) };
|
||||
});
|
||||
|
||||
// returns an object with unique x values in the correct order
|
||||
// returns an object with unique x values
|
||||
return uniqueXValues;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
define(function (require) {
|
||||
return function LayoutTypeFactory(Private) {
|
||||
// visLib layout types
|
||||
return {
|
||||
histogram: Private(require('components/vislib/components/layouts/types/column_layout'))
|
||||
};
|
||||
};
|
||||
});
|
|
@ -38,9 +38,50 @@ define(function (require) {
|
|||
return [this.data];
|
||||
};
|
||||
|
||||
// Function to determine whether to display the legend or not
|
||||
// Displays legend when more than one series of data present
|
||||
Data.prototype.isLegendShown = function () {
|
||||
var isLegend = false;
|
||||
var visData;
|
||||
|
||||
if (this.data.rows) {
|
||||
visData = this.data.rows;
|
||||
} else if (this.data.columns) {
|
||||
visData = this.data.columns;
|
||||
} else {
|
||||
visData = [this.data];
|
||||
}
|
||||
|
||||
_.forEach(visData, function countSeriesLength(obj) {
|
||||
var dataLength = obj.series ? obj.series.length : obj.slices.children.length;
|
||||
|
||||
if (dataLength > 1) {
|
||||
isLegend = true;
|
||||
}
|
||||
});
|
||||
|
||||
return isLegend;
|
||||
};
|
||||
|
||||
Data.prototype.pieData = function () {
|
||||
if (!this.data.slices) {
|
||||
return this.data.rows ? this.data.rows : this.data.columns;
|
||||
}
|
||||
return [this.data];
|
||||
};
|
||||
|
||||
// Get attributes off the data, e.g. `tooltipFormatter` or `xAxisFormatter`
|
||||
Data.prototype.get = function (thing) {
|
||||
var data = this.chartData();
|
||||
var data;
|
||||
|
||||
if (this.data.rows) {
|
||||
data = this.data.rows;
|
||||
} else if (this.data.columns) {
|
||||
data = this.data.columns;
|
||||
} else {
|
||||
data = [this.data];
|
||||
}
|
||||
|
||||
// pulls the value off the first item in the array
|
||||
// these values are typically the same between data objects of the same chart
|
||||
// May need to verify this or refactor
|
||||
|
@ -62,9 +103,10 @@ define(function (require) {
|
|||
return values;
|
||||
};
|
||||
|
||||
// TODO: need to make this more generic
|
||||
Data.prototype.shouldBeStacked = function (series) {
|
||||
// Series should be an array
|
||||
if (series.length > 1) {
|
||||
if (this._attr.type === 'histogram' && series.length > 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -78,7 +120,10 @@ define(function (require) {
|
|||
// for each object in the dataArray,
|
||||
// push the calculated y value to the initialized array (arr)
|
||||
_.forEach(this.flatten(), function (series) {
|
||||
arr.push(self.getYStackMax(series));
|
||||
if (self.shouldBeStacked(series)) {
|
||||
return arr.push(self.getYStackMax(series));
|
||||
}
|
||||
return arr.push(self.getYMax(series));
|
||||
});
|
||||
|
||||
// return the largest value from the array
|
||||
|
@ -86,22 +131,20 @@ define(function (require) {
|
|||
};
|
||||
|
||||
Data.prototype.stackData = function (series) {
|
||||
// Determine if the data should be stacked
|
||||
if (this.shouldBeStacked(series)) {
|
||||
// if true, stack data
|
||||
return this._attr.stack(series);
|
||||
}
|
||||
return series;
|
||||
return this._attr.stack(series);
|
||||
};
|
||||
|
||||
Data.prototype.getYStackMax = function (series) {
|
||||
// Return the calculated y value
|
||||
return d3.max(this.stackData(series), function (data) {
|
||||
return d3.max(data, function (d) {
|
||||
// if stacked, need to add d.y0 + d.y for the y value
|
||||
if (d.y0) {
|
||||
return d.y0 + d.y;
|
||||
}
|
||||
return d.y0 + d.y;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Data.prototype.getYMax = function (series) {
|
||||
return d3.max(series, function (data) {
|
||||
return d3.max(data, function (d) {
|
||||
return d.y;
|
||||
});
|
||||
});
|
||||
|
@ -124,7 +167,12 @@ define(function (require) {
|
|||
|
||||
// Return a function that does color lookup on labels
|
||||
Data.prototype.getColorFunc = function () {
|
||||
return color(this.getLabels(this.data));
|
||||
return color(this.getLabels());
|
||||
};
|
||||
|
||||
// Return a function that does color lookup on names for pie charts
|
||||
Data.prototype.getPieColorFunc = function () {
|
||||
return color(this.get('names'));
|
||||
};
|
||||
|
||||
return Data;
|
||||
|
|
82
src/kibana/components/vislib/lib/dispatch.js
Normal file
82
src/kibana/components/vislib/lib/dispatch.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
define(function (require) {
|
||||
return function DispatchClass(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
|
||||
/**
|
||||
* Events Class
|
||||
*/
|
||||
function Dispatch(vis, chartData) {
|
||||
if (!(this instanceof Dispatch)) {
|
||||
return new Dispatch(vis, chartData);
|
||||
}
|
||||
var type = vis._attr.type;
|
||||
|
||||
this.vis = vis;
|
||||
this.chartData = chartData;
|
||||
this.color = type === 'pie' ? vis.data.getPieColorFunc() : vis.data.getColorFunc();
|
||||
this._attr = _.defaults(vis._attr || {}, {
|
||||
yValue: function (d) {
|
||||
return d.y;
|
||||
},
|
||||
dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout')
|
||||
});
|
||||
}
|
||||
|
||||
// Response to `click` and `hover` events
|
||||
Dispatch.prototype.eventResponse = function (d, i) {
|
||||
var label = d.label ? d.label : d.name;
|
||||
var getYValue = this._attr.yValue;
|
||||
var color = this.color;
|
||||
var chartData = this.chartData;
|
||||
var attr = this._attr;
|
||||
var vis = this.vis;
|
||||
|
||||
return {
|
||||
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
|
||||
};
|
||||
};
|
||||
|
||||
// Add brush to the svg
|
||||
Dispatch.prototype.addBrush = function (xScale, svg) {
|
||||
var dispatch = this._attr.dispatch;
|
||||
var attr = this._attr;
|
||||
var chartData = this.chartData;
|
||||
var isBrush = this._attr.addBrushing;
|
||||
var height = this._attr.height;
|
||||
var margin = this._attr.margin;
|
||||
|
||||
// Brush scale
|
||||
var brush = d3.svg.brush()
|
||||
.x(xScale)
|
||||
.on('brushend', function brushEnd() {
|
||||
// response returned on brush
|
||||
return dispatch.brush({
|
||||
range: brush.extent(),
|
||||
config: attr,
|
||||
e: d3.event,
|
||||
data: chartData
|
||||
});
|
||||
});
|
||||
|
||||
// if `addBrushing` is true, add brush canvas
|
||||
if (isBrush) {
|
||||
return svg.append('g')
|
||||
.attr('class', 'brush')
|
||||
.call(brush)
|
||||
.selectAll('rect')
|
||||
.attr('height', height - margin.top - margin.bottom);
|
||||
}
|
||||
};
|
||||
|
||||
return Dispatch;
|
||||
};
|
||||
});
|
|
@ -1,15 +1,10 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
return function HandlerBaseClass(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var Data = Private(require('components/vislib/lib/data'));
|
||||
var Layout = Private(require('components/vislib/lib/layout'));
|
||||
var Legend = Private(require('components/vislib/lib/legend'));
|
||||
var Layout = Private(require('components/vislib/lib/layout/layout'));
|
||||
var Tooltip = Private(require('components/vislib/lib/tooltip'));
|
||||
var XAxis = Private(require('components/vislib/lib/x_axis'));
|
||||
var YAxis = Private(require('components/vislib/lib/y_axis'));
|
||||
var AxisTitle = Private(require('components/vislib/lib/axis_title'));
|
||||
var ChartTitle = Private(require('components/vislib/lib/chart_title'));
|
||||
|
||||
/*
|
||||
* Handles building all the components of the visualization
|
||||
|
@ -19,12 +14,12 @@ define(function (require) {
|
|||
* returns an object with reference to the vis.prototype,
|
||||
* and news up all the constructors needed to build a visualization
|
||||
*/
|
||||
function Handler(vis) {
|
||||
function Handler(vis, opts) {
|
||||
if (!(this instanceof Handler)) {
|
||||
return new Handler(vis);
|
||||
return new Handler(vis, opts);
|
||||
}
|
||||
|
||||
this.data = new Data(vis.data, vis._attr);
|
||||
this.data = opts.data || new Data(vis.data, vis._attr);
|
||||
this.vis = vis;
|
||||
this.el = vis.el;
|
||||
this.ChartClass = vis.ChartClass;
|
||||
|
@ -33,50 +28,29 @@ define(function (require) {
|
|||
});
|
||||
|
||||
// Visualization constructors
|
||||
// Add the visualization layout
|
||||
this.layout = new Layout(this.el, this.data.injectZeros(), this._attr.type);
|
||||
this.layout = new Layout(vis.el, vis.data, vis._attr.type);
|
||||
this.xAxis = opts.xAxis;
|
||||
this.yAxis = opts.yAxis;
|
||||
this.chartTitle = opts.chartTitle;
|
||||
this.axisTitle = opts.axisTitle;
|
||||
|
||||
// Only add legend if addLegend attribute set
|
||||
if (this._attr.addLegend) {
|
||||
this.legend = new Legend(this.vis, this.el, this.data.getLabels(), this.data.getColorFunc(), this._attr);
|
||||
}
|
||||
|
||||
// only add tooltip if addTooltip attribute set
|
||||
if (this._attr.addTooltip) {
|
||||
this.tooltip = new Tooltip(this.el, this.data.get('tooltipFormatter'));
|
||||
}
|
||||
|
||||
// add a x axis
|
||||
this.xAxis = new XAxis({
|
||||
el: this.el,
|
||||
xValues: this.data.xValues(),
|
||||
ordered: this.data.get('ordered'),
|
||||
xAxisFormatter: this.data.get('xAxisFormatter'),
|
||||
_attr: this._attr
|
||||
});
|
||||
|
||||
// add a y axis
|
||||
this.yAxis = new YAxis({
|
||||
el: this.el,
|
||||
yMax: this.data.getYMaxValue(),
|
||||
_attr: this._attr
|
||||
});
|
||||
|
||||
// add axis titles
|
||||
this.axisTitle = new AxisTitle(this.el, this.data.get('xAxisLabel'), this.data.get('yAxisLabel'));
|
||||
|
||||
// add chart titles
|
||||
this.chartTitle = new ChartTitle(this.el);
|
||||
if (this._attr.addLegend && this.data.isLegendShown()) {
|
||||
this.legend = opts.legend;
|
||||
}
|
||||
|
||||
// Array of objects to render to the visualization
|
||||
this.renderArray = _.filter([
|
||||
this.layout,
|
||||
this.legend,
|
||||
this.tooltip,
|
||||
this.axisTitle,
|
||||
this.chartTitle,
|
||||
this.xAxis,
|
||||
this.yAxis,
|
||||
this.xAxis
|
||||
this.chartTitle,
|
||||
this.axisTitle,
|
||||
this.legend,
|
||||
this.tooltip
|
||||
], Boolean);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
define(function (require) {
|
||||
return function HandlerTypeFactory(Private) {
|
||||
// handler types
|
||||
return {
|
||||
histogram: Private(require('components/vislib/lib/handler/types/column')),
|
||||
pie: Private(require('components/vislib/lib/handler/types/pie'))
|
||||
};
|
||||
};
|
||||
});
|
40
src/kibana/components/vislib/lib/handler/types/column.js
Normal file
40
src/kibana/components/vislib/lib/handler/types/column.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
define(function (require) {
|
||||
return function ColumnHandler(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var injectZeros = Private(require('components/vislib/components/zero_injection/inject_zeros'));
|
||||
var Handler = Private(require('components/vislib/lib/handler/handler'));
|
||||
var Data = Private(require('components/vislib/lib/data'));
|
||||
var Legend = Private(require('components/vislib/lib/legend'));
|
||||
var XAxis = Private(require('components/vislib/lib/x_axis'));
|
||||
var YAxis = Private(require('components/vislib/lib/y_axis'));
|
||||
var AxisTitle = Private(require('components/vislib/lib/axis_title'));
|
||||
var ChartTitle = Private(require('components/vislib/lib/chart_title'));
|
||||
|
||||
return function (vis) {
|
||||
var data = new Data(injectZeros(vis.data), vis._attr);
|
||||
|
||||
var ColumnHandler = new Handler(vis, {
|
||||
data: data,
|
||||
legend: new Legend(vis, vis.el, data.getLabels(), data.getColorFunc(), vis._attr),
|
||||
axisTitle: new AxisTitle(vis.el, data.get('xAxisLabel'), data.get('yAxisLabel')),
|
||||
chartTitle: new ChartTitle(vis.el),
|
||||
xAxis: new XAxis({
|
||||
el : vis.el,
|
||||
xValues : data.xValues(),
|
||||
ordered : data.get('ordered'),
|
||||
xAxisFormatter: data.get('xAxisFormatter'),
|
||||
_attr : vis._attr
|
||||
}),
|
||||
yAxis: new YAxis({
|
||||
el : vis.el,
|
||||
yMax : data.getYMaxValue(),
|
||||
_attr: vis._attr
|
||||
})
|
||||
});
|
||||
|
||||
return ColumnHandler;
|
||||
};
|
||||
};
|
||||
});
|
||||
|
20
src/kibana/components/vislib/lib/handler/types/pie.js
Normal file
20
src/kibana/components/vislib/lib/handler/types/pie.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
define(function (require) {
|
||||
return function PieHandler(d3, Private) {
|
||||
|
||||
var Handler = Private(require('components/vislib/lib/handler/handler'));
|
||||
var Data = Private(require('components/vislib/lib/data'));
|
||||
var Legend = Private(require('components/vislib/lib/legend'));
|
||||
var ChartTitle = Private(require('components/vislib/lib/chart_title'));
|
||||
|
||||
return function (vis) {
|
||||
var data = new Data(vis.data, vis._attr);
|
||||
|
||||
var PieHandler = new Handler(vis, {
|
||||
legend: new Legend(vis, vis.el, data.get('names'), data.getPieColorFunc(), vis._attr),
|
||||
chartTitle: new ChartTitle(vis.el)
|
||||
});
|
||||
|
||||
return PieHandler;
|
||||
};
|
||||
};
|
||||
});
|
|
@ -2,7 +2,7 @@ define(function (require) {
|
|||
return function LayoutFactory(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var layoutType = Private(require('components/vislib/layout_types'));
|
||||
var layoutType = Private(require('components/vislib/lib/layout/layout_types'));
|
||||
|
||||
/*
|
||||
* The Layout Constructor is responsible for rendering the visualization
|
9
src/kibana/components/vislib/lib/layout/layout_types.js
Normal file
9
src/kibana/components/vislib/lib/layout/layout_types.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
define(function (require) {
|
||||
return function LayoutTypeFactory(Private) {
|
||||
// visLib layout types
|
||||
return {
|
||||
histogram: Private(require('components/vislib/lib/layout/types/column_layout')),
|
||||
pie: Private(require('components/vislib/lib/layout/types/pie_layout'))
|
||||
};
|
||||
};
|
||||
});
|
|
@ -0,0 +1,50 @@
|
|||
define(function () {
|
||||
return function ChartSplitFactory(d3) {
|
||||
/*
|
||||
* Adds div DOM elements to the `.chart-wrapper` element based on the data layout.
|
||||
* For example, if the data has rows, it returns the same number of
|
||||
* `.chart` elements as row objects.
|
||||
*/
|
||||
return function split(selection) {
|
||||
selection.each(function (data) {
|
||||
var div = d3.select(this)
|
||||
.attr('class', function () {
|
||||
// Determine the parent class
|
||||
if (data.rows) {
|
||||
return 'chart-wrapper-row';
|
||||
} else if (data.columns) {
|
||||
return 'chart-wrapper-column';
|
||||
} else {
|
||||
return 'chart-wrapper';
|
||||
}
|
||||
});
|
||||
var divClass;
|
||||
|
||||
var charts = div.selectAll('charts')
|
||||
.append('div')
|
||||
.data(function (d) {
|
||||
// Determine the child class
|
||||
if (d.rows) {
|
||||
divClass = 'chart-row';
|
||||
return d.rows;
|
||||
} else if (d.columns) {
|
||||
divClass = 'chart-column';
|
||||
return d.columns;
|
||||
} else {
|
||||
divClass = 'chart';
|
||||
return [d];
|
||||
}
|
||||
})
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', function () {
|
||||
return divClass;
|
||||
});
|
||||
|
||||
if (!data.slices) {
|
||||
charts.call(split);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
define(function () {
|
||||
return function ChartTitleSplitFactory(d3) {
|
||||
/*
|
||||
* Adds div DOM elements to either the `.y-axis-chart-title` element or the
|
||||
* `.x-axis-chart-title` element based on the data layout.
|
||||
* For example, if the data has rows, it returns the same number of
|
||||
* `.chart-title` elements as row objects.
|
||||
*/
|
||||
return function (selection) {
|
||||
selection.each(function (data) {
|
||||
var div = d3.select(this);
|
||||
|
||||
if (!data.slices) {
|
||||
div.selectAll('.chart-title')
|
||||
.append('div')
|
||||
.data(function (d) {
|
||||
return d.rows ? d.rows : d.columns;
|
||||
})
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'chart-title');
|
||||
|
||||
if (data.rows) {
|
||||
// if rows remove the x axis chart title element
|
||||
d3.select('.x-axis-chart-title').remove();
|
||||
} else {
|
||||
// if columns, remove the y axis chart title element
|
||||
d3.select('.y-axis-chart-title').remove();
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
// if not data.rows or data.columns, return no chart titles
|
||||
return d3.select(this).remove();
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,10 +1,10 @@
|
|||
define(function (require) {
|
||||
return function ColumnLayoutFactory(d3, Private) {
|
||||
|
||||
var chartSplit = Private(require('components/vislib/components/layouts/splits/column_chart/chart_split'));
|
||||
var yAxisSplit = Private(require('components/vislib/components/layouts/splits/column_chart/y_axis_split'));
|
||||
var xAxisSplit = Private(require('components/vislib/components/layouts/splits/column_chart/x_axis_split'));
|
||||
var chartTitleSplit = Private(require('components/vislib/components/layouts/splits/column_chart/chart_title_split'));
|
||||
var chartSplit = Private(require('components/vislib/lib/layout/splits/column_chart/chart_split'));
|
||||
var yAxisSplit = Private(require('components/vislib/lib/layout/splits/column_chart/y_axis_split'));
|
||||
var xAxisSplit = Private(require('components/vislib/lib/layout/splits/column_chart/x_axis_split'));
|
||||
var chartTitleSplit = Private(require('components/vislib/lib/layout/splits/column_chart/chart_title_split'));
|
||||
|
||||
/*
|
||||
* Specifies the visualization layout for column charts.
|
66
src/kibana/components/vislib/lib/layout/types/pie_layout.js
Normal file
66
src/kibana/components/vislib/lib/layout/types/pie_layout.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
define(function (require) {
|
||||
return function ColumnLayoutFactory(d3, Private) {
|
||||
|
||||
var chartSplit = Private(require('components/vislib/lib/layout/splits/pie_chart/chart_split'));
|
||||
var chartTitleSplit = Private(require('components/vislib/lib/layout/splits/pie_chart/chart_title_split'));
|
||||
|
||||
/*
|
||||
* Specifies the visualization layout for column charts.
|
||||
*
|
||||
* This is done using an array of objects. The first object has
|
||||
* a `parent` DOM element, a DOM `type` (e.g. div, svg, etc),
|
||||
* and a `class` (required). Each child can omit the parent object,
|
||||
* but must include a type and class.
|
||||
*
|
||||
* Optionally, you can specify `datum` to be bound to the DOM
|
||||
* element, a `splits` function that divides the selected element
|
||||
* into more DOM elements based on a callback function provided, or
|
||||
* a children array which nests other layout objects.
|
||||
*
|
||||
* Objects in children arrays are children of the current object and return
|
||||
* DOM elements which are children of their respective parent element.
|
||||
*/
|
||||
|
||||
return function (el, data) {
|
||||
if (!el || !data) {
|
||||
throw new Error('Both an el and data need to be specified');
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
parent: el,
|
||||
type: 'div',
|
||||
class: 'vis-wrapper',
|
||||
datum: data,
|
||||
children: [
|
||||
{
|
||||
type: 'div',
|
||||
class: 'y-axis-chart-title',
|
||||
splits: chartTitleSplit
|
||||
},
|
||||
{
|
||||
type: 'div',
|
||||
class: 'vis-col-wrapper',
|
||||
children: [
|
||||
{
|
||||
type: 'div',
|
||||
class: 'chart-wrapper',
|
||||
splits: chartSplit
|
||||
},
|
||||
{
|
||||
type: 'div',
|
||||
class: 'x-axis-chart-title',
|
||||
splits: chartTitleSplit
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'div',
|
||||
class: 'legend-col-wrapper'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
});
|
|
@ -3,8 +3,10 @@ define(function (require) {
|
|||
var _ = require('lodash');
|
||||
var legendHeaderTemplate = _.template(require('text!components/vislib/partials/legend_header.html'));
|
||||
|
||||
var Tooltip = Private(require('components/vislib/lib/tooltip'));
|
||||
|
||||
// Dynamically adds css file
|
||||
require('css!components/vislib/components/styles/main');
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
/*
|
||||
* Append legend to the visualization
|
||||
|
@ -23,18 +25,18 @@ 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',
|
||||
'blurredOpacity' : 0.3,
|
||||
'focusOpacity' : 1,
|
||||
'defaultOpacity' : 1,
|
||||
'isOpen' : false
|
||||
'isOpen' : true
|
||||
});
|
||||
}
|
||||
|
||||
// Add legend header
|
||||
// Need to change the header icon
|
||||
Legend.prototype.header = function (el, args) {
|
||||
return el.append('div')
|
||||
.attr('class', 'header')
|
||||
|
@ -87,7 +89,8 @@ define(function (require) {
|
|||
var self = this;
|
||||
|
||||
// toggle
|
||||
headerIcon.on('click', function () {
|
||||
headerIcon
|
||||
.on('click', function legendClick() {
|
||||
if (self._attr.isOpen) {
|
||||
// close legend
|
||||
visEl.select('ul.legend-ul')
|
||||
|
@ -106,6 +109,10 @@ define(function (require) {
|
|||
}
|
||||
});
|
||||
|
||||
headerIcon
|
||||
.datum(['Legend'])
|
||||
.call(self.tooltip.render());
|
||||
|
||||
visEl.selectAll('.color')
|
||||
.on('mouseover', function (d) {
|
||||
var liClass = '.' + self.colorToClass(self.color(d));
|
||||
|
|
|
@ -4,7 +4,7 @@ define(function (require) {
|
|||
var $ = require('jquery');
|
||||
|
||||
// Dynamically adds css file
|
||||
require('css!components/vislib/components/styles/main');
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
/*
|
||||
* Append a tooltip div element to the visualization
|
||||
|
@ -24,7 +24,7 @@ define(function (require) {
|
|||
|
||||
Tooltip.prototype.render = function () {
|
||||
var self = this;
|
||||
|
||||
|
||||
return function (selection) {
|
||||
|
||||
// if tooltip not appended to body, append one
|
||||
|
@ -40,18 +40,12 @@ define(function (require) {
|
|||
var tooltipDiv = d3.select('.' + self.tooltipClass);
|
||||
|
||||
selection.each(function () {
|
||||
|
||||
|
||||
// DOM element on which the tooltip is called
|
||||
var element = d3.select(this);
|
||||
|
||||
|
||||
// define selections relative to el of tooltip
|
||||
var chartXoffset;
|
||||
var chartWidth;
|
||||
var chartHeight;
|
||||
var yaxisWidth;
|
||||
var offset;
|
||||
var tipWidth;
|
||||
var tipHeight;
|
||||
|
||||
element
|
||||
.on('mousemove.tip', function (d) {
|
||||
|
@ -60,20 +54,20 @@ define(function (require) {
|
|||
left: d3.event.clientX,
|
||||
top: d3.event.clientY
|
||||
};
|
||||
|
||||
|
||||
offset = self.getOffsets(tooltipDiv, mouseMove);
|
||||
|
||||
// return text and position for tooltip
|
||||
return tooltipDiv.datum(d)
|
||||
.text(self.tooltipFormatter)
|
||||
.style('visibility', 'visible')
|
||||
.html(self.tooltipFormatter)
|
||||
.style('display', 'block')
|
||||
.style('left', mouseMove.left + offset.left + 'px')
|
||||
.style('top', mouseMove.top - offset.top + 'px');
|
||||
.style('top', mouseMove.top + offset.top + 'px');
|
||||
})
|
||||
|
||||
.on('mouseout.tip', function () {
|
||||
// hide tooltip
|
||||
return tooltipDiv.style('visibility', 'hidden');
|
||||
return tooltipDiv.style('display', 'none');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -83,37 +77,30 @@ define(function (require) {
|
|||
|
||||
var self = this;
|
||||
var offset = {top: 10, left: 10};
|
||||
var container;
|
||||
var chartXoffset;
|
||||
var chartYoffset;
|
||||
var chartWidth;
|
||||
var chartHeight;
|
||||
var tipWidth;
|
||||
var tipHeight;
|
||||
|
||||
|
||||
if ($(self.el).find('.' + self.containerClass)) {
|
||||
container = $(self.el).find('.' + self.containerClass);
|
||||
chartXoffset = container.offset().left;
|
||||
chartYoffset = container.offset().top;
|
||||
chartWidth = container.width();
|
||||
chartHeight = container.height();
|
||||
tipWidth = tooltipDiv[0][0].clientWidth;
|
||||
tipHeight = tooltipDiv[0][0].clientHeight;
|
||||
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 tipWidth = tooltipDiv[0][0].clientWidth;
|
||||
var tipHeight = tooltipDiv[0][0].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
|
||||
if ((mouseMove.left + offset.left + tipWidth) > (chartXoffset + chartWidth) &&
|
||||
(mouseMove.left - tipWidth - 10) > chartXoffset) {
|
||||
if ((mouseMove.left + offset.left + tipWidth) > (chartXOffset + chartWidth) &&
|
||||
(mouseMove.left - tipWidth - 10) > chartXOffset) {
|
||||
offset.left = -10 - tipWidth;
|
||||
}
|
||||
|
||||
// change yOffset to keep tooltip within container
|
||||
if ((mouseMove.top + tipHeight - 10) > (chartYoffset + chartHeight)) {
|
||||
offset.top = chartYoffset + chartHeight;
|
||||
if ((mouseMove.top + tipHeight - 10) > (chartYOffset + chartHeight)) {
|
||||
offset.top = chartYOffset + chartHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ define(function (require) {
|
|||
|
||||
// Return the d3 y axis
|
||||
YAxis.prototype.getYAxis = function (height) {
|
||||
var self = this;
|
||||
var yScale = this.getYScale(height);
|
||||
|
||||
// y scale should never be `NaN`
|
||||
|
@ -52,7 +51,7 @@ define(function (require) {
|
|||
.ticks(this.tickScale(height))
|
||||
.orient('left');
|
||||
|
||||
if (self.yScale.domain()[1] <= 10) {
|
||||
if (this.yScale.domain()[1] <= 10) {
|
||||
this.yAxis.tickFormat(d3.format('n'));
|
||||
}
|
||||
|
||||
|
@ -84,9 +83,11 @@ define(function (require) {
|
|||
return function (selection) {
|
||||
|
||||
selection.each(function () {
|
||||
div = d3.select(this);
|
||||
width = $(this).width();
|
||||
height = $(this).height() - margin.top - margin.bottom;
|
||||
var el = this;
|
||||
|
||||
div = d3.select(el);
|
||||
width = $(el).width();
|
||||
height = $(el).height() - margin.top - margin.bottom;
|
||||
|
||||
// Validate whether width and height are not 0 or `NaN`
|
||||
self.validateWidthandHeight(width, height);
|
||||
|
|
|
@ -197,7 +197,7 @@ p.rows-label, p.columns-label {
|
|||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
path, line, .axis line, .axis path {
|
||||
.axis line, .axis path {
|
||||
stroke: #ddd;
|
||||
fill: none;
|
||||
shape-rendering: crispEdges;
|
||||
|
@ -218,6 +218,7 @@ path, line, .axis line, .axis path {
|
|||
}
|
||||
|
||||
.k4tip, .vis-tooltip {
|
||||
display: none;
|
||||
line-height: 1.1;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
|
@ -227,9 +228,8 @@ path, line, .axis line, .axis path {
|
|||
border-radius: 4px;
|
||||
position: fixed;
|
||||
z-index: 120;
|
||||
visibility: hidden;
|
||||
word-wrap: break-word;
|
||||
max-width: 140px;
|
||||
max-width: 40%;
|
||||
}
|
||||
|
||||
.rect {
|
|
@ -3,12 +3,12 @@ define(function (require) {
|
|||
var $ = require('jquery');
|
||||
var _ = require('lodash');
|
||||
|
||||
var Handler = Private(require('components/vislib/lib/handler'));
|
||||
var ResizeChecker = Private(require('components/vislib/lib/resize_checker'));
|
||||
var Events = Private(require('factories/events'));
|
||||
var chartTypes = Private(require('components/vislib/vis_types'));
|
||||
var handlerTypes = Private(require('components/vislib/lib/handler/handler_types'));
|
||||
var chartTypes = Private(require('components/vislib/visualizations/vis_types'));
|
||||
var errors = require('errors');
|
||||
require('css!components/vislib/components/styles/main.css');
|
||||
require('css!components/vislib/styles/main.css');
|
||||
|
||||
/*
|
||||
* Visualization controller. Exposed API for creating visualizations.
|
||||
|
@ -37,13 +37,15 @@ define(function (require) {
|
|||
|
||||
// Exposed API for rendering charts.
|
||||
Vis.prototype.render = function (data) {
|
||||
var chartType = this._attr.type;
|
||||
|
||||
if (!data) {
|
||||
throw new Error('No valid data!');
|
||||
}
|
||||
|
||||
// Save data to this object and new up the Handler constructor
|
||||
this.data = data;
|
||||
this.handler = new Handler(this);
|
||||
this.handler = handlerTypes[chartType](this) || handlerTypes.column(this);
|
||||
|
||||
try {
|
||||
this.handler.render();
|
||||
|
|
|
@ -2,6 +2,9 @@ define(function (require) {
|
|||
return function ChartBaseClass(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var Legend = Private(require('components/vislib/lib/legend'));
|
||||
var Dispatch = Private(require('components/vislib/lib/dispatch'));
|
||||
|
||||
/*
|
||||
* Base Class for all visualizations.
|
||||
* Exposes a render method.
|
||||
|
@ -14,6 +17,7 @@ define(function (require) {
|
|||
this.vis = vis;
|
||||
this.chartEl = el;
|
||||
this.chartData = chartData;
|
||||
this.events = new Dispatch(vis, chartData);
|
||||
this._attr = _.defaults(vis._attr || {}, {});
|
||||
}
|
||||
|
||||
|
@ -22,6 +26,10 @@ define(function (require) {
|
|||
return d3.select(this.chartEl).call(this.draw());
|
||||
};
|
||||
|
||||
Chart.prototype.colorToClass = function (label) {
|
||||
return 'color ' + Legend.prototype.colorToClass.call(null, label);
|
||||
};
|
||||
|
||||
return Chart;
|
||||
};
|
||||
});
|
|
@ -4,11 +4,10 @@ define(function (require) {
|
|||
var $ = require('jquery');
|
||||
|
||||
var Chart = Private(require('components/vislib/visualizations/_chart'));
|
||||
var Legend = Private(require('components/vislib/lib/legend'));
|
||||
var errors = require('errors');
|
||||
|
||||
// Dynamically adds css file
|
||||
require('css!components/vislib/components/styles/main');
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
/*
|
||||
* Column chart visualization => vertical bars, stacked bars
|
||||
|
@ -23,26 +22,10 @@ define(function (require) {
|
|||
// Column chart specific attributes
|
||||
this._attr = _.defaults(vis._attr || {}, {
|
||||
xValue: function (d, i) { return d.x; },
|
||||
yValue: function (d, i) { return d.y; },
|
||||
dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout'),
|
||||
yValue: function (d, i) { return d.y; }
|
||||
});
|
||||
}
|
||||
|
||||
// Response to `click` and `hover` events
|
||||
ColumnChart.prototype.eventResponse = function (d, i) {
|
||||
return {
|
||||
value: this._attr.yValue(d, i),
|
||||
point: d,
|
||||
label: d.label,
|
||||
color: this.vis.data.getColorFunc()(d.label),
|
||||
pointIndex: i,
|
||||
series : this.chartData.series,
|
||||
config : this._attr,
|
||||
data : this.chartData,
|
||||
e : d3.event
|
||||
};
|
||||
};
|
||||
|
||||
// Stack data
|
||||
// TODO: refactor so that this is called from the data module
|
||||
ColumnChart.prototype.stackData = function (data) {
|
||||
|
@ -60,38 +43,14 @@ define(function (require) {
|
|||
}));
|
||||
};
|
||||
|
||||
// Add brush to the svg
|
||||
ColumnChart.prototype.addBrush = function (xScale, svg) {
|
||||
var self = this;
|
||||
|
||||
// Brush scale
|
||||
var brush = d3.svg.brush()
|
||||
.x(xScale)
|
||||
.on('brushend', function brushEnd() {
|
||||
// response returned on brush
|
||||
return self._attr.dispatch.brush({
|
||||
range: brush.extent(),
|
||||
config: self._attr,
|
||||
e: d3.event,
|
||||
data: self.chartData
|
||||
});
|
||||
});
|
||||
|
||||
// if `addBrushing` is true, add brush canvas
|
||||
if (self._attr.addBrushing) {
|
||||
svg.append('g')
|
||||
.attr('class', 'brush')
|
||||
.call(brush)
|
||||
.selectAll('rect')
|
||||
.attr('height', this._attr.height - this._attr.margin.top - this._attr.margin.bottom);
|
||||
}
|
||||
};
|
||||
|
||||
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 isTooltip = this._attr.addTooltip;
|
||||
var layer;
|
||||
var bars;
|
||||
|
||||
|
@ -114,71 +73,69 @@ define(function (require) {
|
|||
|
||||
// enter
|
||||
bars.enter()
|
||||
.append('rect')
|
||||
.attr('class', function (d) {
|
||||
return 'color ' + Legend.prototype.colorToClass.call(this, color(d.label));
|
||||
})
|
||||
.attr('fill', function (d) {
|
||||
return color(d.label);
|
||||
});
|
||||
.append('rect')
|
||||
.attr('class', function (d) {
|
||||
return self.colorToClass(color(d.label));
|
||||
})
|
||||
.attr('fill', function (d) {
|
||||
return color(d.label);
|
||||
});
|
||||
|
||||
// update
|
||||
bars
|
||||
.attr('x', function (d) {
|
||||
return xScale(d.x);
|
||||
})
|
||||
.attr('width', function () {
|
||||
var barWidth;
|
||||
var barSpacing;
|
||||
.attr('x', function (d) {
|
||||
return xScale(d.x);
|
||||
})
|
||||
.attr('width', function () {
|
||||
var barWidth;
|
||||
var barSpacing;
|
||||
|
||||
if (data.ordered && data.ordered.date) {
|
||||
barWidth = xScale(data.ordered.min + data.ordered.interval) - xScale(data.ordered.min);
|
||||
barSpacing = barWidth * 0.25;
|
||||
if (data.ordered && data.ordered.date) {
|
||||
barWidth = xScale(data.ordered.min + data.ordered.interval) - xScale(data.ordered.min);
|
||||
barSpacing = barWidth * 0.25;
|
||||
|
||||
return barWidth - barSpacing;
|
||||
}
|
||||
return barWidth - barSpacing;
|
||||
}
|
||||
|
||||
return xScale.rangeBand();
|
||||
})
|
||||
.attr('y', function (d) {
|
||||
return yScale(d.y0 + d.y);
|
||||
})
|
||||
.attr('height', function (d) {
|
||||
return yScale(d.y0) - yScale(d.y0 + d.y);
|
||||
});
|
||||
|
||||
return bars;
|
||||
};
|
||||
|
||||
ColumnChart.prototype.addBarEvents = function (bars) {
|
||||
var self = this;
|
||||
var tooltip = this.vis.tooltip;
|
||||
var isTooltip = this._attr.addTooltip;
|
||||
var dispatch = this._attr.dispatch;
|
||||
|
||||
bars
|
||||
.on('mouseover.bar', function (d, i) {
|
||||
d3.select(this)
|
||||
.classed('hover', true)
|
||||
.style('stroke', '#333')
|
||||
.style('cursor', 'pointer');
|
||||
|
||||
dispatch.hover(self.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('click.bar', function (d, i) {
|
||||
dispatch.click(self.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('mouseout.bar', function () {
|
||||
d3.select(this).classed('hover', false)
|
||||
.style('stroke', null);
|
||||
});
|
||||
return xScale.rangeBand();
|
||||
})
|
||||
.attr('y', function (d) {
|
||||
return yScale(d.y0 + d.y);
|
||||
})
|
||||
.attr('height', function (d) {
|
||||
return yScale(d.y0) - yScale(d.y0 + d.y);
|
||||
});
|
||||
|
||||
// Add tooltip
|
||||
if (isTooltip) {
|
||||
bars.call(tooltip.render());
|
||||
}
|
||||
|
||||
return bars;
|
||||
};
|
||||
|
||||
ColumnChart.prototype.addBarEvents = function (bars) {
|
||||
var events = this.events;
|
||||
var dispatch = this.events._attr.dispatch;
|
||||
|
||||
bars
|
||||
.on('mouseover.bar', function (d, i) {
|
||||
d3.select(this)
|
||||
.classed('hover', true)
|
||||
.style('stroke', '#333')
|
||||
.style('cursor', 'pointer');
|
||||
|
||||
dispatch.hover(events.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('click.bar', function (d, i) {
|
||||
dispatch.click(events.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('mouseout.bar', function () {
|
||||
d3.select(this).classed('hover', false)
|
||||
.style('stroke', null);
|
||||
});
|
||||
};
|
||||
|
||||
ColumnChart.prototype.draw = function () {
|
||||
|
@ -191,6 +148,7 @@ define(function (require) {
|
|||
var elHeight = this._attr.height = $elem.height();
|
||||
var minWidth = 20;
|
||||
var minHeight = 20;
|
||||
var isEvents = this._attr.addEvents;
|
||||
var div;
|
||||
var svg;
|
||||
var width;
|
||||
|
@ -222,13 +180,15 @@ define(function (require) {
|
|||
.attr('transform', 'translate(0,' + margin.top + ')');
|
||||
|
||||
// addBrush canvas
|
||||
self.addBrush(xScale, svg);
|
||||
self.events.addBrush(xScale, svg);
|
||||
|
||||
// add bars
|
||||
bars = self.addBars(svg, layers);
|
||||
|
||||
// add events to bars
|
||||
self.addBarEvents(bars);
|
||||
if (isEvents) {
|
||||
self.addBarEvents(bars);
|
||||
}
|
||||
|
||||
// chart base line
|
||||
var line = svg.append('line')
|
||||
|
|
324
src/kibana/components/vislib/visualizations/line_chart.js
Normal file
324
src/kibana/components/vislib/visualizations/line_chart.js
Normal file
|
@ -0,0 +1,324 @@
|
|||
define(function (require) {
|
||||
return function LineChartFactory(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
|
||||
var Chart = Private(require('components/vislib/visualizations/_chart'));
|
||||
|
||||
// Dynamically adds css file
|
||||
require('css!components/vislib/components/styles/main');
|
||||
|
||||
_(LineChart).inherits(Chart);
|
||||
function LineChart(vis, chartEl, chartData) {
|
||||
if (!(this instanceof LineChart)) {
|
||||
return new LineChart(vis, chartEl, chartData);
|
||||
}
|
||||
|
||||
LineChart.Super.apply(this, arguments);
|
||||
// Line chart specific attributes
|
||||
this._attr = _.defaults(vis._attr || {}, {
|
||||
interpolate: 'linear',
|
||||
xValue: function (d) { return d.x; },
|
||||
yValue: function (d) { return d.y; },
|
||||
dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout')
|
||||
});
|
||||
}
|
||||
|
||||
// Response to `click` and `hover` events
|
||||
LineChart.prototype.eventResponse = function (d, i) {
|
||||
var getYValue = this._attr.yValue;
|
||||
var color = this.vis.data.getColorFunc();
|
||||
var series = this.chartData.series;
|
||||
var config = this._attr;
|
||||
var chartData = this.chartData;
|
||||
|
||||
return {
|
||||
value: getYValue(d, i),
|
||||
point: d,
|
||||
label: d.label,
|
||||
color: color(d.label),
|
||||
pointIndex: i,
|
||||
series: series,
|
||||
config: config,
|
||||
data: chartData,
|
||||
e: d3.event
|
||||
};
|
||||
};
|
||||
|
||||
LineChart.prototype.addCircleEvents = function (circles) {
|
||||
var self = this;
|
||||
var tooltip = this.vis.tooltip;
|
||||
var isTooltip = this._attr.addTooltip;
|
||||
var dispatch = this._attr.dispatch;
|
||||
|
||||
circles
|
||||
.on('mouseover.circle', function mouseOverCircle(d, i) {
|
||||
var circle = this;
|
||||
|
||||
d3.select(circle)
|
||||
.classed('hover', true)
|
||||
.style('stroke', '#333')
|
||||
.style('cursor', 'pointer');
|
||||
|
||||
dispatch.hover(self.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('click.circle', function clickCircle(d, i) {
|
||||
dispatch.click(self.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('mouseout.circle', function mouseOutCircle() {
|
||||
var circle = this;
|
||||
|
||||
d3.select(circle)
|
||||
.classed('hover', false)
|
||||
.style('stroke', null);
|
||||
});
|
||||
|
||||
// Add tooltip
|
||||
if (isTooltip) {
|
||||
circles.call(tooltip.render());
|
||||
}
|
||||
};
|
||||
|
||||
// Add brush to the svg
|
||||
LineChart.prototype.addBrush = function (xScale, svg) {
|
||||
var brushDispatch = this._attr.dispatch.brush;
|
||||
var height = this._attr.height;
|
||||
var margin = this._attr.margin;
|
||||
var self = this;
|
||||
|
||||
// Brush scale
|
||||
var brush = d3.svg.brush()
|
||||
.x(xScale)
|
||||
.on('brushend', function brushEnd() {
|
||||
// response returned on brush
|
||||
return brushDispatch({
|
||||
range: brush.extent(),
|
||||
config: self._attr,
|
||||
e: d3.event,
|
||||
data: self.chartData
|
||||
});
|
||||
});
|
||||
|
||||
if (self._attr.addBrushing) {
|
||||
// add brush canvas
|
||||
svg.append('g')
|
||||
.attr('class', 'brush')
|
||||
.call(brush)
|
||||
.selectAll('rect')
|
||||
.attr('height', height - margin.top - margin.bottom);
|
||||
}
|
||||
};
|
||||
|
||||
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 circleRadius = 4;
|
||||
var circleStrokeWidth = 1;
|
||||
var layer;
|
||||
var circles;
|
||||
|
||||
layer = svg.selectAll('.points')
|
||||
.data(data)
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('class', 'points');
|
||||
|
||||
// Append the bars
|
||||
circles = layer
|
||||
.selectAll('rect')
|
||||
.data(function appendData(d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
// exit
|
||||
circles
|
||||
.exit()
|
||||
.remove();
|
||||
|
||||
// enter
|
||||
circles
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('class', function circleClass(d) {
|
||||
return self.colorToClass(color(d.label));
|
||||
})
|
||||
.attr('fill', function (d) {
|
||||
return color(d.label);
|
||||
})
|
||||
.attr('stroke', function strokeColor(d) {
|
||||
return color(d.label);
|
||||
})
|
||||
.attr('stroke-width', circleStrokeWidth);
|
||||
|
||||
// update
|
||||
circles
|
||||
.attr('cx', function cx(d) {
|
||||
if (ordered && ordered.date) {
|
||||
return xScale(d.x);
|
||||
}
|
||||
return xScale(d.x) + xScale.rangeBand() / 2;
|
||||
})
|
||||
.attr('cy', function cy(d) {
|
||||
return yScale(d.y);
|
||||
})
|
||||
.attr('r', circleRadius);
|
||||
|
||||
return circles;
|
||||
};
|
||||
|
||||
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 interpolate = this._attr.interpolate;
|
||||
var line = d3.svg.line()
|
||||
.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', 'lines');
|
||||
|
||||
lines.append('path')
|
||||
.attr('class', function lineClass(d) {
|
||||
return self.colorToClass(color(d.label));
|
||||
})
|
||||
.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;
|
||||
};
|
||||
|
||||
LineChart.prototype.addClipPath = function (svg, width, height) {
|
||||
// Prevents circles from being clipped at the top of the chart
|
||||
var clipPathBuffer = 5;
|
||||
var startX = 0;
|
||||
var startY = 0 - clipPathBuffer;
|
||||
|
||||
// Creating clipPath
|
||||
return svg
|
||||
.attr('clip-path', 'url(#chart-area)')
|
||||
.append('clipPath')
|
||||
.attr('id', 'chart-area')
|
||||
.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);
|
||||
};
|
||||
|
||||
LineChart.prototype.draw = function () {
|
||||
// Attributes
|
||||
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 xScale = this.vis.xAxis.xScale;
|
||||
var chartToSmallError = 'The height and/or width of this container is too small for this chart.';
|
||||
var minWidth = 20;
|
||||
var minHeight = 20;
|
||||
var startLineX = 0;
|
||||
var lineStrokeWidth = 1;
|
||||
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 {
|
||||
label: label,
|
||||
x: self._attr.xValue.call(d.values, e, i),
|
||||
y: self._attr.yValue.call(d.values, e, i)
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Get the width and height
|
||||
width = elWidth - margin.left - margin.right;
|
||||
height = elHeight - margin.top - margin.bottom;
|
||||
|
||||
// if height or width < 20 or NaN, throw error
|
||||
if (_.isNaN(width) || width < minWidth || _.isNaN(height) || height < minHeight) {
|
||||
throw new Error(chartToSmallError);
|
||||
}
|
||||
|
||||
// Select the current DOM element
|
||||
div = d3.select(el);
|
||||
|
||||
// Create the canvas for the visualization
|
||||
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 + ')');
|
||||
|
||||
// add clipPath to hide circles when they go out of bounds
|
||||
self.addClipPath(svg, width, height);
|
||||
|
||||
// addBrush canvas
|
||||
self.addBrush(xScale, svg);
|
||||
|
||||
// add lines
|
||||
lines = self.addLines(svg, data.series);
|
||||
|
||||
// add circles
|
||||
circles = self.addCircles(svg, layers);
|
||||
|
||||
// add click and hover events to circles
|
||||
self.addCircleEvents(circles);
|
||||
|
||||
// chart base line
|
||||
var line = svg
|
||||
.append('line')
|
||||
.attr('x1', startLineX)
|
||||
.attr('y1', height)
|
||||
.attr('x2', width)
|
||||
.attr('y2', height)
|
||||
.style('stroke', '#ddd')
|
||||
.style('stroke-width', lineStrokeWidth);
|
||||
|
||||
return svg;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return LineChart;
|
||||
};
|
||||
});
|
146
src/kibana/components/vislib/visualizations/pie_chart.js
Normal file
146
src/kibana/components/vislib/visualizations/pie_chart.js
Normal file
|
@ -0,0 +1,146 @@
|
|||
define(function (require) {
|
||||
return function PieChartFactory(d3, Private) {
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
|
||||
var Chart = Private(require('components/vislib/visualizations/_chart'));
|
||||
|
||||
// Dynamically adds css file
|
||||
require('css!components/vislib/styles/main');
|
||||
|
||||
/*
|
||||
* Column chart visualization => vertical bars, stacked bars
|
||||
*/
|
||||
_(PieChart).inherits(Chart);
|
||||
function PieChart(vis, chartEl, chartData) {
|
||||
if (!(this instanceof PieChart)) {
|
||||
return new PieChart(vis, chartEl, chartData);
|
||||
}
|
||||
PieChart.Super.apply(this, arguments);
|
||||
|
||||
this._attr = _.defaults(vis._attr || {}, {
|
||||
getSize: function (d) { return d.size; },
|
||||
dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout')
|
||||
});
|
||||
}
|
||||
|
||||
PieChart.prototype.addPathEvents = function (path) {
|
||||
var events = this.events;
|
||||
var dispatch = this.events._attr.dispatch;
|
||||
|
||||
path
|
||||
.on('mouseover.pie', function mouseOverPie(d, i) {
|
||||
d3.select(this)
|
||||
.classed('hover', true)
|
||||
.style('cursor', 'pointer');
|
||||
|
||||
dispatch.hover(events.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('click.pie', function clickPie(d, i) {
|
||||
dispatch.click(events.eventResponse(d, i));
|
||||
d3.event.stopPropagation();
|
||||
})
|
||||
.on('mouseout.pie', function mouseOutPie() {
|
||||
d3.select(this)
|
||||
.classed('hover', false)
|
||||
.style('stroke', null);
|
||||
});
|
||||
};
|
||||
|
||||
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 partition = d3.layout.partition()
|
||||
.sort(null)
|
||||
.value(function (d) {
|
||||
return d.size;
|
||||
});
|
||||
var x = d3.scale.linear()
|
||||
.range([0, 2 * Math.PI]);
|
||||
var y = d3.scale.sqrt()
|
||||
.range([0, radius]);
|
||||
var arc = d3.svg.arc()
|
||||
.startAngle(function (d) {
|
||||
return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
|
||||
})
|
||||
.endAngle(function (d) {
|
||||
return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
|
||||
})
|
||||
.innerRadius(function (d) {
|
||||
// option for a single layer, i.e pie chart
|
||||
if (d.depth === 1 && !isDonut) {
|
||||
// return no inner radius
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.max(0, y(d.y));
|
||||
})
|
||||
.outerRadius(function (d) {
|
||||
return Math.max(0, y(d.y + d.dy));
|
||||
});
|
||||
var tooltip = this.vis.tooltip;
|
||||
var isTooltip = this._attr.addTooltip;
|
||||
var self = this;
|
||||
var path;
|
||||
|
||||
path = svg
|
||||
.datum(slices)
|
||||
.selectAll('path')
|
||||
.data(partition.nodes)
|
||||
.enter()
|
||||
.append('path')
|
||||
.attr('d', arc)
|
||||
.attr('class', function (d) {
|
||||
if (d.depth === 0) { return; }
|
||||
return self.colorToClass(color(d.name));
|
||||
})
|
||||
.style('stroke', '#fff')
|
||||
.style('fill', function (d) {
|
||||
return color(d.name);
|
||||
})
|
||||
.attr('fill-rule', 'evenodd');
|
||||
|
||||
// Add tooltip
|
||||
if (isTooltip) {
|
||||
path.call(tooltip.render());
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
PieChart.prototype.draw = function () {
|
||||
var self = this;
|
||||
var isEvents = this._attr.addEvents;
|
||||
|
||||
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 svg = div.append('svg')
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
.append('g')
|
||||
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
|
||||
|
||||
// add pie slices
|
||||
var path = self.addPath(width, height, svg, slices);
|
||||
|
||||
// add events to bars
|
||||
if (isEvents) {
|
||||
self.addPathEvents(path);
|
||||
}
|
||||
|
||||
return svg;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
return PieChart;
|
||||
};
|
||||
});
|
|
@ -2,7 +2,10 @@ define(function (require) {
|
|||
return function VisTypeFactory(Private) {
|
||||
// visLib visualization types
|
||||
return {
|
||||
histogram: Private(require('components/vislib/visualizations/column_chart'))
|
||||
histogram: Private(require('components/vislib/visualizations/column_chart')),
|
||||
pie: Private(require('components/vislib/visualizations/pie_chart')),
|
||||
line: Private(require('components/vislib/visualizations/line_chart'))
|
||||
};
|
||||
};
|
||||
|
||||
});
|
|
@ -19,7 +19,6 @@
|
|||
@sidebar-active-hover-color: @component-active-color;
|
||||
|
||||
@vis-editor-sidebar-basis: (100/12) * 2%; // two of twelve columns
|
||||
@vis-editor-sidebar-min-width: 300px;
|
||||
@vis-editor-nesting-width: 3px;
|
||||
@vis-editor-nesting-expand-width: 10px;
|
||||
@vis-editor-agg-editor-spacing: 5px;
|
||||
@vis-editor-sidebar-min-width: 350px;
|
||||
@vis-editor-nesting-width: 8px;
|
||||
@vis-editor-agg-editor-spacing: 5px;
|
|
@ -210,6 +210,14 @@ notifications {
|
|||
}
|
||||
}
|
||||
|
||||
.navbtn {
|
||||
.button-variant(@navbar-default-color; @navbar-default-bg; @navbar-default-border);
|
||||
}
|
||||
|
||||
.navbtn-inverse {
|
||||
.button-variant(@navbar-default-color; @navbar-default-bg; @navbar-default-border);
|
||||
}
|
||||
|
||||
// right section of the main nav base
|
||||
.navbar-static-top .navbar-right {
|
||||
font-size: @font-size-small;
|
||||
|
|
|
@ -28,6 +28,9 @@ parser = OptionParser.new do |opts|
|
|||
opts.on('-p', '--port PORT', 'Kibana port') do |arg|
|
||||
options[:port] = arg
|
||||
end
|
||||
opts.on('-q', '--quiet', 'Turns off logging') do |arg|
|
||||
options[:quiet] = arg
|
||||
end
|
||||
opts.on('-H', '--host HOST', 'Kibana host') do |arg|
|
||||
options[:host] = arg
|
||||
end
|
||||
|
@ -68,6 +71,7 @@ Kibana.global_settings[:host] = host || '0.0.0.0'
|
|||
Kibana.global_settings[:config] = config
|
||||
Kibana.global_settings[:elasticsearch] = elasticsearch
|
||||
Kibana.global_settings[:root] = File.expand_path("#{File.dirname(__FILE__)}/../")
|
||||
Kibana.global_settings[:quiet] = options[:quiet]
|
||||
|
||||
# Set the public folder based on whether we are running in production or not.
|
||||
if ENV['RACK_ENV'] == ('production')
|
||||
|
|
|
@ -37,7 +37,7 @@ module Kibana
|
|||
end
|
||||
|
||||
configure :production do
|
||||
use JSONLogger, settings.logger
|
||||
use JSONLogger, settings.logger unless Kibana.global_settings[:quiet]
|
||||
end
|
||||
|
||||
configure :quiet do
|
||||
|
@ -45,7 +45,7 @@ module Kibana
|
|||
end
|
||||
|
||||
configure :development do
|
||||
use ColorLogger, settings.logger
|
||||
use ColorLogger, settings.logger unless Kibana.global_settings[:quiet]
|
||||
end
|
||||
|
||||
error do
|
||||
|
|
|
@ -17,6 +17,7 @@ module Kibana
|
|||
}
|
||||
|
||||
def self.log(msg)
|
||||
return if Kibana.global_settings[:quiet]
|
||||
if ENV['RACK_ENV'] == 'production'
|
||||
data = {
|
||||
"@timestamp" => Time.now.iso8601,
|
||||
|
|
|
@ -11,7 +11,7 @@ module.exports = {
|
|||
'<%= src %>/kibana/apps/visualize/styles/visualization.less',
|
||||
'<%= src %>/kibana/apps/visualize/styles/main.less',
|
||||
'<%= src %>/kibana/styles/main.less',
|
||||
'<%= src %>/kibana/components/vislib/components/styles/main.less',
|
||||
'<%= src %>/kibana/components/vislib/styles/main.less',
|
||||
'<%= src %>/kibana/components/**/*.less'
|
||||
],
|
||||
expand: true,
|
||||
|
|
|
@ -25,7 +25,7 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
browserName: 'firefox',
|
||||
platform: 'Linux',
|
||||
platform: 'Windows 7',
|
||||
},
|
||||
{
|
||||
browserName: 'internet explorer',
|
||||
|
|
|
@ -7,10 +7,77 @@ define(function (require) {
|
|||
describe('VisLib _chart Test Suite', function () {
|
||||
var ColumnChart;
|
||||
var Chart;
|
||||
var Data;
|
||||
var Vis;
|
||||
var chartData = {};
|
||||
var vis;
|
||||
var el;
|
||||
var myChart;
|
||||
var config;
|
||||
var data = {
|
||||
hits : 621,
|
||||
label : '',
|
||||
ordered : {
|
||||
date: true,
|
||||
interval: 30000,
|
||||
max : 1408734982458,
|
||||
min : 1408734082458
|
||||
},
|
||||
series : [
|
||||
{
|
||||
values: [
|
||||
{
|
||||
x: 1408734060000,
|
||||
y: 8
|
||||
},
|
||||
{
|
||||
x: 1408734090000,
|
||||
y: 23
|
||||
},
|
||||
{
|
||||
x: 1408734120000,
|
||||
y: 30
|
||||
},
|
||||
{
|
||||
x: 1408734150000,
|
||||
y: 28
|
||||
},
|
||||
{
|
||||
x: 1408734180000,
|
||||
y: 36
|
||||
},
|
||||
{
|
||||
x: 1408734210000,
|
||||
y: 30
|
||||
},
|
||||
{
|
||||
x: 1408734240000,
|
||||
y: 26
|
||||
},
|
||||
{
|
||||
x: 1408734270000,
|
||||
y: 22
|
||||
},
|
||||
{
|
||||
x: 1408734300000,
|
||||
y: 29
|
||||
},
|
||||
{
|
||||
x: 1408734330000,
|
||||
y: 24
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
tooltipFormatter: function (datapoint) {
|
||||
return datapoint;
|
||||
},
|
||||
xAxisFormatter: function (thing) {
|
||||
return thing;
|
||||
},
|
||||
xAxisLabel: 'Date Histogram',
|
||||
yAxisLabel: 'Count'
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
module('ChartBaseClass');
|
||||
|
@ -19,15 +86,24 @@ define(function (require) {
|
|||
|
||||
beforeEach(function () {
|
||||
inject(function (d3, Private) {
|
||||
Vis = Private(require('components/vislib/vis'));
|
||||
Data = Private(require('components/vislib/lib/data'));
|
||||
ColumnChart = Private(require('components/vislib/visualizations/column_chart'));
|
||||
Chart = Private(require('components/vislib/visualizations/_chart'));
|
||||
|
||||
el = d3.select('body').append('div').attr('class', 'column-chart');
|
||||
vis = {
|
||||
_attr: {
|
||||
stack: d3.layout.stack()
|
||||
}
|
||||
|
||||
config = {
|
||||
type: 'histogram',
|
||||
shareYAxis: true,
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
stack: d3.layout.stack(),
|
||||
};
|
||||
|
||||
vis = new Vis(el[0][0], config);
|
||||
vis.data = new Data(data, config);
|
||||
|
||||
myChart = new ColumnChart(vis, el, chartData);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -73,7 +73,7 @@ define(function (require) {
|
|||
|
||||
beforeEach(function () {
|
||||
inject(function (d3, Private) {
|
||||
layoutType = Private(require('components/vislib/layout_types'));
|
||||
layoutType = Private(require('components/vislib/lib/layout/layout_types'));
|
||||
el = d3.select('body').append('div').attr('class', 'visualization');
|
||||
columnLayout = layoutType.histogram(el, data);
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ define(function (require) {
|
|||
var Data;
|
||||
var Handler;
|
||||
var handler;
|
||||
var ColumnHandler;
|
||||
var vis;
|
||||
var el;
|
||||
var example;
|
||||
|
@ -92,7 +93,8 @@ define(function (require) {
|
|||
inject(function (d3, Private) {
|
||||
Vis = Private(require('components/vislib/vis'));
|
||||
Data = Private(require('components/vislib/lib/data'));
|
||||
Handler = Private(require('components/vislib/lib/handler'));
|
||||
Handler = Private(require('components/vislib/lib/handler/handler'));
|
||||
ColumnHandler = Private(require('components/vislib/lib/handler/types/column'));
|
||||
|
||||
el = d3.select('body').append('div')
|
||||
.attr('class', 'visualize');
|
||||
|
@ -105,14 +107,9 @@ define(function (require) {
|
|||
};
|
||||
|
||||
vis = new Vis(el[0][0], config);
|
||||
vis.data = data;
|
||||
|
||||
handler = new Handler({
|
||||
vis: vis,
|
||||
el: el[0][0],
|
||||
data: data,
|
||||
ChartClass: vis.ChartClass,
|
||||
_attr: config
|
||||
});
|
||||
handler = ColumnHandler(vis);
|
||||
|
||||
// handler.render(data);
|
||||
});
|
||||
|
|
|
@ -77,8 +77,8 @@ define(function (require) {
|
|||
|
||||
beforeEach(function () {
|
||||
inject(function (d3, Private) {
|
||||
Layout = Private(require('components/vislib/lib/layout'));
|
||||
xAxisSplit = Private(require('components/vislib/components/layouts/splits/column_chart/x_axis_split'));
|
||||
Layout = Private(require('components/vislib/lib/layout/layout'));
|
||||
xAxisSplit = Private(require('components/vislib/lib/layout/splits/column_chart/x_axis_split'));
|
||||
|
||||
el = d3.select('body').append('div')
|
||||
.attr('class', 'visualize-chart');
|
||||
|
|
|
@ -14,7 +14,7 @@ define(function (require) {
|
|||
|
||||
beforeEach(function () {
|
||||
inject(function (d3, Private) {
|
||||
layoutType = Private(require('components/vislib/layout_types'));
|
||||
layoutType = Private(require('components/vislib/lib/layout/layout_types'));
|
||||
layoutFunc = layoutType.histogram;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -144,10 +144,10 @@ define(function (require) {
|
|||
|
||||
beforeEach(function () {
|
||||
inject(function (d3, Private) {
|
||||
chartSplit = Private(require('components/vislib/components/layouts/splits/column_chart/chart_split'));
|
||||
chartTitleSplit = Private(require('components/vislib/components/layouts/splits/column_chart/chart_title_split'));
|
||||
xAxisSplit = Private(require('components/vislib/components/layouts/splits/column_chart/x_axis_split'));
|
||||
yAxisSplit = Private(require('components/vislib/components/layouts/splits/column_chart/y_axis_split'));
|
||||
chartSplit = Private(require('components/vislib/lib/layout/splits/column_chart/chart_split'));
|
||||
chartTitleSplit = Private(require('components/vislib/lib/layout/splits/column_chart/chart_title_split'));
|
||||
xAxisSplit = Private(require('components/vislib/lib/layout/splits/column_chart/x_axis_split'));
|
||||
yAxisSplit = Private(require('components/vislib/lib/layout/splits/column_chart/y_axis_split'));
|
||||
|
||||
el = d3.select('body').append('div')
|
||||
.attr('class', 'visualization')
|
||||
|
|
|
@ -14,7 +14,7 @@ define(function (require) {
|
|||
|
||||
beforeEach(function () {
|
||||
inject(function (d3, Private) {
|
||||
visTypes = Private(require('components/vislib/vis_types'));
|
||||
visTypes = Private(require('components/vislib/visualizations/vis_types'));
|
||||
visFunc = visTypes.histogram;
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue