mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
merged with master
This commit is contained in:
commit
4562f31b6b
@ -2,6 +2,9 @@ vNext
|
||||
|
||||
**New features or improvements**
|
||||
- Allow [[..]] filter notation in all text panels (markdown/html/text) (Issue #511)
|
||||
- New legend display option "Align as table" (Issue #136)
|
||||
- New legend display option "Right side", will show legend to the right of the graph (Issue #556)
|
||||
- Enhanced InfluxDB series aliasing (legend names) with pattern replacements (Issue #525)
|
||||
|
||||
**Changes**
|
||||
- Use unix epoch for Graphite from/to for absolute time ranges (Closes #536)
|
||||
|
@ -39,7 +39,6 @@ require.config({
|
||||
'jquery.flot.stack': '../vendor/jquery/jquery.flot.stack',
|
||||
'jquery.flot.stackpercent':'../vendor/jquery/jquery.flot.stackpercent',
|
||||
'jquery.flot.time': '../vendor/jquery/jquery.flot.time',
|
||||
'jquery.flot.byte': '../vendor/jquery/jquery.flot.byte',
|
||||
|
||||
modernizr: '../vendor/modernizr-2.6.1',
|
||||
|
||||
@ -80,7 +79,6 @@ require.config({
|
||||
//
|
||||
'jquery-ui': ['jquery'],
|
||||
'jquery.flot': ['jquery'],
|
||||
'jquery.flot.byte': ['jquery', 'jquery.flot'],
|
||||
'jquery.flot.pie': ['jquery', 'jquery.flot'],
|
||||
'jquery.flot.events': ['jquery', 'jquery.flot'],
|
||||
'jquery.flot.selection':['jquery', 'jquery.flot'],
|
||||
|
@ -18,6 +18,7 @@ function (angular, $, kbn, moment, _) {
|
||||
var data, plot, annotations;
|
||||
var hiddenData = {};
|
||||
var dashboard = scope.dashboard;
|
||||
var legendSideLastValue = null;
|
||||
|
||||
scope.$on('refresh',function() {
|
||||
if (scope.otherPanelInFullscreenMode()) { return; }
|
||||
@ -56,7 +57,7 @@ function (angular, $, kbn, moment, _) {
|
||||
|
||||
height = height - 32; // subtract panel title bar
|
||||
|
||||
if (scope.panel.legend.show) {
|
||||
if (scope.panel.legend.show && !scope.panel.legend.rightSide) {
|
||||
height = height - 21; // subtract one line legend
|
||||
}
|
||||
|
||||
@ -136,6 +137,7 @@ function (angular, $, kbn, moment, _) {
|
||||
yaxes: [],
|
||||
xaxis: {},
|
||||
grid: {
|
||||
minBorderMargin: 0,
|
||||
markings: [],
|
||||
backgroundColor: null,
|
||||
borderWidth: 0,
|
||||
@ -162,9 +164,30 @@ function (angular, $, kbn, moment, _) {
|
||||
addAnnotations(options);
|
||||
configureAxisOptions(data, options);
|
||||
|
||||
plot = $.plot(elem, data, options);
|
||||
// if legend is to the right delay plot draw a few milliseconds
|
||||
// so the legend width calculation can be done
|
||||
if (shouldDelayDraw(panel)) {
|
||||
console.log('delay');
|
||||
legendSideLastValue = panel.legend.rightSide;
|
||||
setTimeout(function() {
|
||||
plot = $.plot(elem, data, options);
|
||||
addAxisLabels();
|
||||
}, 50);
|
||||
}
|
||||
else {
|
||||
plot = $.plot(elem, data, options);
|
||||
addAxisLabels();
|
||||
}
|
||||
}
|
||||
|
||||
addAxisLabels();
|
||||
function shouldDelayDraw(panel) {
|
||||
if (panel.legend.rightSide) {
|
||||
return true;
|
||||
}
|
||||
if (legendSideLastValue !== null && panel.legend.rightSide !== legendSideLastValue) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function addTimeAxis(options) {
|
||||
@ -354,8 +377,10 @@ function (angular, $, kbn, moment, _) {
|
||||
url += scope.panel.fill !== 0 ? ('&areaAlpha=' + (scope.panel.fill/10).toFixed(1)) : '';
|
||||
url += scope.panel.linewidth !== 0 ? '&lineWidth=' + scope.panel.linewidth : '';
|
||||
url += scope.panel.legend.show ? '&hideLegend=false' : '&hideLegend=true';
|
||||
url += scope.panel.grid.min !== null ? '&yMin=' + scope.panel.grid.min : '';
|
||||
url += scope.panel.grid.max !== null ? '&yMax=' + scope.panel.grid.max : '';
|
||||
url += scope.panel.grid.leftMin !== null ? '&yMin=' + scope.panel.grid.leftMin : '';
|
||||
url += scope.panel.grid.leftMax !== null ? '&yMax=' + scope.panel.grid.leftMax : '';
|
||||
url += scope.panel.grid.rightMin !== null ? '&yMin=' + scope.panel.grid.rightMin : '';
|
||||
url += scope.panel.grid.rightMax !== null ? '&yMax=' + scope.panel.grid.rightMax : '';
|
||||
url += scope.panel['x-axis'] ? '' : '&hideAxes=true';
|
||||
url += scope.panel['y-axis'] ? '' : '&hideYAxis=true';
|
||||
|
||||
|
@ -33,47 +33,25 @@
|
||||
<label class="small">Max / <a ng-click="toggleGridMinMax('rightMax')">Auto <i class="icon-star" ng-show="_.isNull(panel.grid.rightMax)"></i></a></label>
|
||||
<input type="number" class="input-small" ng-model="panel.grid.rightMax" ng-change="render()" ng-model-onblur />
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Label</label>
|
||||
<input ng-change="get_data()" ng-model-onblur placeholder="" type="text" class="input-medium" ng-model="panel.rightYAxisLabel">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="editor-row">
|
||||
|
||||
<div class="section">
|
||||
<h5>Grid thresholds</h5>
|
||||
<div class="editor-option">
|
||||
<label class="small">Level1</label>
|
||||
<input type="number" class="input-small" ng-model="panel.grid.threshold1" ng-change="render()" ng-model-onblur />
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Color</label>
|
||||
<spectrum-picker ng-model="panel.grid.threshold1Color" ng-change="render()" ></spectrum-picker>
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Level2</label>
|
||||
<input type="number" class="input-small" ng-model="panel.grid.threshold2" ng-change="render()" ng-model-onblur />
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Color</label>
|
||||
<spectrum-picker ng-model="panel.grid.threshold2Color" ng-change="render()" ></spectrum-picker>
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Line mode</label><input type="checkbox" ng-model="panel.grid.thresholdLine" ng-checked="panel.grid.thresholdLine" ng-change="render();">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5>Legend</h5>
|
||||
<h5>Legend styles</h5>
|
||||
<div class="editor-option">
|
||||
<label class="small">Show Legend</label><input type="checkbox" ng-model="panel.legend.show" ng-checked="panel.legend.show" ng-change="render();">
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Include Values</label><input type="checkbox" ng-model="panel.legend.values" ng-checked="panel.legend.values" ng-change="render();">
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Align as table</label><input type="checkbox" ng-model="panel.legend.alignAsTable" ng-checked="panel.legend.alignAsTable">
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Right side</label><input type="checkbox" ng-model="panel.legend.rightSide" ng-change="render();" ng-checked="panel.legend.rightSide">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" ng-if="panel.legend.values">
|
||||
@ -100,6 +78,29 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5>Grid thresholds</h5>
|
||||
<div class="editor-option">
|
||||
<label class="small">Level1</label>
|
||||
<input type="number" class="input-small" ng-model="panel.grid.threshold1" ng-change="render()" ng-model-onblur />
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Color</label>
|
||||
<spectrum-picker ng-model="panel.grid.threshold1Color" ng-change="render()" ></spectrum-picker>
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Level2</label>
|
||||
<input type="number" class="input-small" ng-model="panel.grid.threshold2" ng-change="render()" ng-model-onblur />
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Color</label>
|
||||
<spectrum-picker ng-model="panel.grid.threshold2Color" ng-change="render()" ></spectrum-picker>
|
||||
</div>
|
||||
<div class="editor-option">
|
||||
<label class="small">Line mode</label><input type="checkbox" ng-model="panel.grid.thresholdLine" ng-checked="panel.grid.thresholdLine" ng-change="render();">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h5>Show Axes</h5>
|
||||
<div class="editor-option">
|
||||
|
@ -1,38 +1,40 @@
|
||||
<span ng-show="panel.legend.show"
|
||||
ng-class="{'pull-right': series.yaxis === 2, 'hidden-series': hiddenSeries[series.alias]}"
|
||||
ng-repeat='series in legend'
|
||||
class="histogram-legend">
|
||||
<i class='icon-minus pointer'
|
||||
ng-style="{color: series.color}"
|
||||
bs-popover="'colorPopup.html'"
|
||||
>
|
||||
</i>
|
||||
<span class='small histogram-legend-item'>
|
||||
<section class="graph-legend" ng-class="{'graph-legend-table': panel.legend.alignAsTable}">
|
||||
|
||||
<div class="graph-legend-series"
|
||||
ng-repeat='series in legend'
|
||||
ng-class="{'pull-right': series.yaxis === 2, 'graph-legend-series-hidden': hiddenSeries[series.alias]}"
|
||||
>
|
||||
<div class="graph-legend-icon">
|
||||
<i class='icon-minus pointer' ng-style="{color: series.color}" bs-popover="'colorPopup.html'">
|
||||
</i>
|
||||
</div>
|
||||
<div class="graph-legend-alias small">
|
||||
<a ng-click="toggleSeries(series, $event)" data-unique="1" data-placement="{{series.yaxis === 2 ? 'bottomRight' : 'bottomLeft'}}">
|
||||
{{series.alias}}
|
||||
</a>
|
||||
<span ng-if="panel.legend.values">
|
||||
<span ng-show="panel.legend.current">
|
||||
Current: {{series.current}}
|
||||
</span>
|
||||
<span ng-show="panel.legend.min">
|
||||
Min: {{series.min}}
|
||||
</span>
|
||||
<span ng-show="panel.legend.max">
|
||||
Max: {{series.max}}
|
||||
</span>
|
||||
<span ng-show="panel.legend.total">
|
||||
Total: {{series.total}}
|
||||
</span>
|
||||
<span ng-show="panel.legend.avg">
|
||||
Avg: {{series.avg}}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.current">
|
||||
Current: {{series.current}}
|
||||
</div>
|
||||
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.min">
|
||||
Min: {{series.min}}
|
||||
</div>
|
||||
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.max">
|
||||
Max: {{series.max}}
|
||||
</div>
|
||||
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.total">
|
||||
Total: {{series.total}}
|
||||
</div>
|
||||
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.avg">
|
||||
Avg: {{series.avg}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<script type="text/ng-template" id="colorPopup.html">
|
||||
<div class="histogram-legend-popover">
|
||||
<div class="graph-legend-popover">
|
||||
<a class="close" ng-click="dismiss();" href="">×</a>
|
||||
|
||||
<div class="editor-row small" style="padding-bottom: 0;">
|
||||
|
@ -3,21 +3,47 @@
|
||||
style="min-height:{{panel.height || row.height}}"
|
||||
ng-class="{'panel-fullscreen': fullscreen}">
|
||||
|
||||
<div style="position: relative">
|
||||
<!-- <table style="width: 100%">
|
||||
<tr>
|
||||
<td style="width: 100%">
|
||||
<div style="position: relative">
|
||||
|
||||
<div ng-if="datapointsWarning" class="datapoints-warning">
|
||||
<span class="small" ng-show="!datapointsCount">No datapoints <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
|
||||
<span class="small" ng-show="datapointsOutside">Datapoints outside time range <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
|
||||
</div>
|
||||
<div ng-if="datapointsWarning" class="datapoints-warning">
|
||||
<span class="small" ng-show="!datapointsCount">No datapoints <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
|
||||
<span class="small" ng-show="datapointsOutside">Datapoints outside time range <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
|
||||
</div>
|
||||
|
||||
<div grafana-graph class="pointer histogram-chart">
|
||||
</div>
|
||||
<div grafana-graph class="pointer histogram-chart">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div ng-if="panel.legend.show" ng-include="'app/panels/graph/legend.html'">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table> -->
|
||||
|
||||
<div class="graph-wrapper" ng-class="{'graph-legend-rightside': panel.legend.rightSide}">
|
||||
<div class="graph-canvas-wrapper">
|
||||
|
||||
<div ng-if="datapointsWarning" class="datapoints-warning">
|
||||
<span class="small" ng-show="!datapointsCount">No datapoints <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
|
||||
<span class="small" ng-show="datapointsOutside">Datapoints outside time range <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
|
||||
</div>
|
||||
|
||||
<div grafana-graph class="pointer histogram-chart">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="graph-legend-wrapper"
|
||||
ng-if="panel.legend.show"
|
||||
ng-include="'app/panels/graph/legend.html'">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="panel.legend" class="grafana-legend-container">
|
||||
<div ng-include="'app/panels/graph/legend.html'"></div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<div class="panel-full-edit-tabs" ng-if="editMode">
|
||||
|
@ -25,7 +25,6 @@ define([
|
||||
'jquery.flot.events',
|
||||
'jquery.flot.selection',
|
||||
'jquery.flot.time',
|
||||
'jquery.flot.byte',
|
||||
'jquery.flot.stack',
|
||||
'jquery.flot.stackpercent'
|
||||
],
|
||||
|
@ -153,5 +153,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pull-left metrics-editor-help" style="margin-top: 30px;">
|
||||
<div class="span6">
|
||||
<span class="pointer">
|
||||
<i class="icon-question-sign"></i> alias patterns:
|
||||
</span>
|
||||
<ul class="hide">
|
||||
<li>$s = series name</li>
|
||||
<li>$g = group by</li>
|
||||
<li>$[0-9] part of series name for series names seperated by dots.</li>
|
||||
<ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div ng-include src="datasource.editorSrc"></div>
|
||||
|
||||
|
||||
<div class="editor-row" style="margin-top: 20px">
|
||||
<div class="editor-row" style="margin-top: 30px">
|
||||
<button class="btn btn-success pull-right" ng-click="add_target(panel.target)">Add query</button>
|
||||
|
||||
<div class="btn-group pull-right" style="margin-right: 10px;">
|
||||
|
87
src/app/services/influxdb/influxSeries.js
Normal file
87
src/app/services/influxdb/influxSeries.js
Normal file
@ -0,0 +1,87 @@
|
||||
define([
|
||||
'underscore',
|
||||
],
|
||||
function (_) {
|
||||
'use strict';
|
||||
|
||||
function InfluxSeries(options) {
|
||||
this.seriesList = options.seriesList;
|
||||
this.alias = options.alias;
|
||||
this.groupByField = options.groupByField;
|
||||
}
|
||||
|
||||
var p = InfluxSeries.prototype;
|
||||
|
||||
p.getTimeSeries = function() {
|
||||
var output = [];
|
||||
var self = this;
|
||||
var i;
|
||||
|
||||
_.each(self.seriesList, function(series) {
|
||||
var seriesName;
|
||||
var timeCol = series.columns.indexOf('time');
|
||||
var valueCol = 1;
|
||||
var groupByCol = -1;
|
||||
|
||||
if (self.groupByField) {
|
||||
groupByCol = series.columns.indexOf(self.groupByField);
|
||||
}
|
||||
|
||||
// find value column
|
||||
_.each(series.columns, function(column, index) {
|
||||
if (column !== 'time' && column !== 'sequence_number' && column !== self.groupByField) {
|
||||
valueCol = index;
|
||||
}
|
||||
});
|
||||
|
||||
var groups = {};
|
||||
|
||||
if (self.groupByField) {
|
||||
groups = _.groupBy(series.points, function (point) {
|
||||
return point[groupByCol];
|
||||
});
|
||||
}
|
||||
else {
|
||||
groups[series.columns[valueCol]] = series.points;
|
||||
}
|
||||
|
||||
_.each(groups, function(groupPoints, key) {
|
||||
var datapoints = [];
|
||||
for (i = 0; i < groupPoints.length; i++) {
|
||||
var metricValue = isNaN(groupPoints[i][valueCol]) ? null : groupPoints[i][valueCol];
|
||||
datapoints[i] = [metricValue, groupPoints[i][timeCol]];
|
||||
}
|
||||
|
||||
seriesName = series.name + '.' + key;
|
||||
|
||||
if (self.alias) {
|
||||
seriesName = self.createNameForSeries(series.name, key);
|
||||
}
|
||||
|
||||
output.push({ target: seriesName, datapoints: datapoints });
|
||||
});
|
||||
});
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
p.createNameForSeries = function(seriesName, groupByColValue) {
|
||||
var name = this.alias
|
||||
.replace('$s', seriesName);
|
||||
|
||||
var segments = seriesName.split('.');
|
||||
for (var i = 0; i < segments.length; i++) {
|
||||
if (segments[i].length > 0) {
|
||||
name = name.replace('$' + i, segments[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.groupByField) {
|
||||
name = name.replace('$g', groupByColValue);
|
||||
}
|
||||
|
||||
return name;
|
||||
};
|
||||
|
||||
return InfluxSeries;
|
||||
});
|
@ -1,9 +1,10 @@
|
||||
define([
|
||||
'angular',
|
||||
'underscore',
|
||||
'kbn'
|
||||
'kbn',
|
||||
'./influxSeries'
|
||||
],
|
||||
function (angular, _, kbn) {
|
||||
function (angular, _, kbn, InfluxSeries) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('kibana.services');
|
||||
@ -194,57 +195,14 @@ function (angular, _, kbn) {
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
function handleInfluxQueryResponse(alias, groupByField, data) {
|
||||
var output = [];
|
||||
|
||||
_.each(data, function(series) {
|
||||
var seriesName;
|
||||
var timeCol = series.columns.indexOf('time');
|
||||
var valueCol = 1;
|
||||
var groupByCol = -1;
|
||||
|
||||
if (groupByField) {
|
||||
groupByCol = series.columns.indexOf(groupByField);
|
||||
}
|
||||
|
||||
// find value column
|
||||
_.each(series.columns, function(column, index) {
|
||||
if (column !== 'time' && column !== 'sequence_number' && column !== groupByField) {
|
||||
valueCol = index;
|
||||
}
|
||||
});
|
||||
|
||||
var groups = {};
|
||||
|
||||
if (groupByField) {
|
||||
groups = _.groupBy(series.points, function (point) {
|
||||
return point[groupByCol];
|
||||
});
|
||||
}
|
||||
else {
|
||||
groups[series.columns[valueCol]] = series.points;
|
||||
}
|
||||
|
||||
_.each(groups, function(groupPoints, key) {
|
||||
var datapoints = [];
|
||||
for (var i = 0; i < groupPoints.length; i++) {
|
||||
var metricValue = isNaN(groupPoints[i][valueCol]) ? null : groupPoints[i][valueCol];
|
||||
datapoints[i] = [metricValue, groupPoints[i][timeCol]];
|
||||
}
|
||||
|
||||
seriesName = alias ? alias : (series.name + '.' + key);
|
||||
|
||||
// if mulitple groups append key to alias
|
||||
if (alias && groupByField) {
|
||||
seriesName += key;
|
||||
}
|
||||
|
||||
output.push({ target: seriesName, datapoints: datapoints });
|
||||
});
|
||||
|
||||
function handleInfluxQueryResponse(alias, groupByField, seriesList) {
|
||||
var influxSeries = new InfluxSeries({
|
||||
seriesList: seriesList,
|
||||
alias: alias,
|
||||
groupByField: groupByField
|
||||
});
|
||||
|
||||
return output;
|
||||
return influxSeries.getTimeSeries();
|
||||
}
|
||||
|
||||
function getTimeFilter(options) {
|
||||
|
2
src/css/bootstrap.dark.min.css
vendored
2
src/css/bootstrap.dark.min.css
vendored
File diff suppressed because one or more lines are too long
2
src/css/bootstrap.light.min.css
vendored
2
src/css/bootstrap.light.min.css
vendored
File diff suppressed because one or more lines are too long
2
src/css/default.min.css
vendored
2
src/css/default.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
||||
@import "submenu.less";
|
||||
@import "graph.less";
|
||||
@import "bootstrap-tagsinput.less";
|
||||
|
||||
.hide-controls {
|
||||
@ -123,12 +124,6 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hidden-series {
|
||||
a {
|
||||
color: darken(@linkColor, 45%);
|
||||
}
|
||||
}
|
||||
|
||||
.panel-fullscreen {
|
||||
z-index: 100;
|
||||
display: block !important;
|
||||
@ -154,57 +149,10 @@
|
||||
right: -10000px;
|
||||
}
|
||||
|
||||
// Graphite Graph Legends
|
||||
|
||||
.grafana-legend-container {
|
||||
margin: 0 15px;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.grafana-legend-container .popover-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.histogram-legend {
|
||||
display:inline-block;
|
||||
padding: 0 4px;
|
||||
i {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.histogram-legend-item {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.histogram-chart {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.histogram-legend-popover {
|
||||
width: 200px;
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
.btn {
|
||||
padding: 1px 3px;
|
||||
margin-right: 0px;
|
||||
line-height: initial;
|
||||
}
|
||||
.close {
|
||||
margin-right: 5px;
|
||||
color: @linkColor;
|
||||
opacity: 0.7;
|
||||
text-shadow: none;
|
||||
}
|
||||
.editor-row {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-full-edit-tabs {
|
||||
margin-top: 10px;
|
||||
min-height: 250px;
|
||||
@ -520,3 +468,10 @@ select.grafana-target-segment-input {
|
||||
padding-top: 15px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
.metrics-editor-help:hover {
|
||||
.hide {
|
||||
display: block;
|
||||
}
|
||||
}
|
125
src/css/less/graph.less
Normal file
125
src/css/less/graph.less
Normal file
@ -0,0 +1,125 @@
|
||||
.graph-legend {
|
||||
margin: 0 20px;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
|
||||
.popover-content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-legend-icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.graph-legend-series,
|
||||
.graph-legend-icon,
|
||||
.graph-legend-alias,
|
||||
.graph-legend-value {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.graph-legend-series {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.graph-legend-value {
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.graph-legend-table {
|
||||
display: table;
|
||||
|
||||
.graph-legend-series {
|
||||
display: table-row;
|
||||
padding-left: 0;
|
||||
&.pull-right {
|
||||
float: none;
|
||||
.graph-legend-alias::after {
|
||||
content: 'y\00B2';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.graph-legend-alias {
|
||||
display: table-cell;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.graph-legend-icon {
|
||||
display: table-cell;
|
||||
white-space: nowrap;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.graph-legend-value {
|
||||
display: table-cell;
|
||||
white-space: nowrap;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.graph-legend-rightside {
|
||||
|
||||
&.graph-wrapper {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.graph-canvas-wrapper {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.graph-legend-wrapper {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
position: relative;
|
||||
left: -4px;
|
||||
}
|
||||
|
||||
.graph-legend {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.graph-legend-series {
|
||||
display: block;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.graph-legend-table .graph-legend-series {
|
||||
display: table-row;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-legend-series-hidden {
|
||||
a {
|
||||
color: darken(@linkColor, 45%);
|
||||
}
|
||||
}
|
||||
|
||||
.graph-legend-popover {
|
||||
width: 200px;
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
.btn {
|
||||
padding: 1px 3px;
|
||||
margin-right: 0px;
|
||||
line-height: initial;
|
||||
}
|
||||
.close {
|
||||
margin-right: 5px;
|
||||
color: @linkColor;
|
||||
opacity: 0.7;
|
||||
text-shadow: none;
|
||||
}
|
||||
.editor-row {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
142
src/test/specs/influxSeries-specs.js
Normal file
142
src/test/specs/influxSeries-specs.js
Normal file
@ -0,0 +1,142 @@
|
||||
define([
|
||||
'services/influxdb/influxSeries'
|
||||
], function(InfluxSeries) {
|
||||
'use strict';
|
||||
|
||||
describe('when generating timeseries from influxdb response', function() {
|
||||
|
||||
describe('given two series', function() {
|
||||
var series = new InfluxSeries({
|
||||
seriesList: [
|
||||
{
|
||||
columns: ['time', 'mean', 'sequence_number'],
|
||||
name: 'prod.server1.cpu',
|
||||
points: [[1402596000, 10, 1], [1402596001, 12, 2]]
|
||||
},
|
||||
{
|
||||
columns: ['time', 'mean', 'sequence_number'],
|
||||
name: 'prod.server2.cpu',
|
||||
points: [[1402596000, 15, 1], [1402596001, 16, 2]]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var result = series.getTimeSeries();
|
||||
|
||||
it('should generate two time series', function() {
|
||||
expect(result.length).to.be(2);
|
||||
expect(result[0].target).to.be('prod.server1.cpu.mean');
|
||||
expect(result[0].datapoints[0][0]).to.be(10);
|
||||
expect(result[0].datapoints[0][1]).to.be(1402596000);
|
||||
expect(result[0].datapoints[1][0]).to.be(12);
|
||||
expect(result[0].datapoints[1][1]).to.be(1402596001);
|
||||
|
||||
expect(result[1].target).to.be('prod.server2.cpu.mean');
|
||||
expect(result[1].datapoints[0][0]).to.be(15);
|
||||
expect(result[1].datapoints[0][1]).to.be(1402596000);
|
||||
expect(result[1].datapoints[1][0]).to.be(16);
|
||||
expect(result[1].datapoints[1][1]).to.be(1402596001);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given an alias format', function() {
|
||||
var series = new InfluxSeries({
|
||||
seriesList: [
|
||||
{
|
||||
columns: ['time', 'mean', 'sequence_number'],
|
||||
name: 'prod.server1.cpu',
|
||||
points: [[1402596000, 10, 1], [1402596001, 12, 2]]
|
||||
}
|
||||
],
|
||||
alias: '$s.testing'
|
||||
});
|
||||
|
||||
var result = series.getTimeSeries();
|
||||
|
||||
it('should generate correct series name', function() {
|
||||
expect(result[0].target).to.be('prod.server1.cpu.testing');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given an alias format with segment numbers', function() {
|
||||
var series = new InfluxSeries({
|
||||
seriesList: [
|
||||
{
|
||||
columns: ['time', 'mean', 'sequence_number'],
|
||||
name: 'prod.server1.cpu',
|
||||
points: [[1402596000, 10, 1], [1402596001, 12, 2]]
|
||||
}
|
||||
],
|
||||
alias: '$1.mean'
|
||||
});
|
||||
|
||||
var result = series.getTimeSeries();
|
||||
|
||||
it('should generate correct series name', function() {
|
||||
expect(result[0].target).to.be('server1.mean');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given an alias format with group by field', function() {
|
||||
var series = new InfluxSeries({
|
||||
seriesList: [
|
||||
{
|
||||
columns: ['time', 'mean', 'host'],
|
||||
name: 'prod.cpu',
|
||||
points: [[1402596000, 10, 'A']]
|
||||
}
|
||||
],
|
||||
groupByField: 'host',
|
||||
alias: '$g.$1'
|
||||
});
|
||||
|
||||
var result = series.getTimeSeries();
|
||||
|
||||
it('should generate correct series name', function() {
|
||||
expect(result[0].target).to.be('A.cpu');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given group by column', function() {
|
||||
var series = new InfluxSeries({
|
||||
seriesList: [
|
||||
{
|
||||
columns: ['time', 'mean', 'host'],
|
||||
name: 'prod.cpu',
|
||||
points: [
|
||||
[1402596000, 10, 'A'],
|
||||
[1402596001, 11, 'A'],
|
||||
[1402596000, 5, 'B'],
|
||||
[1402596001, 6, 'B'],
|
||||
]
|
||||
}
|
||||
],
|
||||
groupByField: 'host'
|
||||
});
|
||||
|
||||
var result = series.getTimeSeries();
|
||||
|
||||
it('should generate two time series', function() {
|
||||
expect(result.length).to.be(2);
|
||||
expect(result[0].target).to.be('prod.cpu.A');
|
||||
expect(result[0].datapoints[0][0]).to.be(10);
|
||||
expect(result[0].datapoints[0][1]).to.be(1402596000);
|
||||
expect(result[0].datapoints[1][0]).to.be(11);
|
||||
expect(result[0].datapoints[1][1]).to.be(1402596001);
|
||||
|
||||
expect(result[1].target).to.be('prod.cpu.B');
|
||||
expect(result[1].datapoints[0][0]).to.be(5);
|
||||
expect(result[1].datapoints[0][1]).to.be(1402596000);
|
||||
expect(result[1].datapoints[1][0]).to.be(6);
|
||||
expect(result[1].datapoints[1][1]).to.be(1402596001);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -42,7 +42,6 @@ require.config({
|
||||
'jquery.flot.stack': '../vendor/jquery/jquery.flot.stack',
|
||||
'jquery.flot.stackpercent':'../vendor/jquery/jquery.flot.stackpercent',
|
||||
'jquery.flot.time': '../vendor/jquery/jquery.flot.time',
|
||||
'jquery.flot.byte': '../vendor/jquery/jquery.flot.byte',
|
||||
|
||||
modernizr: '../vendor/modernizr-2.6.1',
|
||||
},
|
||||
@ -75,7 +74,6 @@ require.config({
|
||||
|
||||
'jquery-ui': ['jquery'],
|
||||
'jquery.flot': ['jquery'],
|
||||
'jquery.flot.byte': ['jquery', 'jquery.flot'],
|
||||
'jquery.flot.pie': ['jquery', 'jquery.flot'],
|
||||
'jquery.flot.events': ['jquery', 'jquery.flot'],
|
||||
'jquery.flot.selection':['jquery', 'jquery.flot'],
|
||||
@ -96,7 +94,6 @@ require.config({
|
||||
|
||||
'bootstrap-tagsinput': ['jquery'],
|
||||
|
||||
|
||||
timepicker: ['jquery', 'bootstrap'],
|
||||
datepicker: ['jquery', 'bootstrap'],
|
||||
}
|
||||
@ -128,8 +125,10 @@ require([
|
||||
'specs/gfunc-specs',
|
||||
'specs/filterSrv-specs',
|
||||
'specs/kbn-format-specs',
|
||||
'specs/influxSeries-specs'
|
||||
], function () {
|
||||
window.__karma__.start();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
107
src/vendor/jquery/jquery.flot.byte.js
vendored
107
src/vendor/jquery/jquery.flot.byte.js
vendored
@ -1,107 +0,0 @@
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
var options = {};
|
||||
|
||||
//Round to nearby lower multiple of base
|
||||
function floorInBase(n, base) {
|
||||
return base * Math.floor(n / base);
|
||||
}
|
||||
|
||||
function init(plot) {
|
||||
plot.hooks.processDatapoints.push(function (plot) {
|
||||
$.each(plot.getAxes(), function(axisName, axis) {
|
||||
var opts = axis.options;
|
||||
if (opts.mode === "byte" || opts.mode === "byteRate") {
|
||||
axis.tickGenerator = function (axis) {
|
||||
var returnTicks = [],
|
||||
tickSize = 2,
|
||||
delta = axis.delta,
|
||||
steps = 0,
|
||||
tickMin = 0,
|
||||
tickVal,
|
||||
tickCount = 0;
|
||||
|
||||
//Set the reference for the formatter
|
||||
if (opts.mode === "byteRate") {
|
||||
axis.rate = true;
|
||||
}
|
||||
|
||||
//Enforce maximum tick Decimals
|
||||
if (typeof opts.tickDecimals === "number") {
|
||||
axis.tickDecimals = opts.tickDecimals;
|
||||
} else {
|
||||
axis.tickDecimals = 2;
|
||||
}
|
||||
|
||||
//Count the steps
|
||||
while (Math.abs(delta) >= 1024) {
|
||||
steps++;
|
||||
delta /= 1024;
|
||||
}
|
||||
|
||||
//Set the tick size relative to the remaining delta
|
||||
while (tickSize <= 1024) {
|
||||
if (delta <= tickSize) {
|
||||
break;
|
||||
}
|
||||
tickSize *= 2;
|
||||
}
|
||||
|
||||
//Tell flot the tickSize we've calculated
|
||||
if (typeof opts.minTickSize !== "undefined" && tickSize < opts.minTickSize) {
|
||||
axis.tickSize = opts.minTickSize;
|
||||
} else {
|
||||
axis.tickSize = tickSize * Math.pow(1024,steps);
|
||||
}
|
||||
|
||||
//Calculate the new ticks
|
||||
tickMin = floorInBase(axis.min, axis.tickSize);
|
||||
do {
|
||||
tickVal = tickMin + (tickCount++) * axis.tickSize;
|
||||
returnTicks.push(tickVal);
|
||||
} while (tickVal < axis.max);
|
||||
|
||||
return returnTicks;
|
||||
};
|
||||
|
||||
axis.tickFormatter = function(size, axis) {
|
||||
var ext, steps = 0;
|
||||
|
||||
while (Math.abs(size) >= 1024) {
|
||||
steps++;
|
||||
size /= 1024;
|
||||
}
|
||||
|
||||
|
||||
switch (steps) {
|
||||
case 0: ext = " B"; break;
|
||||
case 1: ext = " KB"; break;
|
||||
case 2: ext = " MB"; break;
|
||||
case 3: ext = " GB"; break;
|
||||
case 4: ext = " TB"; break;
|
||||
case 5: ext = " PB"; break;
|
||||
case 6: ext = " EB"; break;
|
||||
case 7: ext = " ZB"; break;
|
||||
case 8: ext = " YB"; break;
|
||||
}
|
||||
|
||||
|
||||
if (typeof axis.rate !== "undefined") {
|
||||
ext += "/s";
|
||||
}
|
||||
|
||||
return (size.toFixed(axis.tickDecimals) + ext);
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: "byte",
|
||||
version: "0.1"
|
||||
});
|
||||
})(jQuery);
|
304
src/vendor/jquery/jquery.flot.js
vendored
304
src/vendor/jquery/jquery.flot.js
vendored
@ -1,6 +1,6 @@
|
||||
/* Javascript plotting library for jQuery, version 0.8.1.
|
||||
/* Javascript plotting library for jQuery, version 0.8.3.
|
||||
|
||||
Copyright (c) 2007-2013 IOLA and Ole Laursen.
|
||||
Copyright (c) 2007-2014 IOLA and Ole Laursen.
|
||||
Licensed under the MIT license.
|
||||
|
||||
*/
|
||||
@ -29,7 +29,7 @@ Licensed under the MIT license.
|
||||
* V. 1.1: Fix error handling so e.g. parsing an empty string does
|
||||
* produce a color rather than just crashing.
|
||||
*/
|
||||
(function(B){B.color={};B.color.make=function(F,E,C,D){var G={};G.r=F||0;G.g=E||0;G.b=C||0;G.a=D!=null?D:1;G.add=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]+=I}return G.normalize()};G.scale=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]*=I}return G.normalize()};G.toString=function(){if(G.a>=1){return"rgb("+[G.r,G.g,G.b].join(",")+")"}else{return"rgba("+[G.r,G.g,G.b,G.a].join(",")+")"}};G.normalize=function(){function H(J,K,I){return K<J?J:(K>I?I:K)}G.r=H(0,parseInt(G.r),255);G.g=H(0,parseInt(G.g),255);G.b=H(0,parseInt(G.b),255);G.a=H(0,G.a,1);return G};G.clone=function(){return B.color.make(G.r,G.b,G.g,G.a)};return G.normalize()};B.color.extract=function(D,C){var E;do{E=D.css(C).toLowerCase();if(E!=""&&E!="transparent"){break}D=D.parent()}while(!B.nodeName(D.get(0),"body"));if(E=="rgba(0, 0, 0, 0)"){E="transparent"}return B.color.parse(E)};B.color.parse=function(F){var E,C=B.color.make;if(E=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10))}if(E=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10),parseFloat(E[4]))}if(E=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55)}if(E=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55,parseFloat(E[4]))}if(E=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(F)){return C(parseInt(E[1],16),parseInt(E[2],16),parseInt(E[3],16))}if(E=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(F)){return C(parseInt(E[1]+E[1],16),parseInt(E[2]+E[2],16),parseInt(E[3]+E[3],16))}var D=B.trim(F).toLowerCase();if(D=="transparent"){return C(255,255,255,0)}else{E=A[D]||[0,0,0];return C(E[0],E[1],E[2])}};var A={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
|
||||
(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
|
||||
|
||||
// the actual Flot code
|
||||
(function($) {
|
||||
@ -38,6 +38,22 @@ Licensed under the MIT license.
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
// A shim to provide 'detach' to jQuery versions prior to 1.4. Using a DOM
|
||||
// operation produces the same effect as detach, i.e. removing the element
|
||||
// without touching its jQuery data.
|
||||
|
||||
// Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+.
|
||||
|
||||
if (!$.fn.detach) {
|
||||
$.fn.detach = function() {
|
||||
return this.each(function() {
|
||||
if (this.parentNode) {
|
||||
this.parentNode.removeChild( this );
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The Canvas object is a wrapper around an HTML5 <canvas> tag.
|
||||
//
|
||||
@ -425,7 +441,7 @@ Licensed under the MIT license.
|
||||
element: positions.length ? info.element.clone() : info.element,
|
||||
x: x,
|
||||
y: y
|
||||
}
|
||||
};
|
||||
|
||||
positions.push(position);
|
||||
|
||||
@ -567,6 +583,7 @@ Licensed under the MIT license.
|
||||
fillColor: null,
|
||||
align: "left", // "left", "right", or "center"
|
||||
horizontal: false,
|
||||
zero: true
|
||||
},
|
||||
shadowSize: 3,
|
||||
highlightColor: null
|
||||
@ -657,6 +674,23 @@ Licensed under the MIT license.
|
||||
};
|
||||
};
|
||||
plot.shutdown = shutdown;
|
||||
plot.destroy = function () {
|
||||
shutdown();
|
||||
placeholder.removeData("plot").empty();
|
||||
|
||||
series = [];
|
||||
options = null;
|
||||
surface = null;
|
||||
overlay = null;
|
||||
eventHolder = null;
|
||||
ctx = null;
|
||||
octx = null;
|
||||
xaxes = [];
|
||||
yaxes = [];
|
||||
hooks = null;
|
||||
highlights = [];
|
||||
plot = null;
|
||||
};
|
||||
plot.resize = function () {
|
||||
var width = placeholder.width(),
|
||||
height = placeholder.height();
|
||||
@ -734,16 +768,16 @@ Licensed under the MIT license.
|
||||
// since the rest of the code assumes that they exist.
|
||||
|
||||
var i, axisOptions, axisCount,
|
||||
fontSize = placeholder.css("font-size"),
|
||||
fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13,
|
||||
fontDefaults = {
|
||||
style: placeholder.css("font-style"),
|
||||
size: Math.round(0.8 * (+placeholder.css("font-size").replace("px", "") || 13)),
|
||||
size: Math.round(0.8 * fontSizeDefault),
|
||||
variant: placeholder.css("font-variant"),
|
||||
weight: placeholder.css("font-weight"),
|
||||
family: placeholder.css("font-family")
|
||||
};
|
||||
|
||||
fontDefaults.lineHeight = fontDefaults.size * 1.15;
|
||||
|
||||
axisCount = options.xaxes.length || 1;
|
||||
for (i = 0; i < axisCount; ++i) {
|
||||
|
||||
@ -760,6 +794,9 @@ Licensed under the MIT license.
|
||||
if (!axisOptions.font.color) {
|
||||
axisOptions.font.color = axisOptions.color;
|
||||
}
|
||||
if (!axisOptions.font.lineHeight) {
|
||||
axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -779,6 +816,9 @@ Licensed under the MIT license.
|
||||
if (!axisOptions.font.color) {
|
||||
axisOptions.font.color = axisOptions.color;
|
||||
}
|
||||
if (!axisOptions.font.lineHeight) {
|
||||
axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -790,10 +830,24 @@ Licensed under the MIT license.
|
||||
if (options.x2axis) {
|
||||
options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);
|
||||
options.xaxes[1].position = "top";
|
||||
// Override the inherit to allow the axis to auto-scale
|
||||
if (options.x2axis.min == null) {
|
||||
options.xaxes[1].min = null;
|
||||
}
|
||||
if (options.x2axis.max == null) {
|
||||
options.xaxes[1].max = null;
|
||||
}
|
||||
}
|
||||
if (options.y2axis) {
|
||||
options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);
|
||||
options.yaxes[1].position = "right";
|
||||
// Override the inherit to allow the axis to auto-scale
|
||||
if (options.y2axis.min == null) {
|
||||
options.yaxes[1].min = null;
|
||||
}
|
||||
if (options.y2axis.max == null) {
|
||||
options.yaxes[1].max = null;
|
||||
}
|
||||
}
|
||||
if (options.grid.coloredAreas)
|
||||
options.grid.markings = options.grid.coloredAreas;
|
||||
@ -1130,7 +1184,7 @@ Licensed under the MIT license.
|
||||
if (val != null) {
|
||||
f = format[m];
|
||||
// extract min/max info
|
||||
if (f.autoscale) {
|
||||
if (f.autoscale !== false) {
|
||||
if (f.x) {
|
||||
updateAxis(s.xaxis, val, val);
|
||||
}
|
||||
@ -1217,11 +1271,8 @@ Licensed under the MIT license.
|
||||
case "right":
|
||||
delta = -s.bars.barWidth;
|
||||
break;
|
||||
case "center":
|
||||
delta = -s.bars.barWidth / 2;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid bar alignment: " + s.bars.align);
|
||||
delta = -s.bars.barWidth / 2;
|
||||
}
|
||||
|
||||
if (s.bars.horizontal) {
|
||||
@ -1252,7 +1303,9 @@ Licensed under the MIT license.
|
||||
// from a previous plot in this container that we'll try to re-use.
|
||||
|
||||
placeholder.css("padding", 0) // padding messes up the positioning
|
||||
.children(":not(.flot-base,.flot-overlay)").remove();
|
||||
.children().filter(function(){
|
||||
return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base');
|
||||
}).remove();
|
||||
|
||||
if (placeholder.css("position") == 'static')
|
||||
placeholder.css("position", "relative"); // for positioning labels and overlay
|
||||
@ -1349,7 +1402,7 @@ Licensed under the MIT license.
|
||||
ticks = axis.ticks || [],
|
||||
labelWidth = opts.labelWidth || 0,
|
||||
labelHeight = opts.labelHeight || 0,
|
||||
maxWidth = labelWidth || axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null;
|
||||
maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null),
|
||||
legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
|
||||
layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
|
||||
font = opts.font || "flot-tick-label tickLabel";
|
||||
@ -1381,37 +1434,50 @@ Licensed under the MIT license.
|
||||
var lw = axis.labelWidth,
|
||||
lh = axis.labelHeight,
|
||||
pos = axis.options.position,
|
||||
isXAxis = axis.direction === "x",
|
||||
tickLength = axis.options.tickLength,
|
||||
axisMargin = options.grid.axisMargin,
|
||||
padding = options.grid.labelMargin,
|
||||
all = axis.direction == "x" ? xaxes : yaxes,
|
||||
index, innermost;
|
||||
innermost = true,
|
||||
outermost = true,
|
||||
first = true,
|
||||
found = false;
|
||||
|
||||
// determine axis margin
|
||||
var samePosition = $.grep(all, function (a) {
|
||||
return a && a.options.position == pos && a.reserveSpace;
|
||||
// Determine the axis's position in its direction and on its side
|
||||
|
||||
$.each(isXAxis ? xaxes : yaxes, function(i, a) {
|
||||
if (a && (a.show || a.reserveSpace)) {
|
||||
if (a === axis) {
|
||||
found = true;
|
||||
} else if (a.options.position === pos) {
|
||||
if (found) {
|
||||
outermost = false;
|
||||
} else {
|
||||
innermost = false;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
if ($.inArray(axis, samePosition) == samePosition.length - 1)
|
||||
axisMargin = 0; // outermost
|
||||
|
||||
// determine tick length - if we're innermost, we can use "full"
|
||||
// The outermost axis on each side has no margin
|
||||
|
||||
if (outermost) {
|
||||
axisMargin = 0;
|
||||
}
|
||||
|
||||
// The ticks for the first axis in each direction stretch across
|
||||
|
||||
if (tickLength == null) {
|
||||
var sameDirection = $.grep(all, function (a) {
|
||||
return a && a.reserveSpace;
|
||||
});
|
||||
|
||||
innermost = $.inArray(axis, sameDirection) == 0;
|
||||
if (innermost)
|
||||
tickLength = "full";
|
||||
else
|
||||
tickLength = 5;
|
||||
tickLength = first ? "full" : 5;
|
||||
}
|
||||
|
||||
if (!isNaN(+tickLength))
|
||||
padding += +tickLength;
|
||||
|
||||
// compute box
|
||||
if (axis.direction == "x") {
|
||||
if (isXAxis) {
|
||||
lh += padding;
|
||||
|
||||
if (pos == "bottom") {
|
||||
@ -1461,7 +1527,7 @@ Licensed under the MIT license.
|
||||
// inside the canvas and isn't clipped off
|
||||
|
||||
var minMargin = options.grid.minBorderMargin,
|
||||
margins = { x: 0, y: 0 }, i, axis;
|
||||
axis, i;
|
||||
|
||||
// check stuff from the plot (FIXME: this should just read
|
||||
// a value from the series, otherwise it's impossible to
|
||||
@ -1472,21 +1538,32 @@ Licensed under the MIT license.
|
||||
minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2));
|
||||
}
|
||||
|
||||
margins.x = margins.y = Math.ceil(minMargin);
|
||||
var margins = {
|
||||
left: minMargin,
|
||||
right: minMargin,
|
||||
top: minMargin,
|
||||
bottom: minMargin
|
||||
};
|
||||
|
||||
// check axis labels, note we don't check the actual
|
||||
// labels but instead use the overall width/height to not
|
||||
// jump as much around with replots
|
||||
$.each(allAxes(), function (_, axis) {
|
||||
var dir = axis.direction;
|
||||
if (axis.reserveSpace)
|
||||
margins[dir] = Math.ceil(Math.max(margins[dir], (dir == "x" ? axis.labelWidth : axis.labelHeight) / 2));
|
||||
if (axis.reserveSpace && axis.ticks && axis.ticks.length) {
|
||||
if (axis.direction === "x") {
|
||||
margins.left = Math.max(margins.left, axis.labelWidth / 2);
|
||||
margins.right = Math.max(margins.right, axis.labelWidth / 2);
|
||||
} else {
|
||||
margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2);
|
||||
margins.top = Math.max(margins.top, axis.labelHeight / 2);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
plotOffset.left = Math.max(margins.x, plotOffset.left);
|
||||
plotOffset.right = Math.max(margins.x, plotOffset.right);
|
||||
plotOffset.top = Math.max(margins.y, plotOffset.top);
|
||||
plotOffset.bottom = Math.max(margins.y, plotOffset.bottom);
|
||||
plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left));
|
||||
plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right));
|
||||
plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top));
|
||||
plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom));
|
||||
}
|
||||
|
||||
function setupGrid() {
|
||||
@ -1512,20 +1589,18 @@ Licensed under the MIT license.
|
||||
}
|
||||
}
|
||||
|
||||
// init axes
|
||||
$.each(axes, function (_, axis) {
|
||||
axis.show = axis.options.show;
|
||||
if (axis.show == null)
|
||||
axis.show = axis.used; // by default an axis is visible if it's got data
|
||||
|
||||
axis.reserveSpace = axis.show || axis.options.reserveSpace;
|
||||
|
||||
var axisOpts = axis.options;
|
||||
axis.show = axisOpts.show == null ? axis.used : axisOpts.show;
|
||||
axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace;
|
||||
setRange(axis);
|
||||
});
|
||||
|
||||
if (showGrid) {
|
||||
|
||||
var allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });
|
||||
var allocatedAxes = $.grep(axes, function (axis) {
|
||||
return axis.show || axis.reserveSpace;
|
||||
});
|
||||
|
||||
$.each(allocatedAxes, function (_, axis) {
|
||||
// make the ticks
|
||||
@ -1654,8 +1729,8 @@ Licensed under the MIT license.
|
||||
axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
|
||||
axis.tickSize = opts.tickSize || size;
|
||||
|
||||
// Time mode was moved to a plug-in in 0.8, but since so many people use this
|
||||
// we'll add an especially friendly make sure they remembered to include it.
|
||||
// Time mode was moved to a plug-in in 0.8, and since so many people use it
|
||||
// we'll add an especially friendly reminder to make sure they included it.
|
||||
|
||||
if (opts.mode == "time" && !axis.tickGenerator) {
|
||||
throw new Error("Time mode requires the flot.time plugin.");
|
||||
@ -1911,26 +1986,34 @@ Licensed under the MIT license.
|
||||
yrange.from = Math.max(yrange.from, yrange.axis.min);
|
||||
yrange.to = Math.min(yrange.to, yrange.axis.max);
|
||||
|
||||
if (xrange.from == xrange.to && yrange.from == yrange.to)
|
||||
var xequal = xrange.from === xrange.to,
|
||||
yequal = yrange.from === yrange.to;
|
||||
|
||||
if (xequal && yequal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// then draw
|
||||
xrange.from = xrange.axis.p2c(xrange.from);
|
||||
xrange.to = xrange.axis.p2c(xrange.to);
|
||||
yrange.from = yrange.axis.p2c(yrange.from);
|
||||
yrange.to = yrange.axis.p2c(yrange.to);
|
||||
xrange.from = Math.floor(xrange.axis.p2c(xrange.from));
|
||||
xrange.to = Math.floor(xrange.axis.p2c(xrange.to));
|
||||
yrange.from = Math.floor(yrange.axis.p2c(yrange.from));
|
||||
yrange.to = Math.floor(yrange.axis.p2c(yrange.to));
|
||||
|
||||
if (xrange.from == xrange.to || yrange.from == yrange.to) {
|
||||
// draw line
|
||||
if (xequal || yequal) {
|
||||
var lineWidth = m.lineWidth || options.grid.markingsLineWidth,
|
||||
subPixel = lineWidth % 2 ? 0.5 : 0;
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = m.color || options.grid.markingsColor;
|
||||
ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
|
||||
ctx.moveTo(xrange.from, yrange.from);
|
||||
ctx.lineTo(xrange.to, yrange.to);
|
||||
ctx.lineWidth = lineWidth;
|
||||
if (xequal) {
|
||||
ctx.moveTo(xrange.to + subPixel, yrange.from);
|
||||
ctx.lineTo(xrange.to + subPixel, yrange.to);
|
||||
} else {
|
||||
ctx.moveTo(xrange.from, yrange.to + subPixel);
|
||||
ctx.lineTo(xrange.to, yrange.to + subPixel);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
else {
|
||||
// fill area
|
||||
} else {
|
||||
ctx.fillStyle = m.color || options.grid.markingsColor;
|
||||
ctx.fillRect(xrange.from, yrange.to,
|
||||
xrange.to - xrange.from,
|
||||
@ -2099,17 +2182,21 @@ Licensed under the MIT license.
|
||||
function drawAxisLabels() {
|
||||
|
||||
$.each(allAxes(), function (_, axis) {
|
||||
if (!axis.show || axis.ticks.length == 0)
|
||||
return;
|
||||
|
||||
var box = axis.box,
|
||||
legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
|
||||
layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
|
||||
font = axis.options.font || "flot-tick-label tickLabel",
|
||||
tick, x, y, halign, valign;
|
||||
|
||||
// Remove text before checking for axis.show and ticks.length;
|
||||
// otherwise plugins, like flot-tickrotor, that draw their own
|
||||
// tick labels will end up with both theirs and the defaults.
|
||||
|
||||
surface.removeText(layer);
|
||||
|
||||
if (!axis.show || axis.ticks.length == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < axis.ticks.length; ++i) {
|
||||
|
||||
tick = axis.ticks[i];
|
||||
@ -2467,7 +2554,7 @@ Licensed under the MIT license.
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
|
||||
function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
|
||||
var left, right, bottom, top,
|
||||
drawLeft, drawRight, drawTop, drawBottom,
|
||||
tmp;
|
||||
@ -2542,13 +2629,8 @@ Licensed under the MIT license.
|
||||
|
||||
// fill the bar
|
||||
if (fillStyleCallback) {
|
||||
c.beginPath();
|
||||
c.moveTo(left, bottom);
|
||||
c.lineTo(left, top);
|
||||
c.lineTo(right, top);
|
||||
c.lineTo(right, bottom);
|
||||
c.fillStyle = fillStyleCallback(bottom, top);
|
||||
c.fill();
|
||||
c.fillRect(left, top, right - left, bottom - top)
|
||||
}
|
||||
|
||||
// draw outline
|
||||
@ -2556,35 +2638,35 @@ Licensed under the MIT license.
|
||||
c.beginPath();
|
||||
|
||||
// FIXME: inline moveTo is buggy with excanvas
|
||||
c.moveTo(left, bottom + offset);
|
||||
c.moveTo(left, bottom);
|
||||
if (drawLeft)
|
||||
c.lineTo(left, top + offset);
|
||||
c.lineTo(left, top);
|
||||
else
|
||||
c.moveTo(left, top + offset);
|
||||
c.moveTo(left, top);
|
||||
if (drawTop)
|
||||
c.lineTo(right, top + offset);
|
||||
c.lineTo(right, top);
|
||||
else
|
||||
c.moveTo(right, top + offset);
|
||||
c.moveTo(right, top);
|
||||
if (drawRight)
|
||||
c.lineTo(right, bottom + offset);
|
||||
c.lineTo(right, bottom);
|
||||
else
|
||||
c.moveTo(right, bottom + offset);
|
||||
c.moveTo(right, bottom);
|
||||
if (drawBottom)
|
||||
c.lineTo(left, bottom + offset);
|
||||
c.lineTo(left, bottom);
|
||||
else
|
||||
c.moveTo(left, bottom + offset);
|
||||
c.moveTo(left, bottom);
|
||||
c.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function drawSeriesBars(series) {
|
||||
function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) {
|
||||
function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
|
||||
var points = datapoints.points, ps = datapoints.pointsize;
|
||||
|
||||
for (var i = 0; i < points.length; i += ps) {
|
||||
if (points[i] == null)
|
||||
continue;
|
||||
drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
|
||||
drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2604,15 +2686,12 @@ Licensed under the MIT license.
|
||||
case "right":
|
||||
barLeft = -series.bars.barWidth;
|
||||
break;
|
||||
case "center":
|
||||
barLeft = -series.bars.barWidth / 2;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid bar alignment: " + series.bars.align);
|
||||
barLeft = -series.bars.barWidth / 2;
|
||||
}
|
||||
|
||||
var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
|
||||
plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);
|
||||
plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
@ -2632,10 +2711,15 @@ Licensed under the MIT license.
|
||||
|
||||
function insertLegend() {
|
||||
|
||||
placeholder.find(".legend").remove();
|
||||
if (options.legend.container != null) {
|
||||
$(options.legend.container).html("");
|
||||
} else {
|
||||
placeholder.find(".legend").remove();
|
||||
}
|
||||
|
||||
if (!options.legend.show)
|
||||
if (!options.legend.show) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fragments = [], entries = [], rowStarted = false,
|
||||
lf = options.legend.labelFormatter, s, label;
|
||||
@ -2796,8 +2880,21 @@ Licensed under the MIT license.
|
||||
}
|
||||
|
||||
if (s.bars.show && !item) { // no other point can be nearby
|
||||
var barLeft = s.bars.align == "left" ? 0 : -s.bars.barWidth/2,
|
||||
barRight = barLeft + s.bars.barWidth;
|
||||
|
||||
var barLeft, barRight;
|
||||
|
||||
switch (s.bars.align) {
|
||||
case "left":
|
||||
barLeft = 0;
|
||||
break;
|
||||
case "right":
|
||||
barLeft = -s.bars.barWidth;
|
||||
break;
|
||||
default:
|
||||
barLeft = -s.bars.barWidth / 2;
|
||||
}
|
||||
|
||||
barRight = barLeft + s.bars.barWidth;
|
||||
|
||||
for (j = 0; j < points.length; j += ps) {
|
||||
var x = points[j], y = points[j + 1], b = points[j + 2];
|
||||
@ -2995,13 +3092,24 @@ Licensed under the MIT license.
|
||||
function drawBarHighlight(series, point) {
|
||||
var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
|
||||
fillStyle = highlightColor,
|
||||
barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
|
||||
barLeft;
|
||||
|
||||
switch (series.bars.align) {
|
||||
case "left":
|
||||
barLeft = 0;
|
||||
break;
|
||||
case "right":
|
||||
barLeft = -series.bars.barWidth;
|
||||
break;
|
||||
default:
|
||||
barLeft = -series.bars.barWidth / 2;
|
||||
}
|
||||
|
||||
octx.lineWidth = series.bars.lineWidth;
|
||||
octx.strokeStyle = highlightColor;
|
||||
|
||||
drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
|
||||
0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
|
||||
function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
|
||||
}
|
||||
|
||||
function getColorOrGradient(spec, bottom, top, defaultColor) {
|
||||
@ -3040,7 +3148,7 @@ Licensed under the MIT license.
|
||||
return plot;
|
||||
};
|
||||
|
||||
$.plot.version = "0.8.1";
|
||||
$.plot.version = "0.8.3";
|
||||
|
||||
$.plot.plugins = [];
|
||||
|
||||
|
40
src/vendor/jquery/jquery.flot.stack.js
vendored
40
src/vendor/jquery/jquery.flot.stack.js
vendored
@ -1,6 +1,6 @@
|
||||
/* Flot plugin for stacking data sets rather than overlyaing them.
|
||||
|
||||
Copyright (c) 2007-2013 IOLA and Ole Laursen.
|
||||
Copyright (c) 2007-2014 IOLA and Ole Laursen.
|
||||
Licensed under the MIT license.
|
||||
|
||||
The plugin assumes the data is sorted on x (or y if stacking horizontally).
|
||||
@ -14,16 +14,16 @@ Two or more series are stacked when their "stack" attribute is set to the same
|
||||
key (which can be any number or string or just "true"). To specify the default
|
||||
stack, you can set the stack option like this:
|
||||
|
||||
series: {
|
||||
stack: null/false, true, or a key (number/string)
|
||||
}
|
||||
series: {
|
||||
stack: null/false, true, or a key (number/string)
|
||||
}
|
||||
|
||||
You can also specify it for a single series, like this:
|
||||
|
||||
$.plot( $("#placeholder"), [{
|
||||
data: [ ... ],
|
||||
stack: true
|
||||
}])
|
||||
$.plot( $("#placeholder"), [{
|
||||
data: [ ... ],
|
||||
stack: true
|
||||
}])
|
||||
|
||||
The stacking order is determined by the order of the data series in the array
|
||||
(later series end up on top of the previous).
|
||||
@ -39,21 +39,21 @@ charts or filled areas).
|
||||
var options = {
|
||||
series: { stack: null } // or number/string
|
||||
};
|
||||
|
||||
|
||||
function init(plot) {
|
||||
function findMatchingSeries(s, allseries) {
|
||||
var res = null;
|
||||
for (var i = 0; i < allseries.length; ++i) {
|
||||
if (s == allseries[i])
|
||||
break;
|
||||
|
||||
|
||||
if (allseries[i].stack == s.stack)
|
||||
res = allseries[i];
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
function stackData(plot, s, datapoints) {
|
||||
if (s.stack == null || s.stack === false)
|
||||
return;
|
||||
@ -118,7 +118,7 @@ charts or filled areas).
|
||||
|
||||
newpoints[l + accumulateOffset] += qy;
|
||||
bottom = qy;
|
||||
|
||||
|
||||
i += ps;
|
||||
j += otherps;
|
||||
}
|
||||
@ -131,7 +131,7 @@ charts or filled areas).
|
||||
newpoints.push(intery + qy);
|
||||
for (m = 2; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
bottom = qy;
|
||||
bottom = qy;
|
||||
}
|
||||
|
||||
j += otherps;
|
||||
@ -142,22 +142,22 @@ charts or filled areas).
|
||||
i += ps;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
for (m = 0; m < ps; ++m)
|
||||
newpoints.push(points[i + m]);
|
||||
|
||||
|
||||
// we might be able to interpolate a point below,
|
||||
// this can give us a better y
|
||||
if (withlines && j > 0 && otherpoints[j - otherps] != null)
|
||||
bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx);
|
||||
|
||||
newpoints[l + accumulateOffset] += bottom;
|
||||
|
||||
|
||||
i += ps;
|
||||
}
|
||||
|
||||
fromgap = false;
|
||||
|
||||
|
||||
if (l != newpoints.length && withbottom)
|
||||
newpoints[l + 2] += bottom;
|
||||
}
|
||||
@ -175,10 +175,10 @@ charts or filled areas).
|
||||
|
||||
datapoints.points = newpoints;
|
||||
}
|
||||
|
||||
|
||||
plot.hooks.processDatapoints.push(stackData);
|
||||
}
|
||||
|
||||
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
|
Loading…
Reference in New Issue
Block a user