src/web/gui/src/dashboard.js/charting/gauge.js
// gauge.js
NETDATA.gaugeInitialize = function (callback) {
if (typeof netdataNoGauge === 'undefined' || !netdataNoGauge) {
$.ajax({
url: NETDATA.gauge_js,
cache: true,
dataType: "script",
xhrFields: {withCredentials: true} // required for the cookie
})
.done(function () {
NETDATA.registerChartLibrary('gauge', NETDATA.gauge_js);
})
.fail(function () {
NETDATA.chartLibraries.gauge.enabled = false;
NETDATA.error(100, NETDATA.gauge_js);
})
.always(function () {
if (typeof callback === "function") {
return callback();
}
})
}
else {
NETDATA.chartLibraries.gauge.enabled = false;
if (typeof callback === "function") {
return callback();
}
}
};
NETDATA.gaugeAnimation = function (state, status) {
let speed = 32;
if (typeof status === 'boolean' && status === false) {
speed = 1000000000;
} else if (typeof status === 'number') {
speed = status;
}
// console.log('gauge speed ' + speed);
state.tmp.gauge_instance.animationSpeed = speed;
state.tmp.___gaugeOld__.speed = speed;
};
NETDATA.gaugeSet = function (state, value, min, max) {
if (typeof value !== 'number') {
value = 0;
}
if (typeof min !== 'number') {
min = 0;
}
if (typeof max !== 'number') {
max = 0;
}
if (value > max) {
max = value;
}
if (value < min) {
min = value;
}
if (min > max) {
let t = min;
min = max;
max = t;
}
else if (min === max) {
max = min + 1;
}
state.legendFormatValueDecimalsFromMinMax(min, max);
// gauge.js has an issue if the needle
// is smaller than min or larger than max
// when we set the new values
// the needle will go crazy
// to prevent it, we always feed it
// with a percentage, so that the needle
// is always between min and max
let pcent = (value - min) * 100 / (max - min);
// bug fix for gauge.js 1.3.1
// if the value is the absolute min or max, the chart is broken
if (pcent < 0.001) {
pcent = 0.001;
}
if (pcent > 99.999) {
pcent = 99.999;
}
state.tmp.gauge_instance.set(pcent);
// console.log('gauge set ' + pcent + ', value ' + value + ', min ' + min + ', max ' + max);
state.tmp.___gaugeOld__.value = value;
state.tmp.___gaugeOld__.min = min;
state.tmp.___gaugeOld__.max = max;
};
NETDATA.gaugeSetLabels = function (state, value, min, max) {
if (state.tmp.___gaugeOld__.valueLabel !== value) {
state.tmp.___gaugeOld__.valueLabel = value;
state.tmp.gaugeChartLabel.innerText = state.legendFormatValue(value);
}
if (state.tmp.___gaugeOld__.minLabel !== min) {
state.tmp.___gaugeOld__.minLabel = min;
state.tmp.gaugeChartMin.innerText = state.legendFormatValue(min);
}
if (state.tmp.___gaugeOld__.maxLabel !== max) {
state.tmp.___gaugeOld__.maxLabel = max;
state.tmp.gaugeChartMax.innerText = state.legendFormatValue(max);
}
};
NETDATA.gaugeClearSelection = function (state, force) {
if (typeof state.tmp.gaugeEvent !== 'undefined' && typeof state.tmp.gaugeEvent.timer !== 'undefined') {
NETDATA.timeout.clear(state.tmp.gaugeEvent.timer);
state.tmp.gaugeEvent.timer = undefined;
}
if (state.isAutoRefreshable() && state.data !== null && force !== true) {
NETDATA.gaugeChartUpdate(state, state.data);
} else {
NETDATA.gaugeAnimation(state, false);
NETDATA.gaugeSetLabels(state, null, null, null);
NETDATA.gaugeSet(state, null, null, null);
}
NETDATA.gaugeAnimation(state, true);
return true;
};
NETDATA.gaugeSetSelection = function (state, t) {
if (state.timeIsVisible(t) !== true) {
return NETDATA.gaugeClearSelection(state, true);
}
let slot = state.calculateRowForTime(t);
if (slot < 0 || slot >= state.data.result.length) {
return NETDATA.gaugeClearSelection(state, true);
}
if (typeof state.tmp.gaugeEvent === 'undefined') {
state.tmp.gaugeEvent = {
timer: undefined,
value: 0,
min: 0,
max: 0
};
}
let value = state.data.result[state.data.result.length - 1 - slot];
let min = (state.tmp.gaugeMin === null) ? NETDATA.commonMin.get(state) : state.tmp.gaugeMin;
let max = (state.tmp.gaugeMax === null) ? NETDATA.commonMax.get(state) : state.tmp.gaugeMax;
// make sure it is zero based
// but only if it has not been set by the user
if (state.tmp.gaugeMin === null && min > 0) {
min = 0;
}
if (state.tmp.gaugeMax === null && max < 0) {
max = 0;
}
state.tmp.gaugeEvent.value = value;
state.tmp.gaugeEvent.min = min;
state.tmp.gaugeEvent.max = max;
NETDATA.gaugeSetLabels(state, value, min, max);
if (state.tmp.gaugeEvent.timer === undefined) {
NETDATA.gaugeAnimation(state, false);
state.tmp.gaugeEvent.timer = NETDATA.timeout.set(function () {
state.tmp.gaugeEvent.timer = undefined;
NETDATA.gaugeSet(state, state.tmp.gaugeEvent.value, state.tmp.gaugeEvent.min, state.tmp.gaugeEvent.max);
}, 0);
}
return true;
};
NETDATA.gaugeChartUpdate = function (state, data) {
let value, min, max;
if (NETDATA.globalPanAndZoom.isActive() || state.isAutoRefreshable() === false) {
NETDATA.gaugeSetLabels(state, null, null, null);
state.tmp.gauge_instance.set(0);
} else {
value = data.result[0];
min = (state.tmp.gaugeMin === null) ? NETDATA.commonMin.get(state) : state.tmp.gaugeMin;
max = (state.tmp.gaugeMax === null) ? NETDATA.commonMax.get(state) : state.tmp.gaugeMax;
if (value < min) {
min = value;
}
if (value > max) {
max = value;
}
// make sure it is zero based
// but only if it has not been set by the user
if (state.tmp.gaugeMin === null && min > 0) {
min = 0;
}
if (state.tmp.gaugeMax === null && max < 0) {
max = 0;
}
NETDATA.gaugeSet(state, value, min, max);
NETDATA.gaugeSetLabels(state, value, min, max);
}
return true;
};
NETDATA.gaugeChartCreate = function (state, data) {
// let chart = $(state.element_chart);
let value = data.result[0];
let min = NETDATA.dataAttribute(state.element, 'gauge-min-value', null);
let max = NETDATA.dataAttribute(state.element, 'gauge-max-value', null);
// let adjust = NETDATA.dataAttribute(state.element, 'gauge-adjust', null);
let pointerColor = NETDATA.dataAttribute(state.element, 'gauge-pointer-color', NETDATA.themes.current.gauge_pointer);
let strokeColor = NETDATA.dataAttribute(state.element, 'gauge-stroke-color', NETDATA.themes.current.gauge_stroke);
let startColor = NETDATA.dataAttribute(state.element, 'gauge-start-color', state.chartCustomColors()[0]);
let stopColor = NETDATA.dataAttribute(state.element, 'gauge-stop-color', void 0);
let generateGradient = NETDATA.dataAttribute(state.element, 'gauge-generate-gradient', false);
if (min === null) {
min = NETDATA.commonMin.get(state);
state.tmp.gaugeMin = null;
} else {
state.tmp.gaugeMin = min;
}
if (max === null) {
max = NETDATA.commonMax.get(state);
state.tmp.gaugeMax = null;
} else {
state.tmp.gaugeMax = max;
}
// make sure it is zero based
// but only if it has not been set by the user
if (state.tmp.gaugeMin === null && min > 0) {
min = 0;
}
if (state.tmp.gaugeMax === null && max < 0) {
max = 0;
}
let width = state.chartWidth(), height = state.chartHeight(); //, ratio = 1.5;
// console.log('gauge width: ' + width.toString() + ', height: ' + height.toString());
//switch(adjust) {
// case 'width': width = height * ratio; break;
// case 'height':
// default: height = width / ratio; break;
//}
//state.element.style.width = width.toString() + 'px';
//state.element.style.height = height.toString() + 'px';
let lum_d = 0.05;
let options = {
lines: 12, // The number of lines to draw
angle: 0.14, // The span of the gauge arc
lineWidth: 0.57, // The line thickness
radiusScale: 1.0, // Relative radius
pointer: {
length: 0.85, // 0.9 The radius of the inner circle
strokeWidth: 0.045, // The rotation offset
color: pointerColor // Fill color
},
limitMax: true, // If false, the max value of the gauge will be updated if value surpass max
limitMin: true, // If true, the min value of the gauge will be fixed unless you set it manually
colorStart: startColor, // Colors
colorStop: stopColor, // just experiment with them
strokeColor: strokeColor, // to see which ones work best for you
generateGradient: (generateGradient === true), // gmosx:
gradientType: 0,
highDpiSupport: true // High resolution support
};
if (generateGradient.constructor === Array) {
// example options:
// data-gauge-generate-gradient="[0, 50, 100]"
// data-gauge-gradient-percent-color-0="#FFFFFF"
// data-gauge-gradient-percent-color-50="#999900"
// data-gauge-gradient-percent-color-100="#000000"
options.percentColors = [];
let len = generateGradient.length;
while (len--) {
let pcent = generateGradient[len];
let color = NETDATA.dataAttribute(state.element, 'gauge-gradient-percent-color-' + pcent.toString(), false);
if (color !== false) {
let a = [];
a[0] = pcent / 100;
a[1] = color;
options.percentColors.unshift(a);
}
}
if (options.percentColors.length === 0) {
delete options.percentColors;
}
} else if (generateGradient === false && NETDATA.themes.current.gauge_gradient) {
//noinspection PointlessArithmeticExpressionJS
options.percentColors = [
[0.0, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 0))],
[0.1, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 1))],
[0.2, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 2))],
[0.3, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 3))],
[0.4, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 4))],
[0.5, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 5))],
[0.6, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 6))],
[0.7, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 7))],
[0.8, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 8))],
[0.9, NETDATA.colorLuminance(startColor, (lum_d * 10) - (lum_d * 9))],
[1.0, NETDATA.colorLuminance(startColor, 0.0)]];
}
state.tmp.gauge_canvas = document.createElement('canvas');
state.tmp.gauge_canvas.id = 'gauge-' + state.uuid + '-canvas';
state.tmp.gauge_canvas.className = 'gaugeChart';
state.tmp.gauge_canvas.width = width;
state.tmp.gauge_canvas.height = height;
state.element_chart.appendChild(state.tmp.gauge_canvas);
let valuefontsize = Math.floor(height / 5);
let valuetop = Math.round((height - valuefontsize) / 3.2);
state.tmp.gaugeChartLabel = document.createElement('span');
state.tmp.gaugeChartLabel.className = 'gaugeChartLabel';
state.tmp.gaugeChartLabel.style.fontSize = valuefontsize + 'px';
state.tmp.gaugeChartLabel.style.top = valuetop.toString() + 'px';
state.element_chart.appendChild(state.tmp.gaugeChartLabel);
let titlefontsize = Math.round(valuefontsize / 2.1);
let titletop = 0;
state.tmp.gaugeChartTitle = document.createElement('span');
state.tmp.gaugeChartTitle.className = 'gaugeChartTitle';
state.tmp.gaugeChartTitle.innerText = state.title;
state.tmp.gaugeChartTitle.style.fontSize = titlefontsize + 'px';
state.tmp.gaugeChartTitle.style.lineHeight = titlefontsize + 'px';
state.tmp.gaugeChartTitle.style.top = titletop.toString() + 'px';
state.element_chart.appendChild(state.tmp.gaugeChartTitle);
let unitfontsize = Math.round(titlefontsize * 0.9);
state.tmp.gaugeChartUnits = document.createElement('span');
state.tmp.gaugeChartUnits.className = 'gaugeChartUnits';
state.tmp.gaugeChartUnits.innerText = state.units_current;
state.tmp.gaugeChartUnits.style.fontSize = unitfontsize + 'px';
state.element_chart.appendChild(state.tmp.gaugeChartUnits);
state.tmp.gaugeChartMin = document.createElement('span');
state.tmp.gaugeChartMin.className = 'gaugeChartMin';
state.tmp.gaugeChartMin.style.fontSize = Math.round(valuefontsize * 0.75).toString() + 'px';
state.element_chart.appendChild(state.tmp.gaugeChartMin);
state.tmp.gaugeChartMax = document.createElement('span');
state.tmp.gaugeChartMax.className = 'gaugeChartMax';
state.tmp.gaugeChartMax.style.fontSize = Math.round(valuefontsize * 0.75).toString() + 'px';
state.element_chart.appendChild(state.tmp.gaugeChartMax);
// when we just re-create the chart
// do not animate the first update
let animate = true;
if (typeof state.tmp.gauge_instance !== 'undefined') {
animate = false;
}
state.tmp.gauge_instance = new Gauge(state.tmp.gauge_canvas).setOptions(options); // create sexy gauge!
state.tmp.___gaugeOld__ = {
value: value,
min: min,
max: max,
valueLabel: null,
minLabel: null,
maxLabel: null
};
// we will always feed a percentage
state.tmp.gauge_instance.minValue = 0;
state.tmp.gauge_instance.maxValue = 100;
NETDATA.gaugeAnimation(state, animate);
NETDATA.gaugeSet(state, value, min, max);
NETDATA.gaugeSetLabels(state, value, min, max);
NETDATA.gaugeAnimation(state, true);
state.legendSetUnitsString = function (units) {
if (typeof state.tmp.gaugeChartUnits !== 'undefined' && state.tmp.units !== units) {
state.tmp.gaugeChartUnits.innerText = units;
state.tmp.___gaugeOld__.valueLabel = null;
state.tmp.___gaugeOld__.minLabel = null;
state.tmp.___gaugeOld__.maxLabel = null;
state.tmp.units = units;
}
};
state.legendShowUndefined = function () {
if (typeof state.tmp.gauge_instance !== 'undefined') {
NETDATA.gaugeClearSelection(state);
}
};
return true;
};