Closer to the goal!
parent
c2b5d3bc9d
commit
db13d42818
|
@ -110,7 +110,6 @@
|
|||
'no-new': 2,
|
||||
'no-octal-escape': 2,
|
||||
'no-octal': 2,
|
||||
'no-param-reassign': 2,
|
||||
'no-proto': 2,
|
||||
'no-redeclare': 2,
|
||||
'no-script-url': 2,
|
||||
|
|
|
@ -4,7 +4,6 @@ import AutoRefresh from 'shared/components/AutoRefresh';
|
|||
import LineGraph from 'shared/components/LineGraph';
|
||||
const RefreshingLineGraph = AutoRefresh(LineGraph);
|
||||
|
||||
const OUT_OF_RANGE = "out of range";
|
||||
export const RuleGraph = React.createClass({
|
||||
propTypes: {
|
||||
source: PropTypes.shape({
|
||||
|
@ -40,32 +39,14 @@ export const RuleGraph = React.createClass({
|
|||
);
|
||||
}
|
||||
|
||||
const {value, rangeValue, operator} = rule.values;
|
||||
const tenPercent = 0.1;
|
||||
let lower, upper;
|
||||
let upperRange, lowerRange;
|
||||
|
||||
if (value !== "" && operator === OUT_OF_RANGE) {
|
||||
lower = Math.min(+rule.values.rangeValue, +rule.values.value);
|
||||
lowerRange = lower ? lower + lower * tenPercent : null;
|
||||
}
|
||||
|
||||
if (rangeValue !== "" && operator === OUT_OF_RANGE) {
|
||||
upper = Math.max(+rule.values.rangeValue, +rule.values.value);
|
||||
upperRange = upper ? upper + upper * tenPercent : null;
|
||||
}
|
||||
|
||||
// if either value is null, Dygraph will choose a sensible default
|
||||
const range = {y: [lowerRange, upperRange]};
|
||||
|
||||
return (
|
||||
<RefreshingLineGraph
|
||||
ranges={range}
|
||||
queries={queries}
|
||||
autoRefresh={autoRefreshMs}
|
||||
underlayCallback={this.createUnderlayCallback()}
|
||||
isGraphFilled={false}
|
||||
overrideLineColors={kapacitorLineColors}
|
||||
ruleValues={rule.values}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
|
@ -2,7 +2,13 @@
|
|||
import React, {PropTypes} from 'react';
|
||||
import Dygraph from '../../external/dygraph';
|
||||
|
||||
const {arrayOf, object, array, number, bool, shape} = PropTypes;
|
||||
const {
|
||||
array,
|
||||
arrayOf,
|
||||
number,
|
||||
bool,
|
||||
shape,
|
||||
} = PropTypes;
|
||||
|
||||
const LINE_COLORS = [
|
||||
'#00C9FF',
|
||||
|
@ -28,13 +34,14 @@ export default React.createClass({
|
|||
y: arrayOf(number),
|
||||
y2: arrayOf(number),
|
||||
}),
|
||||
timeSeries: array.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
labels: array.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||
options: object, // eslint-disable-line react/forbid-prop-types
|
||||
containerStyle: object, // eslint-disable-line react/forbid-prop-types
|
||||
timeSeries: array.isRequired,
|
||||
labels: array.isRequired,
|
||||
options: shape({}),
|
||||
containerStyle: shape({}),
|
||||
isGraphFilled: bool,
|
||||
overrideLineColors: array,
|
||||
dygraphSeries: shape({}).isRequired,
|
||||
ruleValues: shape({}),
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
|
@ -54,7 +61,7 @@ export default React.createClass({
|
|||
componentDidMount() {
|
||||
const timeSeries = this.getTimeSeries();
|
||||
// dygraphSeries is a legend label and its corresponding y-axis e.g. {legendLabel1: 'y', legendLabel2: 'y2'};
|
||||
const {ranges, dygraphSeries} = this.props;
|
||||
const {ranges, dygraphSeries, ruleValues} = this.props;
|
||||
|
||||
const refs = this.refs;
|
||||
const graphContainerNode = refs.graphContainer;
|
||||
|
@ -81,7 +88,7 @@ export default React.createClass({
|
|||
series: dygraphSeries,
|
||||
axes: {
|
||||
y: {
|
||||
valueRange: getRange(timeSeries, ranges.y),
|
||||
valueRange: getRange(timeSeries, ranges.y, ruleValues.value, ruleValues.rangeValue),
|
||||
},
|
||||
y2: {
|
||||
valueRange: getRange(timeSeries, ranges.y2),
|
||||
|
@ -141,14 +148,14 @@ export default React.createClass({
|
|||
}
|
||||
|
||||
const timeSeries = this.getTimeSeries();
|
||||
const {labels, ranges, options, dygraphSeries} = this.props;
|
||||
const {labels, ranges, options, dygraphSeries, ruleValues} = this.props;
|
||||
|
||||
dygraph.updateOptions({
|
||||
labels,
|
||||
file: timeSeries,
|
||||
axes: {
|
||||
y: {
|
||||
valueRange: getRange(timeSeries, ranges.y),
|
||||
valueRange: getRange(timeSeries, ranges.y, ruleValues.value, ruleValues.rangeValue),
|
||||
},
|
||||
y2: {
|
||||
valueRange: getRange(timeSeries, ranges.y2),
|
||||
|
@ -172,15 +179,28 @@ export default React.createClass({
|
|||
},
|
||||
});
|
||||
|
||||
function getRange(timeSeries, override) {
|
||||
const TEN_PERCENT = 0.1;
|
||||
|
||||
function getRange(timeSeries, override, value = null, rangeValue = null) {
|
||||
if (override) {
|
||||
return override;
|
||||
}
|
||||
|
||||
let max = null;
|
||||
let min = null;
|
||||
const addPadding = (val) => {
|
||||
if (val === null || val === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
timeSeries.forEach((series) => {
|
||||
if (val < 0) {
|
||||
return val - val * TEN_PERCENT;
|
||||
}
|
||||
|
||||
return val + val * TEN_PERCENT;
|
||||
};
|
||||
|
||||
const points = [...timeSeries, [null, addPadding(value)], [null, addPadding(rangeValue)]];
|
||||
|
||||
const range = points.reduce(([min, max], series) => {
|
||||
for (let i = 1; i < series.length; i++) {
|
||||
const val = series[i];
|
||||
|
||||
|
@ -196,13 +216,15 @@ function getRange(timeSeries, override) {
|
|||
min = Math.min(min, val);
|
||||
max = Math.max(max, val);
|
||||
}
|
||||
|
||||
return [min, max];
|
||||
}
|
||||
});
|
||||
}, [null, null]);
|
||||
|
||||
// Dygraph will not reliably plot X / Y axis labels if min and max are both 0
|
||||
if (min === 0 && max === 0) {
|
||||
if (range[0] === 0 && range[1] === 0) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
return [min, max];
|
||||
return range;
|
||||
}
|
||||
|
|
|
@ -7,23 +7,34 @@ import _ from 'lodash';
|
|||
import timeSeriesToDygraph from 'utils/timeSeriesToDygraph';
|
||||
import lastValues from 'src/shared/parsing/lastValues';
|
||||
|
||||
const {
|
||||
array,
|
||||
arrayOf,
|
||||
number,
|
||||
bool,
|
||||
shape,
|
||||
string,
|
||||
func,
|
||||
} = PropTypes;
|
||||
|
||||
export default React.createClass({
|
||||
displayName: 'LineGraph',
|
||||
propTypes: {
|
||||
data: PropTypes.arrayOf(PropTypes.shape({}).isRequired).isRequired,
|
||||
ranges: PropTypes.shape({
|
||||
y: PropTypes.arrayOf(PropTypes.number),
|
||||
y2: PropTypes.arrayOf(PropTypes.number),
|
||||
data: arrayOf(shape({}).isRequired).isRequired,
|
||||
ranges: shape({
|
||||
y: arrayOf(number),
|
||||
y2: arrayOf(number),
|
||||
}),
|
||||
title: PropTypes.string,
|
||||
isFetchingInitially: PropTypes.bool,
|
||||
isRefreshing: PropTypes.bool,
|
||||
underlayCallback: PropTypes.func,
|
||||
isGraphFilled: PropTypes.bool,
|
||||
overrideLineColors: PropTypes.array,
|
||||
queries: PropTypes.arrayOf(PropTypes.shape({}).isRequired).isRequired,
|
||||
showSingleStat: PropTypes.bool,
|
||||
activeQueryIndex: PropTypes.number,
|
||||
title: string,
|
||||
isFetchingInitially: bool,
|
||||
isRefreshing: bool,
|
||||
underlayCallback: func,
|
||||
isGraphFilled: bool,
|
||||
overrideLineColors: array,
|
||||
queries: arrayOf(shape({}).isRequired).isRequired,
|
||||
showSingleStat: bool,
|
||||
activeQueryIndex: number,
|
||||
ruleValues: shape({}),
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
|
@ -50,7 +61,7 @@ export default React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
const {data, ranges, isFetchingInitially, isRefreshing, isGraphFilled, overrideLineColors, title, underlayCallback, queries, showSingleStat} = this.props;
|
||||
const {data, ranges, isFetchingInitially, isRefreshing, isGraphFilled, overrideLineColors, title, underlayCallback, queries, showSingleStat, ruleValues} = this.props;
|
||||
const {labels, timeSeries, dygraphSeries} = this._timeSeries;
|
||||
|
||||
// If data for this graph is being fetched for the first time, show a graph-wide spinner.
|
||||
|
@ -99,6 +110,7 @@ export default React.createClass({
|
|||
options={options}
|
||||
dygraphSeries={dygraphSeries}
|
||||
ranges={ranges || this.getRanges()}
|
||||
ruleValues={ruleValues}
|
||||
/>
|
||||
{showSingleStat ? <div className="graph-single-stat single-stat">{roundedValue}</div> : null}
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue