mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* gauge chart * adding ranges and color options * adding green to red color pallete * adding more options * fixing based on tanya's review * fixing label positions * improving range settings * percentage mode applies to legend * hidding labels when too long * updating based on ui rview * rebasing on master * adding unit tests * adding selenium tests * fixing tests * adding metric gauge type * removing metric vis * adding metric and goal charts * updating options * fixing bugs * fixing based on review from Thomas * updating icons * fixing tests * updating based on last review * hide some settings if only one range * fixing tests * removing unsupported aggs * fixing defaults * fixing options * fixing error with inverse color schema * adding spacing to info icon * fixing some tiny issues
This commit is contained in:
parent
cbddb475d1
commit
9c67b2a0e2
43 changed files with 1964 additions and 512 deletions
|
@ -0,0 +1,287 @@
|
|||
<div>
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="gaugeType">
|
||||
Gauge Type
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<select
|
||||
id="gaugeType"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.gauge.gaugeType"
|
||||
ng-options="mode for mode in vis.type.params.gaugeTypes"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="percentageMode">
|
||||
Percentage Mode
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input class="kuiCheckBox" id="percentageMode" type="checkbox" ng-model="vis.params.gauge.percentageMode">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="verticalSplit">
|
||||
Vertical Split
|
||||
<kbn-info
|
||||
placement="right"
|
||||
info="Shows gauges one under another">
|
||||
</kbn-info>
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input class="kuiCheckBox" id="verticalSplit" type="checkbox" ng-model="vis.params.gauge.verticalSplit">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="showLabels">
|
||||
Show Labels
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input class="kuiCheckBox" id="showLabels" type="checkbox" ng-model="vis.params.gauge.labels.show">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kuiSideBarFormRow" ng-show="vis.params.gauge.labels.show">
|
||||
<label class="kuiSideBarFormRow__label" for="subText">
|
||||
Sub Text
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input
|
||||
id="subText"
|
||||
class="kuiInput kuiSideBarInput"
|
||||
ng-model="vis.params.gauge.style.subText"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="kuiSideBarFormRow"
|
||||
ng-hide="vis.params.gauge.type === 'simple'"
|
||||
ng-show="vis.params.gauge.colorsRange.length > 1"
|
||||
>
|
||||
<label class="kuiSideBarFormRow__label" for="extendRange">
|
||||
Auto Extend Range
|
||||
<kbn-info
|
||||
placement="right"
|
||||
info="Extends range to the maximum value in your data">
|
||||
</kbn-info>
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input class="kuiCheckBox" id="extendRange" type="checkbox" ng-model="vis.params.gauge.extendRange">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="kuiSideBarCollapsibleTitle">
|
||||
<div
|
||||
class="kuiSideBarCollapsibleTitle__label"
|
||||
ng-click="showColorRange = !showColorRange"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
ng-class="{ 'fa-caret-down': showColorRange, 'fa-caret-right': !showColorRange }"
|
||||
class="fa fa-caret-right kuiSideBarCollapsibleTitle__caret"
|
||||
></span>
|
||||
<span class="kuiSideBarCollapsibleTitle__text">
|
||||
Ranges
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="showColorRange" class="kuiSideBarCollapsibleSection">
|
||||
<div class="kuiSideBarSection">
|
||||
<table class="vis-editor-agg-editor-ranges form-group" ng-show="vis.params.gauge.colorsRange.length">
|
||||
<tr>
|
||||
<th>
|
||||
<label>From</label>
|
||||
</th>
|
||||
<th colspan="2">
|
||||
<label>To</label>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr ng-repeat="range in vis.params.gauge.colorsRange track by $index">
|
||||
<td>
|
||||
<input
|
||||
ng-model="range.from"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="range.from"
|
||||
greater-or-equal-than="{{getGreaterThan($index)}}"
|
||||
required
|
||||
step="any" />
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
ng-model="range.to"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="range.to"
|
||||
greater-or-equal-than="{{range.from}}"
|
||||
required
|
||||
step="any" />
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
ng-click="removeRange($index)"
|
||||
ng-show="vis.params.gauge.colorsRange.length > 1"
|
||||
class="kuiButton kuiButton--danger kuiButton--small">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="hintbox" ng-show="!vis.params.gauge.colorsRange.length">
|
||||
<p>
|
||||
<i class="fa fa-danger text-danger"></i>
|
||||
<strong>Required:</strong> You must specify at least one range.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ng-click="addRange()"
|
||||
class="kuiButton kuiButton--primary kuiButton--fullWidth">
|
||||
Add Range
|
||||
</div>
|
||||
<div class="text text-center text-info">Note: colors can be changed in the legend</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="vis.params.gauge.colorsRange.length > 1">
|
||||
<div class="kuiSideBarCollapsibleTitle">
|
||||
<div
|
||||
class="kuiSideBarCollapsibleTitle__label"
|
||||
ng-click="showColorOptions = !showColorOptions"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
ng-class="{
|
||||
'fa-caret-down': showColorOptions,
|
||||
'fa-caret-right': !showColorOptions
|
||||
}"
|
||||
class="fa fa-caret-right kuiSideBarCollapsibleTitle__caret"
|
||||
></span>
|
||||
<span class="kuiSideBarCollapsibleTitle__text">
|
||||
Color Options
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="showColorOptions" class="kuiSideBarCollapsibleSection">
|
||||
<div class="kuiSideBarSection">
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="colorSchema">
|
||||
Color Schema
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<select
|
||||
id="colorSchema"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.gauge.colorSchema"
|
||||
ng-options="mode for mode in vis.type.params.colorSchemas"
|
||||
></select>
|
||||
</div>
|
||||
<div class="text-info text-center" ng-show="customColors" ng-click="resetColors()">reset colors</div>
|
||||
</div>
|
||||
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="invertColors">
|
||||
Reverse Color Schema
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input class="kuiCheckBox" id="invertColors" type="checkbox" ng-model="vis.params.gauge.invertColors">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
<div class="kuiSideBarCollapsibleTitle">
|
||||
<div
|
||||
class="kuiSideBarCollapsibleTitle__label"
|
||||
ng-click="showStyle = !showStyle"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
ng-class="{
|
||||
'fa-caret-down': showStyle,
|
||||
'fa-caret-right': !showStyle
|
||||
}"
|
||||
class="fa fa-caret-right kuiSideBarCollapsibleTitle__caret"
|
||||
></span>
|
||||
<span class="kuiSideBarCollapsibleTitle__text">
|
||||
Style
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="showStyle" class="kuiSideBarCollapsibleSection">
|
||||
|
||||
<div class="kuiSideBarSection">
|
||||
<div ng-hide="vis.params.gauge.type === 'simple'">
|
||||
<div class="kuiSideBarFormRow" ng-show="vis.params.gauge.colorsRange.length > 1">
|
||||
<label class="kuiSideBarFormRow__label" for="labelColor">
|
||||
Color Labels
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input class="kuiCheckBox" id="labelColor" type="checkbox" ng-model="vis.params.gauge.style.labelColor">
|
||||
</div>
|
||||
</div>
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="showScale">
|
||||
Show Scale
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input class="kuiCheckBox" id="showScale" type="checkbox" ng-model="vis.params.gauge.scale.show">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="vis.params.gauge.type === 'simple'">
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="gaugeColorMode">
|
||||
Color
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<select
|
||||
id="gaugeColorMode"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.gauge.gaugeColorMode"
|
||||
ng-options="mode for mode in vis.type.params.gaugeColorMode"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="backColor">
|
||||
Back/Text Color
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input
|
||||
id="backTextColor"
|
||||
class="kuiInput kuiSideBarInput"
|
||||
ng-model="vis.params.gauge.style.bgFill"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kuiSideBarFormRow">
|
||||
<label class="kuiSideBarFormRow__label" for="showScale">
|
||||
Font Size (<span ng-bind="vis.params.gauge.style.fontSize"></span>pt)
|
||||
</label>
|
||||
<div class="kuiSideBarFormRow__control">
|
||||
<input type="range" ng-model="vis.params.gauge.style.fontSize" class="form-control" min="12" max="120" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,93 @@
|
|||
import { uiModules } from 'ui/modules';
|
||||
import gaugeOptionsTemplate from 'plugins/kbn_vislib_vis_types/controls/gauge_options.html';
|
||||
import _ from 'lodash';
|
||||
const module = uiModules.get('kibana');
|
||||
|
||||
module.directive('gaugeOptions', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: gaugeOptionsTemplate,
|
||||
replace: true,
|
||||
link: function ($scope) {
|
||||
|
||||
$scope.showColorRange = true;
|
||||
|
||||
$scope.$watch('vis.params.gauge.gaugeType', type => {
|
||||
switch (type) {
|
||||
case 'Arc':
|
||||
$scope.vis.params.gauge.type = 'meter';
|
||||
$scope.vis.params.gauge.minAngle = undefined;
|
||||
$scope.vis.params.gauge.maxAngle = undefined;
|
||||
break;
|
||||
case 'Circle':
|
||||
$scope.vis.params.gauge.type = 'meter';
|
||||
$scope.vis.params.gauge.minAngle = 0;
|
||||
$scope.vis.params.gauge.maxAngle = 2 * Math.PI;
|
||||
break;
|
||||
case 'Metric':
|
||||
$scope.vis.params.gauge.type = 'simple';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const updateLegend = () => {
|
||||
if (!$scope.vis.params.gauge.style.bgColor && !$scope.vis.params.gauge.style.labelColor) {
|
||||
$scope.vis.params.addLegend = false;
|
||||
} else {
|
||||
$scope.vis.params.addLegend = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$watch('vis.params.gauge.gaugeColorMode', newValue => {
|
||||
switch (newValue) {
|
||||
case 'Labels':
|
||||
$scope.vis.params.gauge.style.labelColor = true;
|
||||
$scope.vis.params.gauge.style.bgColor = false;
|
||||
break;
|
||||
case 'Background':
|
||||
$scope.vis.params.gauge.style.labelColor = false;
|
||||
$scope.vis.params.gauge.style.bgColor = true;
|
||||
break;
|
||||
case 'None':
|
||||
$scope.vis.params.gauge.style.labelColor = false;
|
||||
$scope.vis.params.gauge.style.bgColor = false;
|
||||
break;
|
||||
}
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$scope.resetColors = function () {
|
||||
$scope.uiState.set('vis.colors', null);
|
||||
$scope.customColors = false;
|
||||
};
|
||||
|
||||
$scope.getGreaterThan = function (index) {
|
||||
if (index === 0) return 0;
|
||||
return $scope.vis.params.gauge.colorsRange[index - 1].to;
|
||||
};
|
||||
|
||||
$scope.addRange = function () {
|
||||
const previousRange = _.last($scope.vis.params.gauge.colorsRange);
|
||||
const from = previousRange ? previousRange.to : 0;
|
||||
const to = previousRange ? from + (previousRange.to - previousRange.from) : 100;
|
||||
$scope.vis.params.gauge.colorsRange.push({ from: from, to: to });
|
||||
};
|
||||
|
||||
$scope.removeRange = function (index) {
|
||||
$scope.vis.params.gauge.colorsRange.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.getColor = function (index) {
|
||||
const defaultColors = this.uiState.get('vis.defaultColors');
|
||||
const overwriteColors = this.uiState.get('vis.colors');
|
||||
const colors = defaultColors ? _.defaults({}, overwriteColors, defaultColors) : overwriteColors;
|
||||
return colors ? Object.values(colors)[index] : 'transparent';
|
||||
};
|
||||
|
||||
$scope.uiState.on('colorChanged', () => {
|
||||
$scope.customColors = true;
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
<!-- vis type specific options -->
|
||||
<gauge-options></gauge-options>
|
95
src/core_plugins/kbn_vislib_vis_types/public/gauge.js
Normal file
95
src/core_plugins/kbn_vislib_vis_types/public/gauge.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import gaugeTemplate from 'plugins/kbn_vislib_vis_types/editors/gauge.html';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import image from './images/icon-gauge.svg';
|
||||
|
||||
export default function GaugeVisType(Private) {
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return new VislibVisType({
|
||||
name: 'gauge',
|
||||
title: 'Gauge',
|
||||
image,
|
||||
description: `Gauges indicate the status of a metric. Use it to show how a metric's value relates
|
||||
to reference threshold values.`,
|
||||
category: VisType.CATEGORY.DATA,
|
||||
params: {
|
||||
defaults: {
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
|
||||
gauge: {
|
||||
verticalSplit: false,
|
||||
extendRange: true,
|
||||
percentageMode: false,
|
||||
gaugeType: 'Arc',
|
||||
gaugeStyle: 'Full',
|
||||
backStyle: 'Full',
|
||||
orientation: 'vertical',
|
||||
colorSchema: 'Green to Red',
|
||||
gaugeColorMode: 'Labels',
|
||||
colorsRange: [
|
||||
{ from: 0, to: 50 },
|
||||
{ from: 50, to: 75 },
|
||||
{ from: 75, to: 100 }
|
||||
],
|
||||
invertColors: false,
|
||||
labels: {
|
||||
show: true,
|
||||
color: 'black'
|
||||
},
|
||||
scale: {
|
||||
show: true,
|
||||
labels: false,
|
||||
color: '#333',
|
||||
},
|
||||
type: 'meter',
|
||||
style: {
|
||||
bgWidth: 0.9,
|
||||
width: 0.9,
|
||||
mask: false,
|
||||
bgMask: false,
|
||||
maskBars: 50,
|
||||
bgFill: '#eee',
|
||||
bgColor: true,
|
||||
subText: '',
|
||||
fontSize: 60,
|
||||
}
|
||||
}
|
||||
},
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
gaugeStyles: ['Full', 'Bars', 'Lines'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
editor: gaugeTemplate
|
||||
},
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
89
src/core_plugins/kbn_vislib_vis_types/public/goal.js
Normal file
89
src/core_plugins/kbn_vislib_vis_types/public/goal.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import gaugeTemplate from 'plugins/kbn_vislib_vis_types/editors/gauge.html';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import image from './images/icon-goal.svg';
|
||||
|
||||
export default function GoalVisType(Private) {
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return new VislibVisType({
|
||||
name: 'goal',
|
||||
title: 'Goal',
|
||||
image,
|
||||
description: 'A goal chart indicates how close you are to your final goal.',
|
||||
category: VisType.CATEGORY.DATA,
|
||||
params: {
|
||||
defaults: {
|
||||
addTooltip: true,
|
||||
addLegend: false,
|
||||
type: 'gauge',
|
||||
gauge: {
|
||||
verticalSplit: false,
|
||||
autoExtend: false,
|
||||
percentageMode: true,
|
||||
gaugeType: 'Arc',
|
||||
gaugeStyle: 'Full',
|
||||
backStyle: 'Full',
|
||||
orientation: 'vertical',
|
||||
useRanges: false,
|
||||
colorSchema: 'Green to Red',
|
||||
gaugeColorMode: 'None',
|
||||
colorsRange: [
|
||||
{ from: 0, to: 10000 }
|
||||
],
|
||||
invertColors: false,
|
||||
labels: {
|
||||
show: true,
|
||||
color: 'black'
|
||||
},
|
||||
scale: {
|
||||
show: false,
|
||||
labels: false,
|
||||
color: '#333',
|
||||
width: 2
|
||||
},
|
||||
type: 'meter',
|
||||
style: {
|
||||
bgFill: '#000',
|
||||
bgColor: false,
|
||||
labelColor: false,
|
||||
subText: '',
|
||||
fontSize: 60,
|
||||
}
|
||||
}
|
||||
},
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
editor: gaugeTemplate
|
||||
},
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="60px" height="41px" viewBox="0 0 60 41" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icon-gauge</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Visualize" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Visualize-Create-New" transform="translate(-916.000000, -655.000000)" fill="#000000">
|
||||
<g id="other" transform="translate(555.000000, 576.000000)">
|
||||
<g id="gauge" transform="translate(321.000000, 45.000000)">
|
||||
<g id="icon-gauge" transform="translate(40.000000, 34.000000)">
|
||||
<path d="M2.3213,41.0269 C0.7813,37.3839 0.0003,33.5169 0.0003,29.5309 C0.0003,13.2479 13.2473,-0.0001 29.5313,-0.0001 C45.8153,-0.0001 59.0623,13.2479 59.0623,29.5309 C59.0623,33.1519 58.4143,36.6899 57.1343,40.0459 L52.4633,38.2639 C53.5243,35.4799 54.0623,32.5419 54.0623,29.5309 C54.0623,16.0049 43.0573,4.9999 29.5313,4.9999 C16.0053,4.9999 5.0003,16.0049 5.0003,29.5309 C5.0003,32.8439 5.6483,36.0559 6.9263,39.0799 L2.3213,41.0269 Z" id="Fill-1"></path>
|
||||
<path d="M43.3481,18.3726 L40.5201,15.5446 L31.9481,24.1166 C31.1911,23.7726 30.3531,23.5766 29.4691,23.5766 C26.1551,23.5766 23.4691,26.2626 23.4691,29.5766 C23.4691,32.8896 26.1551,35.5766 29.4691,35.5766 C32.7821,35.5766 35.4691,32.8896 35.4691,29.5766 C35.4691,28.6096 35.2351,27.7006 34.8291,26.8916 L43.3481,18.3726 Z" id="Fill-3"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="57px" height="43px" viewBox="0 0 57 43" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icon goal</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<polygon id="path-1" points="0 41.32 0 0.293 28.0314 0.293 56.0628 0.293 56.0628 41.32 2.56295907e-15 41.32"></polygon>
|
||||
</defs>
|
||||
<g id="Visualize" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Visualize-Create-New" transform="translate(-1076.000000, -656.000000)">
|
||||
<g id="other" transform="translate(555.000000, 576.000000)">
|
||||
<g id="gauge-w/-goal" transform="translate(481.000000, 45.000000)">
|
||||
<g id="icon-goal" transform="translate(40.000000, 34.000000)">
|
||||
<g id="Group-3" transform="translate(0.000000, 0.707000)">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<g id="Clip-2"></g>
|
||||
<path d="M40.9258,5.867 C40.9258,5.867 39.9208,5.397 39.0838,5.083 L40.1388,2.263 C36.8448,0.991 33.2678,0.293 29.5308,0.293 C13.2478,0.293 -0.0002,13.54 -0.0002,29.824 C-0.0002,33.809 0.7808,37.677 2.3218,41.32 L6.9268,39.372 C5.6488,36.349 4.9998,33.137 4.9998,29.824 C4.9998,16.298 16.0048,5.293 29.5308,5.293 C32.6518,5.293 35.6388,5.879 38.3868,6.946 C47.5498,10.505 54.0628,19.419 54.0628,29.824 C54.0628,32.834 53.5248,35.772 52.4628,38.557 L54.3088,39.299 C54.3088,39.299 54.4508,38.949 54.6278,38.42 C54.8038,37.89 54.9728,37.374 54.9728,37.374 C55.6968,34.935 56.0628,32.404 56.0628,29.824 C56.0628,19.625 50.0548,10.235 40.9258,5.867" id="Fill-1" fill="#000000" mask="url(#mask-2)"></path>
|
||||
</g>
|
||||
<path d="M27.0532,26.3679 C27.6432,26.9749 28.4612,27.2779 29.5072,27.2779 C30.5652,27.2779 31.3842,26.9749 31.9612,26.3679 C32.5392,25.7619 32.8272,24.9799 32.8272,24.0209 C32.8272,22.9779 32.5392,22.1619 31.9612,21.5739 C31.3842,20.9859 30.5652,20.6919 29.5072,20.6919 C28.4612,20.6919 27.6432,20.9859 27.0532,21.5739 C26.4632,22.1619 26.1682,22.9779 26.1682,24.0209 C26.1682,24.9799 26.4632,25.7619 27.0532,26.3679 M26.7232,38.3759 C27.3972,39.0919 28.3272,39.4499 29.5162,39.4499 C30.7042,39.4499 31.6362,39.0919 32.3092,38.3759 C32.9822,37.6609 33.3192,36.6539 33.3192,35.3559 C33.3192,34.0099 32.9762,32.9879 32.2912,32.2899 C31.6052,31.5929 30.6802,31.2439 29.5162,31.2439 C28.3522,31.2439 27.4272,31.5929 26.7412,32.2899 C26.0562,32.9879 25.7142,34.0099 25.7142,35.3559 C25.7142,36.6539 26.0502,37.6609 26.7232,38.3759 M21.3312,31.6799 C22.0002,30.4799 22.9802,29.5759 24.2692,28.9699 C22.9912,28.1209 22.1602,27.2019 21.7772,26.2129 C21.3932,25.2249 21.2012,24.2999 21.2012,23.4389 C21.2012,21.5229 21.9252,19.8879 23.3712,18.5349 C24.8182,17.1829 26.8602,16.5069 29.4982,16.5069 C32.1362,16.5069 34.1782,17.1829 35.6252,18.5349 C37.0712,19.8879 37.7952,21.5229 37.7952,23.4389 C37.7952,24.2999 37.6032,25.2249 37.2212,26.2129 C36.8392,27.2019 36.0112,28.0599 34.7382,28.7879 C36.0422,29.5149 37.0222,30.4799 37.6812,31.6799 C38.3392,32.8819 38.6682,34.2219 38.6682,35.7009 C38.6682,37.9209 37.8452,39.8109 36.2002,41.3689 C34.5552,42.9279 32.2572,43.7069 29.3072,43.7069 C26.3562,43.7069 24.1222,42.9279 22.6052,41.3689 C21.0872,39.8109 20.3282,37.9209 20.3282,35.7009 C20.3282,34.2219 20.6622,32.8819 21.3312,31.6799" id="Fill-4" fill="#000000"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -7,6 +7,9 @@ import areaVisTypeProvider from 'plugins/kbn_vislib_vis_types/area';
|
|||
import tileMapVisTypeProvider from 'plugins/kbn_vislib_vis_types/tile_map';
|
||||
import heatmapVisTypeProvider from 'plugins/kbn_vislib_vis_types/heatmap';
|
||||
import horizontalBarVisTypeProvider from 'plugins/kbn_vislib_vis_types/horizontal_bar';
|
||||
import gaugeVisTypeProvider from 'plugins/kbn_vislib_vis_types/gauge';
|
||||
import goalVisTypeProvider from 'plugins/kbn_vislib_vis_types/goal';
|
||||
import metricVisTypeProvider from 'plugins/kbn_vislib_vis_types/metric';
|
||||
|
||||
VisTypesRegistryProvider.register(histogramVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(lineVisTypeProvider);
|
||||
|
@ -15,3 +18,6 @@ VisTypesRegistryProvider.register(areaVisTypeProvider);
|
|||
VisTypesRegistryProvider.register(tileMapVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(heatmapVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(horizontalBarVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(gaugeVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(goalVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(metricVisTypeProvider);
|
||||
|
|
89
src/core_plugins/kbn_vislib_vis_types/public/metric.js
Normal file
89
src/core_plugins/kbn_vislib_vis_types/public/metric.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import gaugeTemplate from 'plugins/kbn_vislib_vis_types/editors/gauge.html';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import image from './images/icon-number.svg';
|
||||
|
||||
export default function MetricVisType(Private) {
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return new VislibVisType({
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
image,
|
||||
description: 'Display a calculation as a single number',
|
||||
category: VisType.CATEGORY.DATA,
|
||||
params: {
|
||||
defaults: {
|
||||
addTooltip: true,
|
||||
addLegend: false,
|
||||
type: 'gauge',
|
||||
gauge: {
|
||||
verticalSplit: false,
|
||||
autoExtend: false,
|
||||
percentageMode: false,
|
||||
gaugeType: 'Metric',
|
||||
gaugeStyle: 'Full',
|
||||
backStyle: 'Full',
|
||||
orientation: 'vertical',
|
||||
colorSchema: 'Green to Red',
|
||||
gaugeColorMode: 'None',
|
||||
useRange: false,
|
||||
colorsRange: [
|
||||
{ from: 0, to: 100 },
|
||||
],
|
||||
invertColors: false,
|
||||
labels: {
|
||||
show: true,
|
||||
color: 'black'
|
||||
},
|
||||
scale: {
|
||||
show: false,
|
||||
labels: false,
|
||||
color: '#333',
|
||||
width: 2
|
||||
},
|
||||
type: 'simple',
|
||||
style: {
|
||||
fontSize: 60,
|
||||
bgFill: '#000',
|
||||
bgColor: false,
|
||||
labelColor: false,
|
||||
subText: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
editor: gaugeTemplate
|
||||
},
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
|
@ -28,6 +28,10 @@
|
|||
.form-horizontal .control-label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.kuiSideBarSelect {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
nesting-indicator {
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
export default function (kibana) {
|
||||
|
||||
return new kibana.Plugin({
|
||||
|
||||
uiExports: {
|
||||
visTypes: [
|
||||
'plugins/metric_vis/metric_vis'
|
||||
]
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"name": "metric_vis",
|
||||
"version": "kibana"
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import ngMock from 'ng_mock';
|
||||
import expect from 'expect.js';
|
||||
|
||||
import { VisProvider } from 'ui/vis';
|
||||
import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
import MetricVisProvider from '../metric_vis';
|
||||
|
||||
describe('metric_vis', () => {
|
||||
let setup = null;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject((Private, $rootScope) => {
|
||||
setup = () => {
|
||||
const Vis = Private(VisProvider);
|
||||
const metricVisType = Private(MetricVisProvider);
|
||||
const indexPattern = Private(LogstashIndexPatternStubProvider);
|
||||
|
||||
indexPattern.stubSetFieldFormat('ip', 'url', {
|
||||
urlTemplate: 'http://ip.info?address={{value}}',
|
||||
labelTemplate: 'ip[{{value}}]'
|
||||
});
|
||||
|
||||
const vis = new Vis(indexPattern, {
|
||||
type: 'metric',
|
||||
aggs: [{ id: '1', type: 'top_hits', schema: 'metric', params: { field: 'ip' } }],
|
||||
});
|
||||
|
||||
const $el = $('<div>');
|
||||
const renderbot = metricVisType.createRenderbot(vis, $el);
|
||||
const render = (esResponse) => {
|
||||
renderbot.render(esResponse);
|
||||
$rootScope.$digest();
|
||||
};
|
||||
|
||||
return { $el, render };
|
||||
};
|
||||
}));
|
||||
|
||||
it('renders html value from field formatter', () => {
|
||||
const { $el, render } = setup();
|
||||
|
||||
const ip = '235.195.237.208';
|
||||
render({
|
||||
hits: { total: 0, hits: [] },
|
||||
aggregations: {
|
||||
'1': {
|
||||
hits: { total: 1, hits: [{ _source: { ip } }] }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const $link = $el
|
||||
.find('a[href]')
|
||||
.filter(function () { return this.href.includes('ip.info'); });
|
||||
|
||||
expect($link).to.have.length(1);
|
||||
expect($link.text()).to.be(`ip[${ip}]`);
|
||||
});
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
import ngMock from 'ng_mock';
|
||||
import expect from 'expect.js';
|
||||
import $ from 'jquery';
|
||||
|
||||
describe('metric vis', function () {
|
||||
let $scope;
|
||||
|
||||
const formatter = function (value) {
|
||||
return value.toFixed(3);
|
||||
};
|
||||
|
||||
beforeEach(ngMock.module('kibana/metric_vis'));
|
||||
beforeEach(ngMock.inject(function ($rootScope, $controller) {
|
||||
$scope = $rootScope.$new();
|
||||
const $element = $('<div>');
|
||||
$controller('KbnMetricVisController', { $scope, $element });
|
||||
$scope.$digest();
|
||||
}));
|
||||
|
||||
it('should set the metric label and value', function () {
|
||||
$scope.processTableGroups({
|
||||
tables: [{
|
||||
columns: [{ title: 'Count' }],
|
||||
rows: [[ { toString: () => formatter(4301021) } ]]
|
||||
}]
|
||||
});
|
||||
|
||||
expect($scope.metrics.length).to.be(1);
|
||||
expect($scope.metrics[0].label).to.be('Count');
|
||||
expect($scope.metrics[0].value).to.be('4301021.000');
|
||||
});
|
||||
|
||||
it('should support multi-value metrics', function () {
|
||||
$scope.processTableGroups({
|
||||
tables: [{
|
||||
columns: [
|
||||
{ title: '1st percentile of bytes' },
|
||||
{ title: '99th percentile of bytes' }
|
||||
],
|
||||
rows: [[ { toString: () => formatter(182) }, { toString: () => formatter(445842.4634666484) } ]]
|
||||
}]
|
||||
});
|
||||
|
||||
expect($scope.metrics.length).to.be(2);
|
||||
expect($scope.metrics[0].label).to.be('1st percentile of bytes');
|
||||
expect($scope.metrics[0].value).to.be('182.000');
|
||||
expect($scope.metrics[1].label).to.be('99th percentile of bytes');
|
||||
expect($scope.metrics[1].value).to.be('445842.463');
|
||||
});
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
<div ng-controller="KbnMetricVisController" class="metric-vis">
|
||||
<div class="metric-container" ng-repeat="metric in metrics">
|
||||
<div class="metric-value" ng-bind-html="metric.value" ng-style="{'font-size': vis.params.fontSize+'pt'}"></div>
|
||||
<div>{{metric.label}}</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,55 +0,0 @@
|
|||
import 'plugins/metric_vis/metric_vis.less';
|
||||
import 'plugins/metric_vis/metric_vis_controller';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import metricVisTemplate from 'plugins/metric_vis/metric_vis.html';
|
||||
import metricVisParamsTemplate from 'plugins/metric_vis/metric_vis_params.html';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import image from './images/icon-number.svg';
|
||||
// we need to load the css ourselves
|
||||
|
||||
// we also need to load the controller and used by the template
|
||||
|
||||
// register the provider with the visTypes registry
|
||||
VisTypesRegistryProvider.register(MetricVisProvider);
|
||||
|
||||
function MetricVisProvider(Private) {
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const TemplateVisType = Private(TemplateVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
// return the visType object, which kibana will use to display and configure new
|
||||
// Vis object of this type.
|
||||
return new TemplateVisType({
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
image,
|
||||
description: 'Display a calculation as a single number',
|
||||
category: VisType.CATEGORY.DATA,
|
||||
template: metricVisTemplate,
|
||||
params: {
|
||||
defaults: {
|
||||
handleNoResults: true,
|
||||
fontSize: 60
|
||||
},
|
||||
editor: metricVisParamsTemplate
|
||||
},
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: ['!derivative', '!geo_centroid'],
|
||||
defaults: [
|
||||
{ type: 'count', schema: 'metric' }
|
||||
]
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
||||
// export the provider so that the visType can be required with Private()
|
||||
export default MetricVisProvider;
|
|
@ -1,18 +0,0 @@
|
|||
@import (reference) "~ui/styles/mixins.less";
|
||||
|
||||
.metric-vis {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.metric-value {
|
||||
font-weight: bold;
|
||||
.ellipsis();
|
||||
}
|
||||
|
||||
.metric-container {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
import { AggResponseTabifyProvider } from 'ui/agg_response/tabify/tabify';
|
||||
import { uiModules } from 'ui/modules';
|
||||
// get the kibana/metric_vis module, and make sure that it requires the "kibana" module if it
|
||||
// didn't already
|
||||
const module = uiModules.get('kibana/metric_vis', ['kibana']);
|
||||
|
||||
module.controller('KbnMetricVisController', function ($scope, $element, Private) {
|
||||
const tabifyAggResponse = Private(AggResponseTabifyProvider);
|
||||
|
||||
const metrics = $scope.metrics = [];
|
||||
|
||||
$scope.processTableGroups = function (tableGroups) {
|
||||
tableGroups.tables.forEach(function (table) {
|
||||
table.columns.forEach(function (column, i) {
|
||||
const value = table.rows[0][i];
|
||||
|
||||
metrics.push({
|
||||
label: column.title,
|
||||
value: value.toString('html')
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watch('esResponse', function (resp) {
|
||||
if (resp) {
|
||||
const options = {
|
||||
asAggConfigResults: true
|
||||
};
|
||||
|
||||
metrics.length = 0;
|
||||
$scope.processTableGroups(tabifyAggResponse($scope.vis, resp, options));
|
||||
$element.trigger('renderComplete');
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,4 +0,0 @@
|
|||
<div class="form-group">
|
||||
<label>Font Size - {{ vis.params.fontSize }}pt</label>
|
||||
<input type="range" ng-model="vis.params.fontSize" class="form-control" min="12" max="120" />
|
||||
</div>
|
71
src/fixtures/vislib/mock_data/terms/_seriesMultiple.js
Normal file
71
src/fixtures/vislib/mock_data/terms/_seriesMultiple.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
module.exports = {
|
||||
'yAxisLabel': 'Count',
|
||||
'zAxisLabel': 'machine.os.raw: Descending',
|
||||
'yScale': null,
|
||||
'series': [{
|
||||
'label': 'ios',
|
||||
'aggLabel': 'Count',
|
||||
'aggId': '1',
|
||||
'values': [{
|
||||
'x': '_all',
|
||||
'y': 2820,
|
||||
'series': 'ios'
|
||||
}]
|
||||
}, {
|
||||
'label': 'win 7',
|
||||
'aggLabel': 'Count',
|
||||
'aggId': '1',
|
||||
'values': [{
|
||||
'x': '_all',
|
||||
'y': 2319,
|
||||
'series': 'win 7'
|
||||
}]
|
||||
}, {
|
||||
'label': 'win 8',
|
||||
'aggLabel': 'Count',
|
||||
'aggId': '1',
|
||||
'values': [{
|
||||
'x': '_all',
|
||||
'y': 1835,
|
||||
'series': 'win 8'
|
||||
}]
|
||||
}, {
|
||||
'label': 'win xp',
|
||||
'aggLabel': 'Count',
|
||||
'aggId': '1',
|
||||
'values': [{
|
||||
'x': '_all',
|
||||
'y': 734,
|
||||
'series': 'win xp'
|
||||
}]
|
||||
}, {
|
||||
'label': 'osx',
|
||||
'aggLabel': 'Count',
|
||||
'aggId': '1',
|
||||
'values': [{
|
||||
'x': '_all',
|
||||
'y': 1352,
|
||||
'series': 'osx'
|
||||
}]
|
||||
}],
|
||||
'hits': 14005,
|
||||
'xAxisFormatter': function (val) {
|
||||
if (_.isObject(val)) {
|
||||
return JSON.stringify(val);
|
||||
}
|
||||
else if (val == null) {
|
||||
return '';
|
||||
}
|
||||
else {
|
||||
return '' + val;
|
||||
}
|
||||
},
|
||||
'yAxisFormatter': function (val) {
|
||||
return val;
|
||||
},
|
||||
'tooltipFormatter': function (d) {
|
||||
return d;
|
||||
}
|
||||
};
|
|
@ -270,6 +270,10 @@
|
|||
fill: @svg-tick-text-color;
|
||||
}
|
||||
|
||||
.chart-label {
|
||||
fill: @svg-tick-text-color;
|
||||
}
|
||||
|
||||
.brush .extent {
|
||||
stroke: @svg-brush-color;
|
||||
}
|
||||
|
|
144
src/ui/public/vislib/__tests__/visualizations/gauge_chart.js
Normal file
144
src/ui/public/vislib/__tests__/visualizations/gauge_chart.js
Normal file
|
@ -0,0 +1,144 @@
|
|||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
import data from 'fixtures/vislib/mock_data/terms/_seriesMultiple';
|
||||
import FixturesVislibVisFixtureProvider from 'fixtures/vislib/_vis_fixture';
|
||||
import 'ui/persisted_state';
|
||||
|
||||
describe('Vislib Gauge Chart Test Suite', function () {
|
||||
let PersistedState;
|
||||
let vislibVis;
|
||||
let vis;
|
||||
let persistedState;
|
||||
let chartEl;
|
||||
const visLibParams = {
|
||||
type: 'gauge',
|
||||
addTooltip: true,
|
||||
addLegend: false,
|
||||
gauge: {
|
||||
verticalSplit: false,
|
||||
autoExtend: false,
|
||||
percentageMode: false,
|
||||
gaugeStyle: 'Full',
|
||||
backStyle: 'Full',
|
||||
orientation: 'vertical',
|
||||
colorSchema: 'Green to Red',
|
||||
colorsRange: [
|
||||
{ from: 0, to: 1500 },
|
||||
{ from: 1500, to: 2500 },
|
||||
{ from: 2500, to: 3000 }
|
||||
],
|
||||
invertColors: false,
|
||||
labels: {
|
||||
show: true,
|
||||
color: 'black'
|
||||
},
|
||||
scale: {
|
||||
show: true,
|
||||
labels: false,
|
||||
color: '#333',
|
||||
width: 2
|
||||
},
|
||||
type: 'meter',
|
||||
style: {
|
||||
bgWidth: 0.9,
|
||||
width: 0.9,
|
||||
mask: false,
|
||||
bgMask: false,
|
||||
maskBars: 50,
|
||||
bgFill: '#eee',
|
||||
subText: '',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function generateVis(opts = {}) {
|
||||
const config = _.defaultsDeep({}, opts, visLibParams);
|
||||
if (vis) {
|
||||
vis.destroy();
|
||||
$('.visualize-chart').remove();
|
||||
}
|
||||
vis = vislibVis(config);
|
||||
persistedState = new PersistedState();
|
||||
vis.on('brush', _.noop);
|
||||
vis.render(data, persistedState);
|
||||
chartEl = vis.handler.charts[0].chartEl;
|
||||
}
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function (Private, $injector) {
|
||||
vislibVis = Private(FixturesVislibVisFixtureProvider);
|
||||
PersistedState = $injector.get('PersistedState');
|
||||
generateVis();
|
||||
}));
|
||||
|
||||
afterEach(function () {
|
||||
vis.destroy();
|
||||
$('.visualize-chart').remove();
|
||||
});
|
||||
|
||||
it('creates meter gauge', function () {
|
||||
expect($(chartEl).find('svg').length).to.equal(5);
|
||||
expect($(chartEl).find('svg > g > g > text').text()).to.equal('2820231918357341352');
|
||||
});
|
||||
|
||||
it('creates circle gauge', function () {
|
||||
generateVis({
|
||||
gauge: {
|
||||
minAngle: 0,
|
||||
maxAngle: 2 * Math.PI
|
||||
}
|
||||
});
|
||||
expect($(chartEl).find('svg').length).to.equal(5);
|
||||
});
|
||||
|
||||
it('creates gauge with percentage mode', function () {
|
||||
generateVis({
|
||||
gauge: {
|
||||
percentageMode: true
|
||||
}
|
||||
});
|
||||
expect($(chartEl).find('svg > g > g > text').text()).to.equal('94%77%61%24%45%');
|
||||
});
|
||||
|
||||
it('creates gauge with vertical mode', function () {
|
||||
generateVis({
|
||||
gauge: {
|
||||
verticalSplit: true
|
||||
}
|
||||
});
|
||||
expect($(chartEl).find('svg').width()).to.equal($(chartEl).width());
|
||||
});
|
||||
|
||||
it('applies range settings correctly', function () {
|
||||
const paths = $(chartEl).find('svg > g > g:nth-child(1) > path:nth-child(2)');
|
||||
const fills = [];
|
||||
paths.each(function () { fills.push(this.style.fill); });
|
||||
expect(fills).to.eql([
|
||||
'rgb(165, 0, 38)',
|
||||
'rgb(255, 255, 190)',
|
||||
'rgb(255, 255, 190)',
|
||||
'rgb(0, 104, 55)',
|
||||
'rgb(0, 104, 55)'
|
||||
]);
|
||||
});
|
||||
|
||||
it('applies color schema correctly', function () {
|
||||
generateVis({
|
||||
gauge: {
|
||||
colorSchema: 'Blues'
|
||||
}
|
||||
});
|
||||
const paths = $(chartEl).find('svg > g > g:nth-child(1) > path:nth-child(2)');
|
||||
const fills = [];
|
||||
paths.each(function () { fills.push(this.style.fill); });
|
||||
expect(fills).to.eql([
|
||||
'rgb(8, 48, 107)',
|
||||
'rgb(107, 174, 214)',
|
||||
'rgb(107, 174, 214)',
|
||||
'rgb(247, 251, 255)',
|
||||
'rgb(247, 251, 255)'
|
||||
]);
|
||||
});
|
||||
});
|
|
@ -2562,3 +2562,175 @@ vislibColorMaps['Yellow to Red'] = [[0.000, [1.000, 1.000, 0.800]],
|
|||
[0.998, [0.502, 0.000, 0.149]],
|
||||
[1.000, [0.502, 0.000, 0.149]]];
|
||||
|
||||
vislibColorMaps['Green to Red'] = [
|
||||
[0, [0, 0.408, 0.216]], [0.002, [0, 0.408, 0.216]], [0.004, [0.004, 0.415, 0.22]],
|
||||
[0.006, [0.004, 0.415, 0.22]], [0.008, [0.008, 0.423, 0.223]], [0.01, [0.008, 0.423, 0.223]],
|
||||
[0.012, [0.012, 0.43, 0.227]], [0.014, [0.012, 0.43, 0.227]], [0.016, [0.016, 0.437, 0.231]],
|
||||
[0.018, [0.016, 0.437, 0.231]], [0.02, [0.02, 0.445, 0.235]], [0.022, [0.02, 0.445, 0.235]],
|
||||
[0.023, [0.024, 0.452, 0.239]], [0.025, [0.024, 0.452, 0.239]], [0.027, [0.028, 0.46, 0.243]],
|
||||
[0.029, [0.028, 0.46, 0.243]], [0.031, [0.032, 0.467, 0.246]], [0.033, [0.032, 0.467, 0.246]],
|
||||
[0.035, [0.036, 0.474, 0.25]], [0.037, [0.036, 0.474, 0.25]], [0.039, [0.04, 0.482, 0.254]],
|
||||
[0.041, [0.04, 0.482, 0.254]], [0.043, [0.044, 0.489, 0.258]], [0.045, [0.044, 0.489, 0.258]],
|
||||
[0.047, [0.048, 0.496, 0.262]], [0.049, [0.048, 0.496, 0.262]], [0.051, [0.052, 0.504, 0.266]],
|
||||
[0.053, [0.052, 0.504, 0.266]], [0.055, [0.056, 0.511, 0.27]], [0.057, [0.056, 0.511, 0.27]],
|
||||
[0.059, [0.06, 0.519, 0.273]], [0.061, [0.06, 0.519, 0.273]], [0.063, [0.064, 0.526, 0.277]],
|
||||
[0.065, [0.064, 0.526, 0.277]], [0.067, [0.068, 0.533, 0.281]], [0.068, [0.068, 0.533, 0.281]],
|
||||
[0.07, [0.072, 0.541, 0.285]], [0.072, [0.072, 0.541, 0.285]], [0.074, [0.076, 0.548, 0.289]],
|
||||
[0.076, [0.076, 0.548, 0.289]], [0.078, [0.08, 0.555, 0.293]], [0.08, [0.08, 0.555, 0.293]],
|
||||
[0.082, [0.084, 0.563, 0.296]], [0.084, [0.084, 0.563, 0.296]], [0.086, [0.088, 0.57, 0.3]],
|
||||
[0.088, [0.088, 0.57, 0.3]], [0.09, [0.092, 0.578, 0.304]], [0.092, [0.092, 0.578, 0.304]],
|
||||
[0.094, [0.096, 0.585, 0.308]], [0.096, [0.096, 0.585, 0.308]], [0.098, [0.1, 0.592, 0.312]],
|
||||
[0.1, [0.1, 0.592, 0.312]], [0.102, [0.108, 0.599, 0.315]], [0.104, [0.108, 0.599, 0.315]],
|
||||
[0.106, [0.119, 0.605, 0.318]], [0.108, [0.119, 0.605, 0.318]], [0.11, [0.131, 0.61, 0.321]],
|
||||
[0.112, [0.131, 0.61, 0.321]], [0.114, [0.143, 0.616, 0.324]], [0.115, [0.143, 0.616, 0.324]],
|
||||
[0.117, [0.155, 0.622, 0.327]], [0.119, [0.155, 0.622, 0.327]], [0.121, [0.166, 0.627, 0.33]],
|
||||
[0.123, [0.166, 0.627, 0.33]], [0.125, [0.178, 0.633, 0.333]], [0.127, [0.178, 0.633, 0.333]],
|
||||
[0.129, [0.19, 0.639, 0.336]], [0.131, [0.19, 0.639, 0.336]], [0.133, [0.201, 0.644, 0.339]],
|
||||
[0.135, [0.201, 0.644, 0.339]], [0.137, [0.213, 0.65, 0.341]], [0.139, [0.213, 0.65, 0.341]],
|
||||
[0.141, [0.225, 0.656, 0.344]], [0.143, [0.225, 0.656, 0.344]], [0.145, [0.236, 0.662, 0.347]],
|
||||
[0.147, [0.236, 0.662, 0.347]], [0.149, [0.248, 0.667, 0.35]], [0.151, [0.248, 0.667, 0.35]],
|
||||
[0.153, [0.26, 0.673, 0.353]], [0.155, [0.26, 0.673, 0.353]], [0.157, [0.271, 0.679, 0.356]],
|
||||
[0.159, [0.271, 0.679, 0.356]], [0.16, [0.283, 0.684, 0.359]], [0.162, [0.283, 0.684, 0.359]],
|
||||
[0.164, [0.295, 0.69, 0.362]], [0.166, [0.295, 0.69, 0.362]], [0.168, [0.306, 0.696, 0.365]],
|
||||
[0.17, [0.306, 0.696, 0.365]], [0.172, [0.318, 0.701, 0.368]], [0.174, [0.318, 0.701, 0.368]],
|
||||
[0.176, [0.33, 0.707, 0.371]], [0.178, [0.33, 0.707, 0.371]], [0.18, [0.342, 0.713, 0.374]],
|
||||
[0.182, [0.342, 0.713, 0.374]], [0.184, [0.353, 0.718, 0.377]], [0.186, [0.353, 0.718, 0.377]],
|
||||
[0.188, [0.365, 0.724, 0.379]], [0.19, [0.365, 0.724, 0.379]], [0.192, [0.377, 0.73, 0.382]],
|
||||
[0.194, [0.377, 0.73, 0.382]], [0.196, [0.388, 0.735, 0.385]], [0.198, [0.388, 0.735, 0.385]],
|
||||
[0.2, [0.4, 0.741, 0.388]], [0.202, [0.4, 0.741, 0.388]], [0.204, [0.41, 0.745, 0.389]],
|
||||
[0.205, [0.41, 0.745, 0.389]], [0.207, [0.42, 0.75, 0.39]], [0.209, [0.42, 0.75, 0.39]],
|
||||
[0.211, [0.43, 0.754, 0.391]], [0.213, [0.43, 0.754, 0.391]], [0.215, [0.439, 0.758, 0.393]],
|
||||
[0.217, [0.439, 0.758, 0.393]], [0.219, [0.449, 0.763, 0.394]], [0.221, [0.449, 0.763, 0.394]],
|
||||
[0.223, [0.459, 0.767, 0.395]], [0.225, [0.459, 0.767, 0.395]], [0.227, [0.469, 0.771, 0.396]],
|
||||
[0.229, [0.469, 0.771, 0.396]], [0.231, [0.479, 0.776, 0.397]], [0.233, [0.479, 0.776, 0.397]],
|
||||
[0.235, [0.489, 0.78, 0.398]], [0.237, [0.489, 0.78, 0.398]], [0.239, [0.498, 0.784, 0.399]],
|
||||
[0.241, [0.498, 0.784, 0.399]], [0.243, [0.508, 0.789, 0.4]], [0.245, [0.508, 0.789, 0.4]],
|
||||
[0.247, [0.518, 0.793, 0.401]], [0.249, [0.518, 0.793, 0.401]], [0.25, [0.528, 0.797, 0.402]],
|
||||
[0.252, [0.528, 0.797, 0.402]], [0.254, [0.538, 0.801, 0.403]], [0.256, [0.538, 0.801, 0.403]],
|
||||
[0.258, [0.548, 0.806, 0.404]], [0.26, [0.548, 0.806, 0.404]], [0.262, [0.557, 0.81, 0.405]],
|
||||
[0.264, [0.557, 0.81, 0.405]], [0.266, [0.567, 0.814, 0.407]], [0.268, [0.567, 0.814, 0.407]],
|
||||
[0.27, [0.577, 0.819, 0.408]], [0.272, [0.577, 0.819, 0.408]], [0.274, [0.587, 0.823, 0.409]],
|
||||
[0.276, [0.587, 0.823, 0.409]], [0.278, [0.597, 0.827, 0.41]], [0.28, [0.597, 0.827, 0.41]],
|
||||
[0.282, [0.607, 0.832, 0.411]], [0.284, [0.607, 0.832, 0.411]], [0.286, [0.617, 0.836, 0.412]],
|
||||
[0.288, [0.617, 0.836, 0.412]], [0.29, [0.626, 0.84, 0.413]], [0.292, [0.626, 0.84, 0.413]],
|
||||
[0.294, [0.636, 0.845, 0.414]], [0.295, [0.636, 0.845, 0.414]], [0.297, [0.646, 0.849, 0.415]],
|
||||
[0.299, [0.646, 0.849, 0.415]], [0.301, [0.655, 0.853, 0.418]], [0.303, [0.655, 0.853, 0.418]],
|
||||
[0.305, [0.663, 0.856, 0.423]], [0.307, [0.663, 0.856, 0.423]], [0.309, [0.671, 0.859, 0.428]],
|
||||
[0.311, [0.671, 0.859, 0.428]], [0.313, [0.678, 0.863, 0.433]], [0.315, [0.678, 0.863, 0.433]],
|
||||
[0.317, [0.686, 0.866, 0.439]], [0.319, [0.686, 0.866, 0.439]], [0.321, [0.694, 0.87, 0.444]],
|
||||
[0.323, [0.694, 0.87, 0.444]], [0.325, [0.702, 0.873, 0.449]], [0.327, [0.702, 0.873, 0.449]],
|
||||
[0.329, [0.71, 0.876, 0.454]], [0.331, [0.71, 0.876, 0.454]], [0.333, [0.718, 0.88, 0.459]],
|
||||
[0.335, [0.718, 0.88, 0.459]], [0.337, [0.725, 0.883, 0.464]], [0.339, [0.725, 0.883, 0.464]],
|
||||
[0.341, [0.733, 0.887, 0.469]], [0.342, [0.733, 0.887, 0.469]], [0.344, [0.741, 0.89, 0.474]],
|
||||
[0.346, [0.741, 0.89, 0.474]], [0.348, [0.749, 0.893, 0.479]], [0.35, [0.749, 0.893, 0.479]],
|
||||
[0.352, [0.757, 0.897, 0.484]], [0.354, [0.757, 0.897, 0.484]], [0.356, [0.765, 0.9, 0.489]],
|
||||
[0.358, [0.765, 0.9, 0.489]], [0.36, [0.773, 0.903, 0.494]], [0.362, [0.773, 0.903, 0.494]],
|
||||
[0.364, [0.78, 0.907, 0.499]], [0.366, [0.78, 0.907, 0.499]], [0.368, [0.788, 0.91, 0.504]],
|
||||
[0.37, [0.788, 0.91, 0.504]], [0.372, [0.796, 0.914, 0.51]], [0.374, [0.796, 0.914, 0.51]],
|
||||
[0.376, [0.804, 0.917, 0.515]], [0.378, [0.804, 0.917, 0.515]], [0.38, [0.812, 0.92, 0.52]],
|
||||
[0.382, [0.812, 0.92, 0.52]], [0.384, [0.82, 0.924, 0.525]], [0.386, [0.82, 0.924, 0.525]],
|
||||
[0.387, [0.827, 0.927, 0.53]], [0.389, [0.827, 0.927, 0.53]], [0.391, [0.835, 0.93, 0.535]],
|
||||
[0.393, [0.835, 0.93, 0.535]], [0.395, [0.843, 0.934, 0.54]], [0.397, [0.843, 0.934, 0.54]],
|
||||
[0.399, [0.851, 0.937, 0.545]], [0.401, [0.851, 0.937, 0.545]], [0.403, [0.857, 0.94, 0.553]],
|
||||
[0.405, [0.857, 0.94, 0.553]], [0.407, [0.863, 0.942, 0.561]], [0.409, [0.863, 0.942, 0.561]],
|
||||
[0.411, [0.869, 0.945, 0.569]], [0.413, [0.869, 0.945, 0.569]], [0.415, [0.874, 0.947, 0.577]],
|
||||
[0.417, [0.874, 0.947, 0.577]], [0.419, [0.88, 0.95, 0.585]], [0.421, [0.88, 0.95, 0.585]],
|
||||
[0.423, [0.886, 0.952, 0.593]], [0.425, [0.886, 0.952, 0.593]], [0.427, [0.892, 0.954, 0.601]],
|
||||
[0.429, [0.892, 0.954, 0.601]], [0.431, [0.898, 0.957, 0.609]], [0.432, [0.898, 0.957, 0.609]],
|
||||
[0.434, [0.904, 0.959, 0.617]], [0.436, [0.904, 0.959, 0.617]], [0.438, [0.909, 0.962, 0.625]],
|
||||
[0.44, [0.909, 0.962, 0.625]], [0.442, [0.915, 0.964, 0.633]], [0.444, [0.915, 0.964, 0.633]],
|
||||
[0.446, [0.921, 0.967, 0.641]], [0.448, [0.921, 0.967, 0.641]], [0.45, [0.927, 0.969, 0.649]],
|
||||
[0.452, [0.927, 0.969, 0.649]], [0.454, [0.933, 0.972, 0.657]], [0.456, [0.933, 0.972, 0.657]],
|
||||
[0.458, [0.939, 0.974, 0.665]], [0.46, [0.939, 0.974, 0.665]], [0.462, [0.944, 0.977, 0.673]],
|
||||
[0.464, [0.944, 0.977, 0.673]], [0.466, [0.95, 0.979, 0.681]], [0.468, [0.95, 0.979, 0.681]],
|
||||
[0.47, [0.956, 0.982, 0.689]], [0.472, [0.956, 0.982, 0.689]], [0.474, [0.962, 0.984, 0.697]],
|
||||
[0.476, [0.962, 0.984, 0.697]], [0.477, [0.968, 0.986, 0.705]], [0.479, [0.968, 0.986, 0.705]],
|
||||
[0.481, [0.974, 0.989, 0.713]], [0.483, [0.974, 0.989, 0.713]], [0.485, [0.98, 0.991, 0.721]],
|
||||
[0.487, [0.98, 0.991, 0.721]], [0.489, [0.985, 0.994, 0.729]], [0.491, [0.985, 0.994, 0.729]],
|
||||
[0.493, [0.991, 0.996, 0.737]], [0.495, [0.991, 0.996, 0.737]], [0.497, [0.997, 0.999, 0.745]],
|
||||
[0.499, [0.997, 0.999, 0.745]], [0.501, [1, 0.998, 0.745]], [0.503, [1, 0.998, 0.745]],
|
||||
[0.505, [1, 0.993, 0.737]], [0.507, [1, 0.993, 0.737]], [0.509, [1, 0.988, 0.729]],
|
||||
[0.511, [1, 0.988, 0.729]], [0.513, [0.999, 0.983, 0.721]], [0.515, [0.999, 0.983, 0.721]],
|
||||
[0.517, [0.999, 0.979, 0.713]], [0.519, [0.999, 0.979, 0.713]], [0.521, [0.999, 0.974, 0.705]],
|
||||
[0.523, [0.999, 0.974, 0.705]], [0.524, [0.999, 0.969, 0.697]], [0.526, [0.999, 0.969, 0.697]],
|
||||
[0.528, [0.999, 0.964, 0.689]], [0.53, [0.999, 0.964, 0.689]], [0.532, [0.999, 0.959, 0.681]],
|
||||
[0.534, [0.999, 0.959, 0.681]], [0.536, [0.999, 0.955, 0.673]], [0.538, [0.999, 0.955, 0.673]],
|
||||
[0.54, [0.998, 0.95, 0.665]], [0.542, [0.998, 0.95, 0.665]], [0.544, [0.998, 0.945, 0.657]],
|
||||
[0.546, [0.998, 0.945, 0.657]], [0.548, [0.998, 0.94, 0.649]], [0.55, [0.998, 0.94, 0.649]],
|
||||
[0.552, [0.998, 0.936, 0.641]], [0.554, [0.998, 0.936, 0.641]], [0.556, [0.998, 0.931, 0.633]],
|
||||
[0.558, [0.998, 0.931, 0.633]], [0.56, [0.998, 0.926, 0.625]], [0.562, [0.998, 0.926, 0.625]],
|
||||
[0.564, [0.997, 0.921, 0.617]], [0.566, [0.997, 0.921, 0.617]], [0.568, [0.997, 0.917, 0.609]],
|
||||
[0.569, [0.997, 0.917, 0.609]], [0.571, [0.997, 0.912, 0.601]], [0.573, [0.997, 0.912, 0.601]],
|
||||
[0.575, [0.997, 0.907, 0.593]], [0.577, [0.997, 0.907, 0.593]], [0.579, [0.997, 0.902, 0.585]],
|
||||
[0.581, [0.997, 0.902, 0.585]], [0.583, [0.997, 0.898, 0.577]], [0.585, [0.997, 0.898, 0.577]],
|
||||
[0.587, [0.997, 0.893, 0.569]], [0.589, [0.997, 0.893, 0.569]], [0.591, [0.996, 0.888, 0.561]],
|
||||
[0.593, [0.996, 0.888, 0.561]], [0.595, [0.996, 0.883, 0.553]], [0.597, [0.996, 0.883, 0.553]],
|
||||
[0.599, [0.996, 0.878, 0.545]], [0.601, [0.996, 0.878, 0.545]], [0.603, [0.996, 0.871, 0.539]],
|
||||
[0.605, [0.996, 0.871, 0.539]], [0.607, [0.996, 0.863, 0.532]], [0.609, [0.996, 0.863, 0.532]],
|
||||
[0.611, [0.996, 0.855, 0.526]], [0.613, [0.996, 0.855, 0.526]], [0.614, [0.995, 0.848, 0.519]],
|
||||
[0.616, [0.995, 0.848, 0.519]], [0.618, [0.995, 0.84, 0.513]], [0.62, [0.995, 0.84, 0.513]],
|
||||
[0.622, [0.995, 0.832, 0.506]], [0.624, [0.995, 0.832, 0.506]], [0.626, [0.995, 0.825, 0.5]],
|
||||
[0.628, [0.995, 0.825, 0.5]], [0.63, [0.995, 0.817, 0.493]], [0.632, [0.995, 0.817, 0.493]],
|
||||
[0.634, [0.995, 0.809, 0.487]], [0.636, [0.995, 0.809, 0.487]],
|
||||
[0.638, [0.995, 0.802, 0.481]], [0.64, [0.995, 0.802, 0.481]], [0.642, [0.994, 0.794, 0.474]],
|
||||
[0.644, [0.994, 0.794, 0.474]], [0.646, [0.994, 0.786, 0.468]], [0.648, [0.994, 0.786, 0.468]],
|
||||
[0.65, [0.994, 0.778, 0.461]], [0.652, [0.994, 0.778, 0.461]], [0.654, [0.994, 0.771, 0.455]],
|
||||
[0.656, [0.994, 0.771, 0.455]], [0.658, [0.994, 0.763, 0.448]], [0.659, [0.994, 0.763, 0.448]],
|
||||
[0.661, [0.994, 0.755, 0.442]], [0.663, [0.994, 0.755, 0.442]], [0.665, [0.993, 0.748, 0.435]],
|
||||
[0.667, [0.993, 0.748, 0.435]], [0.669, [0.993, 0.74, 0.429]], [0.671, [0.993, 0.74, 0.429]],
|
||||
[0.673, [0.993, 0.732, 0.422]], [0.675, [0.993, 0.732, 0.422]], [0.677, [0.993, 0.725, 0.416]],
|
||||
[0.679, [0.993, 0.725, 0.416]], [0.681, [0.993, 0.717, 0.409]], [0.683, [0.993, 0.717, 0.409]],
|
||||
[0.685, [0.993, 0.709, 0.403]], [0.687, [0.993, 0.709, 0.403]], [0.689, [0.993, 0.702, 0.397]],
|
||||
[0.691, [0.993, 0.702, 0.397]], [0.693, [0.992, 0.694, 0.39]], [0.695, [0.992, 0.694, 0.39]],
|
||||
[0.697, [0.992, 0.686, 0.384]], [0.699, [0.992, 0.686, 0.384]], [0.701, [0.991, 0.677, 0.378]],
|
||||
[0.703, [0.991, 0.677, 0.378]], [0.705, [0.99, 0.667, 0.373]], [0.706, [0.99, 0.667, 0.373]],
|
||||
[0.708, [0.989, 0.657, 0.369]], [0.71, [0.989, 0.657, 0.369]], [0.712, [0.987, 0.647, 0.364]],
|
||||
[0.714, [0.987, 0.647, 0.364]], [0.716, [0.986, 0.637, 0.36]], [0.718, [0.986, 0.637, 0.36]],
|
||||
[0.72, [0.985, 0.627, 0.355]], [0.722, [0.985, 0.627, 0.355]], [0.724, [0.983, 0.617, 0.35]],
|
||||
[0.726, [0.983, 0.617, 0.35]], [0.728, [0.982, 0.607, 0.346]], [0.73, [0.982, 0.607, 0.346]],
|
||||
[0.732, [0.98, 0.597, 0.341]], [0.734, [0.98, 0.597, 0.341]], [0.736, [0.979, 0.587, 0.337]],
|
||||
[0.738, [0.979, 0.587, 0.337]], [0.74, [0.978, 0.577, 0.332]], [0.742, [0.978, 0.577, 0.332]],
|
||||
[0.744, [0.976, 0.567, 0.327]], [0.746, [0.976, 0.567, 0.327]], [0.748, [0.975, 0.557, 0.323]],
|
||||
[0.75, [0.975, 0.557, 0.323]], [0.751, [0.973, 0.547, 0.318]], [0.753, [0.973, 0.547, 0.318]],
|
||||
[0.755, [0.972, 0.537, 0.313]], [0.757, [0.972, 0.537, 0.313]], [0.759, [0.971, 0.527, 0.309]],
|
||||
[0.761, [0.971, 0.527, 0.309]], [0.763, [0.969, 0.517, 0.304]], [0.765, [0.969, 0.517, 0.304]],
|
||||
[0.767, [0.968, 0.507, 0.3]], [0.769, [0.968, 0.507, 0.3]], [0.771, [0.967, 0.497, 0.295]],
|
||||
[0.773, [0.967, 0.497, 0.295]], [0.775, [0.965, 0.487, 0.29]], [0.777, [0.965, 0.487, 0.29]],
|
||||
[0.779, [0.964, 0.477, 0.286]], [0.781, [0.964, 0.477, 0.286]], [0.783, [0.962, 0.467, 0.281]],
|
||||
[0.785, [0.962, 0.467, 0.281]], [0.787, [0.961, 0.457, 0.277]], [0.789, [0.961, 0.457, 0.277]],
|
||||
[0.791, [0.96, 0.447, 0.272]], [0.793, [0.96, 0.447, 0.272]], [0.795, [0.958, 0.437, 0.267]],
|
||||
[0.796, [0.958, 0.437, 0.267]], [0.798, [0.957, 0.427, 0.263]], [0.8, [0.957, 0.427, 0.263]],
|
||||
[0.802, [0.952, 0.418, 0.258]], [0.804, [0.952, 0.418, 0.258]], [0.806, [0.948, 0.409, 0.254]],
|
||||
[0.808, [0.948, 0.409, 0.254]], [0.81, [0.943, 0.399, 0.25]], [0.812, [0.943, 0.399, 0.25]],
|
||||
[0.814, [0.939, 0.39, 0.246]], [0.816, [0.939, 0.39, 0.246]], [0.818, [0.935, 0.381, 0.241]],
|
||||
[0.82, [0.935, 0.381, 0.241]], [0.822, [0.93, 0.371, 0.237]], [0.824, [0.93, 0.371, 0.237]],
|
||||
[0.826, [0.926, 0.362, 0.233]], [0.828, [0.926, 0.362, 0.233]], [0.83, [0.921, 0.352, 0.228]],
|
||||
[0.832, [0.921, 0.352, 0.228]], [0.834, [0.917, 0.343, 0.224]], [0.836, [0.917, 0.343, 0.224]],
|
||||
[0.838, [0.912, 0.334, 0.22]], [0.84, [0.912, 0.334, 0.22]], [0.841, [0.908, 0.324, 0.215]],
|
||||
[0.843, [0.908, 0.324, 0.215]], [0.845, [0.903, 0.315, 0.211]], [0.847, [0.903, 0.315, 0.211]],
|
||||
[0.849, [0.899, 0.305, 0.207]], [0.851, [0.899, 0.305, 0.207]], [0.853, [0.894, 0.296, 0.202]],
|
||||
[0.855, [0.894, 0.296, 0.202]], [0.857, [0.89, 0.287, 0.198]], [0.859, [0.89, 0.287, 0.198]],
|
||||
[0.861, [0.886, 0.277, 0.194]], [0.863, [0.886, 0.277, 0.194]], [0.865, [0.881, 0.268, 0.19]],
|
||||
[0.867, [0.881, 0.268, 0.19]], [0.869, [0.877, 0.259, 0.185]], [0.871, [0.877, 0.259, 0.185]],
|
||||
[0.873, [0.872, 0.249, 0.181]], [0.875, [0.872, 0.249, 0.181]], [0.877, [0.868, 0.24, 0.177]],
|
||||
[0.879, [0.868, 0.24, 0.177]], [0.881, [0.863, 0.23, 0.172]], [0.883, [0.863, 0.23, 0.172]],
|
||||
[0.885, [0.859, 0.221, 0.168]], [0.886, [0.859, 0.221, 0.168]], [0.888, [0.854, 0.212, 0.164]],
|
||||
[0.89, [0.854, 0.212, 0.164]], [0.892, [0.85, 0.202, 0.159]], [0.894, [0.85, 0.202, 0.159]],
|
||||
[0.896, [0.845, 0.193, 0.155]], [0.898, [0.845, 0.193, 0.155]], [0.9, [0.839, 0.185, 0.153]],
|
||||
[0.902, [0.839, 0.185, 0.153]], [0.904, [0.832, 0.177, 0.153]], [0.906, [0.832, 0.177, 0.153]],
|
||||
[0.908, [0.824, 0.17, 0.153]], [0.91, [0.824, 0.17, 0.153]], [0.912, [0.816, 0.162, 0.152]],
|
||||
[0.914, [0.816, 0.162, 0.152]], [0.916, [0.809, 0.155, 0.152]], [0.918, [0.809, 0.155, 0.152]],
|
||||
[0.92, [0.801, 0.148, 0.152]], [0.922, [0.801, 0.148, 0.152]], [0.924, [0.793, 0.14, 0.152]],
|
||||
[0.926, [0.793, 0.14, 0.152]], [0.928, [0.785, 0.133, 0.152]], [0.93, [0.785, 0.133, 0.152]],
|
||||
[0.932, [0.778, 0.125, 0.152]], [0.933, [0.778, 0.125, 0.152]], [0.935, [0.77, 0.118, 0.151]],
|
||||
[0.937, [0.77, 0.118, 0.151]], [0.939, [0.762, 0.111, 0.151]], [0.941, [0.762, 0.111, 0.151]],
|
||||
[0.943, [0.755, 0.103, 0.151]], [0.945, [0.755, 0.103, 0.151]], [0.947, [0.747, 0.096, 0.151]],
|
||||
[0.949, [0.747, 0.096, 0.151]], [0.951, [0.739, 0.089, 0.151]], [0.953, [0.739, 0.089, 0.151]],
|
||||
[0.955, [0.732, 0.081, 0.151]], [0.957, [0.732, 0.081, 0.151]], [0.959, [0.724, 0.074, 0.151]],
|
||||
[0.961, [0.724, 0.074, 0.151]], [0.963, [0.716, 0.066, 0.15]], [0.965, [0.716, 0.066, 0.15]],
|
||||
[0.967, [0.709, 0.059, 0.15]], [0.969, [0.709, 0.059, 0.15]], [0.971, [0.701, 0.052, 0.15]],
|
||||
[0.973, [0.701, 0.052, 0.15]], [0.975, [0.693, 0.044, 0.15]], [0.977, [0.693, 0.044, 0.15]],
|
||||
[0.978, [0.686, 0.037, 0.15]], [0.98, [0.686, 0.037, 0.15]], [0.982, [0.678, 0.03, 0.15]],
|
||||
[0.984, [0.678, 0.03, 0.15]], [0.986, [0.67, 0.022, 0.149]], [0.988, [0.67, 0.022, 0.149]],
|
||||
[0.99, [0.662, 0.015, 0.149]], [0.992, [0.662, 0.015, 0.149]], [0.994, [0.655, 0.007, 0.149]],
|
||||
[0.996, [0.655, 0.007, 0.149]], [0.998, [0.647, 0, 0.149]], [1, [0.647, 0, 0.149]]];
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { VislibLibLayoutTypesColumnLayoutProvider } from './types/column_layout';
|
||||
import { VislibLibLayoutTypesPieLayoutProvider } from './types/pie_layout';
|
||||
import { GaugeLayoutProvider } from './types/gauge_layout';
|
||||
|
||||
export function VislibLibLayoutLayoutTypesProvider(Private) {
|
||||
|
||||
|
@ -13,6 +14,7 @@ export function VislibLibLayoutLayoutTypesProvider(Private) {
|
|||
*/
|
||||
return {
|
||||
pie: Private(VislibLibLayoutTypesPieLayoutProvider),
|
||||
gauge: Private(GaugeLayoutProvider),
|
||||
point_series: Private(VislibLibLayoutTypesColumnLayoutProvider)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import d3 from 'd3';
|
||||
define(function () {
|
||||
return function ChartSplitFactory() {
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
const div = d3.select(this)
|
||||
.attr('class', function () {
|
||||
if (data.rows) {
|
||||
return 'chart-wrapper-row';
|
||||
} else if (data.columns) {
|
||||
return 'chart-wrapper-column';
|
||||
} else {
|
||||
return 'chart-wrapper';
|
||||
}
|
||||
});
|
||||
let divClass;
|
||||
|
||||
const charts = div.selectAll('charts')
|
||||
.append('div')
|
||||
.data(function (d) {
|
||||
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.series) {
|
||||
charts.call(split);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
import d3 from 'd3';
|
||||
define(function () {
|
||||
return function ChartTitleSplitFactory() {
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* if not data.rows or data.columns, return no chart titles
|
||||
*/
|
||||
|
||||
return function (selection, parent) {
|
||||
selection.each(function (data) {
|
||||
const 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) {
|
||||
d3.select(parent).select('.x-axis-chart-title').remove();
|
||||
} else {
|
||||
d3.select(parent).select('.y-axis-chart-title').remove();
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
return d3.select(this).remove();
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
65
src/ui/public/vislib/lib/layout/types/gauge_layout.js
Normal file
65
src/ui/public/vislib/lib/layout/types/gauge_layout.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
import GaugeChartSplitProvider from '../splits/gauge_chart/chart_split';
|
||||
//import VislibLibLayoutSplitsPieChartChartTitleSplitProvider from '../splits/gauge_chart/chart_title_split';
|
||||
export function GaugeLayoutProvider(Private) {
|
||||
const chartSplit = Private(GaugeChartSplitProvider);
|
||||
//const chartTitleSplit = Private(VislibLibLayoutSplitsPieChartChartTitleSplitProvider);
|
||||
|
||||
/**
|
||||
* 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: 'vis-alerts'
|
||||
},
|
||||
{
|
||||
type: 'div',
|
||||
class: 'x-axis-chart-title',
|
||||
//splits: chartTitleSplit
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
14
src/ui/public/vislib/lib/types/gauge.js
Normal file
14
src/ui/public/vislib/lib/types/gauge.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
export function vislibGaugeProvider() {
|
||||
|
||||
return function (config) {
|
||||
if (!config.chart) {
|
||||
config.chart = _.defaults({}, config, {
|
||||
type: 'gauge'
|
||||
});
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import { VislibTypesPointSeries } from './point_series';
|
||||
import { VislibPieConfigProvider } from './pie';
|
||||
import { vislibGaugeProvider } from './gauge';
|
||||
|
||||
export function VislibTypesProvider(Private) {
|
||||
const pointSeries = Private(VislibTypesPointSeries);
|
||||
|
@ -17,5 +18,6 @@ export function VislibTypesProvider(Private) {
|
|||
area: pointSeries.area,
|
||||
point_series: pointSeries.line,
|
||||
heatmap: pointSeries.heatmap,
|
||||
gauge: Private(vislibGaugeProvider)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
fill: @svg-tick-text-color;
|
||||
}
|
||||
|
||||
.chart-text {
|
||||
fill: @svg-tick-text-color;
|
||||
}
|
||||
|
||||
/* Brush Styling */
|
||||
.brush .extent {
|
||||
stroke: @svg-brush-color;
|
||||
|
|
71
src/ui/public/vislib/visualizations/gauge_chart.js
Normal file
71
src/ui/public/vislib/visualizations/gauge_chart.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
import d3 from 'd3';
|
||||
import $ from 'jquery';
|
||||
import { VislibVisualizationsChartProvider } from './_chart';
|
||||
import { GaugeTypesProvider } from './gauges/gauge_types';
|
||||
|
||||
export function GaugeChartProvider(Private) {
|
||||
|
||||
const Chart = Private(VislibVisualizationsChartProvider);
|
||||
const gaugeTypes = Private(GaugeTypesProvider);
|
||||
|
||||
class GaugeChart extends Chart {
|
||||
constructor(handler, chartEl, chartData) {
|
||||
super(handler, chartEl, chartData);
|
||||
this.gaugeConfig = handler.visConfig.get('gauge', {});
|
||||
this.gauge = new gaugeTypes[this.gaugeConfig.type](this);
|
||||
}
|
||||
|
||||
addEvents(element) {
|
||||
const events = this.events;
|
||||
|
||||
return element
|
||||
.call(events.addHoverEvent())
|
||||
.call(events.addMouseoutEvent())
|
||||
.call(events.addClickEvent());
|
||||
}
|
||||
|
||||
draw() {
|
||||
const self = this;
|
||||
const verticalSplit = this.gaugeConfig.verticalSplit;
|
||||
|
||||
return function (selection) {
|
||||
selection.each(function (data) {
|
||||
const div = d3.select(this);
|
||||
const width = verticalSplit ? $(this).width() : $(this).width() / data.series.length;
|
||||
const height = (verticalSplit ? $(this).height() / data.series.length : $(this).height()) - 25;
|
||||
const transformX = width / 2;
|
||||
const transformY = self.gaugeConfig.gaugeType === 'Meter' ? height / 1.5 : height / 2;
|
||||
|
||||
|
||||
|
||||
data.series.forEach(series => {
|
||||
const svg = div.append('svg')
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
.style('display', 'inline-block')
|
||||
.style('overflow', 'hidden');
|
||||
|
||||
const g = svg.append('g')
|
||||
.attr('transform', `translate(${transformX}, ${transformY})`);
|
||||
|
||||
const gauges = self.gauge.drawGauge(g, series, width, height);
|
||||
self.addEvents(gauges);
|
||||
});
|
||||
|
||||
div.append('div')
|
||||
.attr('class', 'chart-title')
|
||||
.style('text-align', 'center')
|
||||
.text(data.label || data.yAxisLabel);
|
||||
|
||||
self.events.emit('rendered', {
|
||||
chart: data
|
||||
});
|
||||
|
||||
return div;
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return GaugeChart;
|
||||
}
|
10
src/ui/public/vislib/visualizations/gauges/gauge_types.js
Normal file
10
src/ui/public/vislib/visualizations/gauges/gauge_types.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { MeterGaugeProvider } from './meter';
|
||||
import { SimpleGaugeProvider } from './simple';
|
||||
|
||||
export function GaugeTypesProvider(Private) {
|
||||
|
||||
return {
|
||||
meter: Private(MeterGaugeProvider),
|
||||
simple: Private(SimpleGaugeProvider),
|
||||
};
|
||||
}
|
300
src/ui/public/vislib/visualizations/gauges/meter.js
Normal file
300
src/ui/public/vislib/visualizations/gauges/meter.js
Normal file
|
@ -0,0 +1,300 @@
|
|||
import d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import { getHeatmapColors } from 'ui/vislib/components/color/heatmap_color';
|
||||
|
||||
export function MeterGaugeProvider() {
|
||||
|
||||
|
||||
const defaultConfig = {
|
||||
showTooltip: true,
|
||||
percentageMode: true,
|
||||
maxAngle: 2 * Math.PI * 1.3,
|
||||
minAngle: 2 * Math.PI * 0.7,
|
||||
innerSpace: 5,
|
||||
extents: [0, 10000],
|
||||
scale: {
|
||||
show: true,
|
||||
color: '#666',
|
||||
width: 2,
|
||||
ticks: 10,
|
||||
tickLength: 8,
|
||||
},
|
||||
labels: {
|
||||
show: true,
|
||||
color: '#666'
|
||||
},
|
||||
style: {
|
||||
bgWidth: 0.5,
|
||||
width: 0.9
|
||||
}
|
||||
};
|
||||
|
||||
class MeterGauge {
|
||||
constructor(gaugeChart) {
|
||||
this.gaugeChart = gaugeChart;
|
||||
this.gaugeConfig = gaugeChart.gaugeConfig;
|
||||
this.gaugeConfig = _.defaultsDeep(this.gaugeConfig, defaultConfig);
|
||||
|
||||
this.gaugeChart.handler.visConfig.set('legend', {
|
||||
labels: this.getLabels(),
|
||||
colors: this.getColors()
|
||||
});
|
||||
|
||||
const colors = this.gaugeChart.handler.visConfig.get('legend.colors', null);
|
||||
if (colors) {
|
||||
this.gaugeChart.handler.vis.uiState.setSilent('vis.defaultColors', null);
|
||||
this.gaugeChart.handler.vis.uiState.setSilent('vis.defaultColors', colors);
|
||||
}
|
||||
|
||||
this.colorFunc = this.gaugeChart.handler.data.getColorFunc();
|
||||
}
|
||||
|
||||
getLabels() {
|
||||
const isPercentageMode = this.gaugeConfig.percentageMode;
|
||||
const colorsRange = this.gaugeConfig.colorsRange;
|
||||
const max = _.last(colorsRange).to;
|
||||
const labels = [];
|
||||
colorsRange.forEach(range => {
|
||||
const from = isPercentageMode ? Math.round(100 * range.from / max) : range.from;
|
||||
const to = isPercentageMode ? Math.round(100 * range.to / max) : range.to;
|
||||
labels.push(`${from} - ${to}`);
|
||||
});
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
getColors() {
|
||||
const invertColors = this.gaugeConfig.invertColors;
|
||||
const colorSchema = this.gaugeConfig.colorSchema;
|
||||
const colorsRange = this.gaugeConfig.colorsRange;
|
||||
const labels = this.getLabels();
|
||||
const colors = {};
|
||||
for (let i = 0; i < labels.length; i += 1) {
|
||||
const divider = Math.max(colorsRange.length - 1, 1);
|
||||
const val = invertColors ? 1 - i / divider : i / divider;
|
||||
colors[labels[i]] = getHeatmapColors(val, colorSchema);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
getBucket(val) {
|
||||
let bucket = _.findIndex(this.gaugeConfig.colorsRange, range => {
|
||||
return range.from <= val && range.to > val;
|
||||
});
|
||||
|
||||
if (bucket === -1) {
|
||||
if (val < this.gaugeConfig.colorsRange[0].from) bucket = 0;
|
||||
else bucket = this.gaugeConfig.colorsRange.length - 1;
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
getLabel(val) {
|
||||
const bucket = this.getBucket(val);
|
||||
const labels = this.gaugeChart.handler.visConfig.get('legend.labels');
|
||||
return labels[bucket];
|
||||
}
|
||||
|
||||
getColorBucket(val) {
|
||||
const bucket = this.getBucket(val);
|
||||
const labels = this.gaugeChart.handler.visConfig.get('legend.labels');
|
||||
return this.colorFunc(labels[bucket]);
|
||||
}
|
||||
|
||||
drawScale(svg, radius, angle) {
|
||||
const scaleWidth = this.gaugeConfig.scale.width;
|
||||
const tickLength = this.gaugeConfig.scale.tickLength;
|
||||
const scaleTicks = this.gaugeConfig.scale.ticks;
|
||||
|
||||
const scale = svg.append('g');
|
||||
|
||||
this.gaugeConfig.colorsRange.forEach(range => {
|
||||
const color = this.getColorBucket(range.from);
|
||||
|
||||
const scaleArc = d3.svg.arc()
|
||||
.startAngle(angle(range.from))
|
||||
.endAngle(angle(range.to))
|
||||
.innerRadius(radius)
|
||||
.outerRadius(radius + scaleWidth);
|
||||
|
||||
scale
|
||||
.append('path')
|
||||
.attr('d', scaleArc)
|
||||
.style('stroke', color)
|
||||
.style('fill', color);
|
||||
});
|
||||
|
||||
|
||||
const extents = angle.domain();
|
||||
for (let i = 0; i <= scaleTicks; i++) {
|
||||
const val = i * (extents[1] - extents[0]) / scaleTicks;
|
||||
const tickAngle = angle(val) - Math.PI / 2;
|
||||
const x0 = Math.cos(tickAngle) * radius;
|
||||
const x1 = Math.cos(tickAngle) * (radius - tickLength);
|
||||
const y0 = Math.sin(tickAngle) * radius;
|
||||
const y1 = Math.sin(tickAngle) * (radius - tickLength);
|
||||
const color = this.getColorBucket(val);
|
||||
scale.append('line')
|
||||
.attr('x1', x0).attr('x2', x1)
|
||||
.attr('y1', y0).attr('y2', y1)
|
||||
.style('stroke-width', scaleWidth)
|
||||
.style('stroke', color);
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
drawGauge(svg, data, width, height) {
|
||||
const marginFactor = 0.95;
|
||||
const tooltip = this.gaugeChart.tooltip;
|
||||
const isTooltip = this.gaugeChart.handler.visConfig.get('addTooltip');
|
||||
const maxAngle = this.gaugeConfig.maxAngle;
|
||||
const minAngle = this.gaugeConfig.minAngle;
|
||||
const angleFactor = this.gaugeConfig.gaugeType === 'Meter' ? 0.75 : 1;
|
||||
const maxRadius = (Math.min(width, height / angleFactor) / 2) * marginFactor;
|
||||
const yFieldFormatter = this.gaugeChart.handler.data.get('yAxisFormatter');
|
||||
|
||||
const extendRange = this.gaugeConfig.extendRange;
|
||||
const maxY = _.max(data.values, 'y').y;
|
||||
const min = this.gaugeConfig.colorsRange[0].from;
|
||||
const max = _.last(this.gaugeConfig.colorsRange).to;
|
||||
const angle = d3.scale.linear()
|
||||
.range([minAngle, maxAngle])
|
||||
.domain([min, extendRange && max < maxY ? maxY : max]);
|
||||
const radius = d3.scale.linear()
|
||||
.range([0, maxRadius])
|
||||
.domain([this.gaugeConfig.innerSpace + 1, 0]);
|
||||
|
||||
const totalWidth = Math.abs(radius(0) - radius(1));
|
||||
const bgPadding = totalWidth * (1 - this.gaugeConfig.style.bgWidth) / 2;
|
||||
const gaugePadding = totalWidth * (1 - this.gaugeConfig.style.width) / 2;
|
||||
const arc = d3.svg.arc()
|
||||
.startAngle(minAngle)
|
||||
.endAngle(function (d) {
|
||||
return Math.max(0, Math.min(maxAngle, angle(d.y)));
|
||||
})
|
||||
.innerRadius(function (d, i, j) {
|
||||
return Math.max(0, radius(j + 1) + gaugePadding);
|
||||
})
|
||||
.outerRadius(function (d, i, j) {
|
||||
return Math.max(0, radius(j) - gaugePadding);
|
||||
});
|
||||
|
||||
|
||||
const bgArc = d3.svg.arc()
|
||||
.startAngle(minAngle)
|
||||
.endAngle(maxAngle)
|
||||
.innerRadius(function (d, i, j) {
|
||||
return Math.max(0, radius(j + 1) + bgPadding);
|
||||
})
|
||||
.outerRadius(function (d, i, j) {
|
||||
return Math.max(0, radius(j) - bgPadding);
|
||||
});
|
||||
|
||||
const gaugeHolders = svg
|
||||
.selectAll('path')
|
||||
.data([data])
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('data-label', (d) => this.getLabel(d.values[0].y));
|
||||
|
||||
|
||||
const gauges = gaugeHolders
|
||||
.selectAll('g')
|
||||
.data(d => d.values)
|
||||
.enter();
|
||||
|
||||
|
||||
gauges
|
||||
.append('path')
|
||||
.attr('d', bgArc)
|
||||
.style('fill', this.gaugeConfig.style.bgFill);
|
||||
|
||||
const self = this;
|
||||
const series = gauges
|
||||
.append('path')
|
||||
.attr('d', arc)
|
||||
.style('fill', function (d) {
|
||||
return self.getColorBucket(d.y);
|
||||
});
|
||||
|
||||
const smallContainer = svg.node().getBBox().height < 70;
|
||||
let hiddenLabels = smallContainer;
|
||||
|
||||
if (this.gaugeConfig.labels.show) {
|
||||
svg
|
||||
.append('text')
|
||||
.attr('class', 'chart-label')
|
||||
.text(data.label)
|
||||
.attr('y', -30)
|
||||
.attr('style', 'dominant-baseline: central; text-anchor: middle;')
|
||||
.style('display', function () {
|
||||
const textLength = this.getBBox().width;
|
||||
const textTooLong = textLength > maxRadius;
|
||||
if (textTooLong) {
|
||||
hiddenLabels = true;
|
||||
}
|
||||
return smallContainer || textTooLong ? 'none' : 'initial';
|
||||
});
|
||||
|
||||
svg
|
||||
.append('text')
|
||||
.attr('class', 'chart-label')
|
||||
.text(this.gaugeConfig.style.subText)
|
||||
.attr('y', 20)
|
||||
.attr('style', 'dominant-baseline: central; text-anchor: middle;')
|
||||
.style('display', function () {
|
||||
const textLength = this.getBBox().width;
|
||||
const textTooLong = textLength > maxRadius;
|
||||
if (textTooLong) {
|
||||
hiddenLabels = true;
|
||||
}
|
||||
return smallContainer || textTooLong ? 'none' : 'initial';
|
||||
});
|
||||
|
||||
gauges
|
||||
.append('text')
|
||||
.attr('class', 'chart-label')
|
||||
.attr('y', -5)
|
||||
.text(d => {
|
||||
if (this.gaugeConfig.percentageMode) {
|
||||
const percentage = Math.round(100 * (d.y - min) / (max - min));
|
||||
return `${percentage}%`;
|
||||
}
|
||||
return yFieldFormatter(d.y);
|
||||
})
|
||||
.attr('style', 'dominant-baseline: central;')
|
||||
.style('text-anchor', 'middle')
|
||||
.style('font-size', '2em')
|
||||
.style('display', function () {
|
||||
const textLength = this.getBBox().width;
|
||||
const textTooLong = textLength > maxRadius;
|
||||
if (textTooLong) {
|
||||
hiddenLabels = true;
|
||||
}
|
||||
return textTooLong ? 'none' : 'initial';
|
||||
});
|
||||
}
|
||||
|
||||
if (this.gaugeConfig.scale.show) {
|
||||
this.drawScale(svg, radius(1), angle);
|
||||
}
|
||||
|
||||
if (isTooltip) {
|
||||
series.each(function () {
|
||||
const gauge = d3.select(this);
|
||||
gauge.call(tooltip.render());
|
||||
});
|
||||
}
|
||||
|
||||
if (hiddenLabels) {
|
||||
this.gaugeChart.handler.alerts.show('Some labels were hidden due to size constrains');
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
}
|
||||
|
||||
return MeterGauge;
|
||||
}
|
207
src/ui/public/vislib/visualizations/gauges/simple.js
Normal file
207
src/ui/public/vislib/visualizations/gauges/simple.js
Normal file
|
@ -0,0 +1,207 @@
|
|||
import d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import { getHeatmapColors } from 'ui/vislib/components/color/heatmap_color';
|
||||
|
||||
export function SimpleGaugeProvider() {
|
||||
|
||||
|
||||
const defaultConfig = {
|
||||
showTooltip: true,
|
||||
percentageMode: true,
|
||||
extents: [0, 10000],
|
||||
scale: {
|
||||
show: true,
|
||||
color: '#666',
|
||||
width: 2,
|
||||
ticks: 10,
|
||||
tickLength: 5,
|
||||
},
|
||||
labels: {
|
||||
show: true,
|
||||
color: '#666'
|
||||
},
|
||||
style: {
|
||||
bgColor: true,
|
||||
bgFill: '#666'
|
||||
}
|
||||
};
|
||||
|
||||
class SimpleGauge {
|
||||
constructor(gaugeChart) {
|
||||
this.gaugeChart = gaugeChart;
|
||||
this.gaugeConfig = gaugeChart.gaugeConfig;
|
||||
this.gaugeConfig = _.defaultsDeep(this.gaugeConfig, defaultConfig);
|
||||
this.randomNumber = Math.round(Math.random() * 100000);
|
||||
|
||||
this.gaugeChart.handler.visConfig.set('legend', {
|
||||
labels: this.getLabels(),
|
||||
colors: this.getColors()
|
||||
});
|
||||
|
||||
const colors = this.gaugeChart.handler.visConfig.get('legend.colors', null);
|
||||
if (colors) {
|
||||
this.gaugeChart.handler.vis.uiState.setSilent('vis.defaultColors', null);
|
||||
this.gaugeChart.handler.vis.uiState.setSilent('vis.defaultColors', colors);
|
||||
}
|
||||
|
||||
this.colorFunc = this.gaugeChart.handler.data.getColorFunc();
|
||||
}
|
||||
|
||||
getLabels() {
|
||||
const isPercentageMode = this.gaugeConfig.percentageMode;
|
||||
const colorsRange = this.gaugeConfig.colorsRange;
|
||||
const max = _.last(colorsRange).to;
|
||||
const labels = [];
|
||||
colorsRange.forEach(range => {
|
||||
const from = isPercentageMode ? Math.round(100 * range.from / max) : range.from;
|
||||
const to = isPercentageMode ? Math.round(100 * range.to / max) : range.to;
|
||||
labels.push(`${from} - ${to}`);
|
||||
});
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
getColors() {
|
||||
const invertColors = this.gaugeConfig.invertColors;
|
||||
const colorSchema = this.gaugeConfig.colorSchema;
|
||||
const colorsRange = this.gaugeConfig.colorsRange;
|
||||
const labels = this.getLabels();
|
||||
const colors = {};
|
||||
for (let i = 0; i < labels.length; i += 1) {
|
||||
const divider = Math.max(colorsRange.length - 1, 1);
|
||||
const val = invertColors ? 1 - i / divider : i / divider;
|
||||
colors[labels[i]] = getHeatmapColors(val, colorSchema);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
getBucket(val) {
|
||||
let bucket = _.findIndex(this.gaugeConfig.colorsRange, range => {
|
||||
return range.from <= val && range.to > val;
|
||||
});
|
||||
|
||||
if (bucket === -1) {
|
||||
if (val < this.gaugeConfig.colorsRange[0].from) bucket = 0;
|
||||
else bucket = this.gaugeConfig.colorsRange.length - 1;
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
getLabel(val) {
|
||||
const bucket = this.getBucket(val);
|
||||
const labels = this.gaugeChart.handler.visConfig.get('legend.labels');
|
||||
return labels[bucket];
|
||||
}
|
||||
|
||||
getColorBucket(val) {
|
||||
const bucket = this.getBucket(val);
|
||||
const labels = this.gaugeChart.handler.visConfig.get('legend.labels');
|
||||
return this.colorFunc(labels[bucket]);
|
||||
}
|
||||
|
||||
drawGauge(svg, data, width) {
|
||||
const tooltip = this.gaugeChart.tooltip;
|
||||
const isTooltip = this.gaugeChart.handler.visConfig.get('addTooltip');
|
||||
const yFieldFormatter = this.gaugeChart.handler.data.get('yAxisFormatter');
|
||||
const fontSize = this.gaugeChart.handler.visConfig.get('gauge.style.fontSize');
|
||||
|
||||
const labelColor = this.gaugeConfig.style.labelColor;
|
||||
const bgColor = this.gaugeConfig.style.bgColor;
|
||||
const bgFill = this.gaugeConfig.style.bgFill;
|
||||
const min = this.gaugeConfig.colorsRange[0].from;
|
||||
const max = _.last(this.gaugeConfig.colorsRange).to;
|
||||
|
||||
const gaugeHolders = svg
|
||||
.selectAll('path')
|
||||
.data([data])
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('data-label', (d) => this.getLabel(d.values[0].y));
|
||||
|
||||
|
||||
const gauges = gaugeHolders
|
||||
.selectAll('g')
|
||||
.data(d => d.values)
|
||||
.enter();
|
||||
|
||||
|
||||
const self = this;
|
||||
const series = gauges
|
||||
.append('rect')
|
||||
.attr('x', '-50%')
|
||||
.attr('y', '-50%')
|
||||
.attr('width', '99%')
|
||||
.attr('height', '99%')
|
||||
.style('fill', function (d) {
|
||||
return bgColor ? self.getColorBucket(d.y) : 'transparent';
|
||||
});
|
||||
|
||||
const smallContainer = svg.node().getBBox().height < 70;
|
||||
let hiddenLabels = smallContainer;
|
||||
|
||||
const isTextTooLong = function () {
|
||||
const textLength = this.getBBox().width;
|
||||
const textTooLong = textLength > width;
|
||||
if (textTooLong) {
|
||||
hiddenLabels = true;
|
||||
}
|
||||
return smallContainer || textTooLong ? 'none' : 'initial';
|
||||
};
|
||||
|
||||
|
||||
if (this.gaugeConfig.labels.show) {
|
||||
svg
|
||||
.append('text')
|
||||
.attr('class', 'chart-label')
|
||||
.text(data.label)
|
||||
.attr('y', Math.min(-25, -fontSize))
|
||||
.attr('style', 'dominant-baseline: central; text-anchor: middle;')
|
||||
.style('display', isTextTooLong)
|
||||
.style('fill', bgFill);
|
||||
|
||||
svg
|
||||
.append('text')
|
||||
.attr('class', 'chart-label')
|
||||
.text(this.gaugeConfig.style.subText)
|
||||
.attr('y', Math.max(15, fontSize))
|
||||
.attr('style', 'dominant-baseline: central; text-anchor: middle;')
|
||||
.style('display', isTextTooLong)
|
||||
.style('fill', bgFill);
|
||||
}
|
||||
|
||||
gauges
|
||||
.append('text')
|
||||
.attr('class', 'chart-label')
|
||||
.attr('y', -5)
|
||||
.text(d => {
|
||||
if (this.gaugeConfig.percentageMode) {
|
||||
const percentage = Math.round(100 * (d.y - min) / (max - min));
|
||||
return `${percentage}%`;
|
||||
}
|
||||
return yFieldFormatter(d.y);
|
||||
})
|
||||
.attr('style', 'dominant-baseline: central; font-weight: bold; white-space: nowrap;text-overflow: ellipsis;overflow: hidden;')
|
||||
.style('text-anchor', 'middle')
|
||||
.style('font-size', fontSize + 'pt')
|
||||
.style('fill', function () {
|
||||
return !bgColor && labelColor ? self.getColorBucket(data.values[0].y) : bgFill;
|
||||
});
|
||||
|
||||
if (isTooltip) {
|
||||
series.each(function () {
|
||||
const gauge = d3.select(this);
|
||||
gauge.call(tooltip.render());
|
||||
});
|
||||
}
|
||||
|
||||
if (hiddenLabels) {
|
||||
this.gaugeChart.handler.alerts.show('Some labels were hidden due to size constrains');
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
}
|
||||
|
||||
return SimpleGauge;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import { VislibVisualizationsPointSeriesProvider } from './point_series';
|
||||
import { VislibVisualizationsPieChartProvider } from './pie_chart';
|
||||
import { GaugeChartProvider } from './gauge_chart';
|
||||
|
||||
export function VislibVisualizationsVisTypesProvider(Private) {
|
||||
|
||||
|
@ -13,6 +14,7 @@ export function VislibVisualizationsVisTypesProvider(Private) {
|
|||
*/
|
||||
return {
|
||||
pie: Private(VislibVisualizationsPieChartProvider),
|
||||
point_series: Private(VislibVisualizationsPointSeriesProvider)
|
||||
point_series: Private(VislibVisualizationsPointSeriesProvider),
|
||||
gauge: Private(GaugeChartProvider)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'plugins/kbn_vislib_vis_types/controls/point_series_options';
|
|||
import 'plugins/kbn_vislib_vis_types/controls/line_interpolation_option';
|
||||
import 'plugins/kbn_vislib_vis_types/controls/heatmap_options';
|
||||
import 'plugins/kbn_vislib_vis_types/controls/point_series';
|
||||
import 'plugins/kbn_vislib_vis_types/controls/gauge_options';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { AggResponsePointSeriesProvider } from 'ui/agg_response/point_series/point_series';
|
||||
import VislibVisTypeVislibRenderbotProvider from 'ui/vislib_vis_type/vislib_renderbot';
|
||||
|
|
|
@ -113,7 +113,7 @@ uiModules.get('kibana')
|
|||
$scope.open = $scope.vis.params.addLegend;
|
||||
}
|
||||
|
||||
if (vislibVis.visConfigArgs.type === 'heatmap') {
|
||||
if (['heatmap', 'gauge'].includes(vislibVis.visConfigArgs.type)) {
|
||||
const labels = vislibVis.getLegendLabels();
|
||||
if (labels) {
|
||||
$scope.labels = _.map(labels, label => {
|
||||
|
|
|
@ -22,6 +22,8 @@ export default function ({ getService, getPageObjects }) {
|
|||
'Pie',
|
||||
'Vertical Bar',
|
||||
'Data Table',
|
||||
'Gauge',
|
||||
'Goal',
|
||||
'Metric',
|
||||
'Tile Map',
|
||||
'Timelion',
|
||||
|
|
74
test/functional/apps/visualize/_gauge_chart.js
Normal file
74
test/functional/apps/visualize/_gauge_chart.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getService, getPageObjects }) {
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
const screenshots = getService('screenshots');
|
||||
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
|
||||
|
||||
describe('visualize app', function describeIndexTests() {
|
||||
const fromTime = '2015-09-19 06:31:44.000';
|
||||
const toTime = '2015-09-23 18:31:44.000';
|
||||
|
||||
before(function () {
|
||||
log.debug('navigateToApp visualize');
|
||||
return PageObjects.common.navigateToUrl('visualize', 'new')
|
||||
.then(function () {
|
||||
log.debug('clickGauge');
|
||||
return PageObjects.visualize.clickGauge();
|
||||
})
|
||||
.then(function clickNewSearch() {
|
||||
return PageObjects.visualize.clickNewSearch();
|
||||
})
|
||||
.then(function setAbsoluteRange() {
|
||||
log.debug('Set absolute time range from \"' + fromTime + '\" to \"' + toTime + '\"');
|
||||
return PageObjects.header.setAbsoluteRange(fromTime, toTime);
|
||||
});
|
||||
});
|
||||
|
||||
describe('gauge chart', function indexPatternCreation() {
|
||||
|
||||
it('should show Count', function () {
|
||||
const expectedCount = ['14,004', 'Count'];
|
||||
|
||||
// initial metric of "Count" is selected by default
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getGaugeValue()
|
||||
.then(function (metricValue) {
|
||||
screenshots.take('Visualize-gauge-chart');
|
||||
expect(expectedCount).to.eql(metricValue[0].split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Split Gauges', function () {
|
||||
const expectedTexts = [ 'win 8', 'win xp', 'win 7', 'ios', 'osx' ];
|
||||
return PageObjects.visualize.clickMetricEditor()
|
||||
.then(function clickBucket() {
|
||||
log.debug('Bucket = Split Group');
|
||||
return PageObjects.visualize.clickBucket('Split Group');
|
||||
})
|
||||
.then(function selectAggregation() {
|
||||
log.debug('Aggregation = Terms');
|
||||
return PageObjects.visualize.selectAggregation('Terms');
|
||||
})
|
||||
.then(function selectField() {
|
||||
log.debug('Field = machine.os.raw');
|
||||
return PageObjects.visualize.selectField('machine.os.raw');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getGaugeValue()
|
||||
.then(function (metricValue) {
|
||||
expect(expectedTexts).to.eql(metricValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getService, getPageObjects }) {
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
const screenshots = getService('screenshots');
|
||||
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
|
||||
|
||||
describe('visualize app', function describeIndexTests() {
|
||||
const fromTime = '2015-09-19 06:31:44.000';
|
||||
const toTime = '2015-09-23 18:31:44.000';
|
||||
|
||||
before(function () {
|
||||
log.debug('navigateToApp visualize');
|
||||
return PageObjects.common.navigateToUrl('visualize', 'new')
|
||||
.then(function () {
|
||||
log.debug('clickMetric');
|
||||
return PageObjects.visualize.clickMetric();
|
||||
})
|
||||
.then(function clickNewSearch() {
|
||||
return PageObjects.visualize.clickNewSearch();
|
||||
})
|
||||
.then(function setAbsoluteRange() {
|
||||
log.debug('Set absolute time range from \"' + fromTime + '\" to \"' + toTime + '\"');
|
||||
return PageObjects.header.setAbsoluteRange(fromTime, toTime);
|
||||
});
|
||||
});
|
||||
|
||||
describe('metric chart', function indexPatternCreation() {
|
||||
|
||||
it('should show Count', function () {
|
||||
const expectedCount = ['14,004', 'Count'];
|
||||
|
||||
// initial metric of "Count" is selected by default
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
screenshots.take('Visualize-metric-chart');
|
||||
expect(expectedCount).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Average', function () {
|
||||
const avgMachineRam = ['13,104,036,080.615', 'Average machine.ram'];
|
||||
return PageObjects.visualize.clickMetricEditor()
|
||||
.then(function () {
|
||||
log.debug('Aggregation = Average');
|
||||
return PageObjects.visualize.selectAggregation('Average');
|
||||
})
|
||||
.then(function selectField() {
|
||||
log.debug('Field = machine.ram');
|
||||
return PageObjects.visualize.selectField('machine.ram', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(avgMachineRam).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Sum', function () {
|
||||
const sumPhpMemory = ['85,865,880', 'Sum of phpmemory'];
|
||||
log.debug('Aggregation = Sum');
|
||||
return PageObjects.visualize.selectAggregation('Sum')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = phpmemory');
|
||||
return PageObjects.visualize.selectField('phpmemory', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(sumPhpMemory).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Median', function () {
|
||||
const medianBytes = ['5,565.263', '50th percentile of bytes'];
|
||||
// For now, only comparing the text label part of the metric
|
||||
log.debug('Aggregation = Median');
|
||||
return PageObjects.visualize.selectAggregation('Median')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = bytes');
|
||||
return PageObjects.visualize.selectField('bytes', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
// only comparing the text label!
|
||||
expect(medianBytes[1]).to.eql(metricValue.split('\n')[1]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Min', function () {
|
||||
const minTimestamp = ['September 20th 2015, 00:00:00.000', 'Min @timestamp'];
|
||||
log.debug('Aggregation = Min');
|
||||
return PageObjects.visualize.selectAggregation('Min')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = @timestamp');
|
||||
return PageObjects.visualize.selectField('@timestamp', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(minTimestamp).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Max', function () {
|
||||
const maxRelatedContentArticleModifiedTime = ['April 4th 2015, 00:54:41.000', 'Max relatedContent.article:modified_time'];
|
||||
log.debug('Aggregation = Max');
|
||||
return PageObjects.visualize.selectAggregation('Max')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = relatedContent.article:modified_time');
|
||||
return PageObjects.visualize.selectField('relatedContent.article:modified_time', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(maxRelatedContentArticleModifiedTime).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Standard Deviation', function () {
|
||||
const standardDeviationBytes = [
|
||||
'-1,435.138', 'Lower Standard Deviation of bytes',
|
||||
'12,889.766', 'Upper Standard Deviation of bytes'
|
||||
];
|
||||
log.debug('Aggregation = Standard Deviation');
|
||||
return PageObjects.visualize.selectAggregation('Standard Deviation')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = bytes');
|
||||
return PageObjects.visualize.selectField('bytes', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(standardDeviationBytes).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Unique Count', function () {
|
||||
const uniqueCountClientip = ['1,000', 'Unique count of clientip'];
|
||||
log.debug('Aggregation = Unique Count');
|
||||
return PageObjects.visualize.selectAggregation('Unique Count')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = clientip');
|
||||
return PageObjects.visualize.selectField('clientip', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(uniqueCountClientip).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
log.debug('metricValue=' + metricValue.split('\n'));
|
||||
expect(uniqueCountClientip).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Percentiles', function () {
|
||||
const percentileMachineRam = [
|
||||
'2,147,483,648', '1st percentile of machine.ram',
|
||||
'3,221,225,472', '5th percentile of machine.ram',
|
||||
'7,516,192,768', '25th percentile of machine.ram',
|
||||
'12,884,901,888', '50th percentile of machine.ram',
|
||||
'18,253,611,008', '75th percentile of machine.ram',
|
||||
'32,212,254,720', '95th percentile of machine.ram',
|
||||
'32,212,254,720', '99th percentile of machine.ram'
|
||||
];
|
||||
|
||||
log.debug('Aggregation = Percentiles');
|
||||
return PageObjects.visualize.selectAggregation('Percentiles')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = machine.ram');
|
||||
return PageObjects.visualize.selectField('machine.ram', 'metrics');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(percentileMachineRam).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should show Percentile Ranks', function () {
|
||||
const percentileRankBytes = [ '2.036%', 'Percentile rank 99 of "memory"'];
|
||||
log.debug('Aggregation = Percentile Ranks');
|
||||
return PageObjects.visualize.selectAggregation('Percentile Ranks')
|
||||
.then(function selectField() {
|
||||
log.debug('Field = bytes');
|
||||
return PageObjects.visualize.selectField('memory', 'metrics');
|
||||
})
|
||||
.then(function selectField() {
|
||||
log.debug('Values = 99');
|
||||
return PageObjects.visualize.setValue('99');
|
||||
})
|
||||
.then(function clickGo() {
|
||||
return PageObjects.visualize.clickGo();
|
||||
})
|
||||
.then(function () {
|
||||
return retry.try(function tryingForTime() {
|
||||
return PageObjects.visualize.getMetric()
|
||||
.then(function (metricValue) {
|
||||
expect(percentileRankBytes).to.eql(metricValue.split('\n'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
|
@ -24,10 +24,10 @@ export default function ({ getService, loadTestFile }) {
|
|||
|
||||
loadTestFile(require.resolve('./_editor'));
|
||||
loadTestFile(require.resolve('./_chart_types'));
|
||||
loadTestFile(require.resolve('./_gauge_chart'));
|
||||
loadTestFile(require.resolve('./_area_chart'));
|
||||
loadTestFile(require.resolve('./_line_chart'));
|
||||
loadTestFile(require.resolve('./_data_table'));
|
||||
loadTestFile(require.resolve('./_metric_chart'));
|
||||
loadTestFile(require.resolve('./_pie_chart'));
|
||||
loadTestFile(require.resolve('./_tag_cloud'));
|
||||
loadTestFile(require.resolve('./_tile_map'));
|
||||
|
|
|
@ -50,6 +50,13 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
|
|||
.click();
|
||||
}
|
||||
|
||||
clickGauge() {
|
||||
return remote
|
||||
.setFindTimeout(defaultFindTimeout)
|
||||
.findByPartialLinkText('Gauge')
|
||||
.click();
|
||||
}
|
||||
|
||||
clickPieChart() {
|
||||
return remote
|
||||
.setFindTimeout(defaultFindTimeout)
|
||||
|
@ -167,6 +174,13 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
|
|||
.getVisibleText();
|
||||
}
|
||||
|
||||
getGaugeValue() {
|
||||
return remote
|
||||
.setFindTimeout(2000)
|
||||
.findAllByCssSelector('visualize .chart svg')
|
||||
.getVisibleText();
|
||||
}
|
||||
|
||||
clickMetricEditor() {
|
||||
return remote
|
||||
.setFindTimeout(defaultFindTimeout)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue