src/web/gui/src/dashboard.js/charting/d3pie.js
// d3pie
NETDATA.d3pieInitialize = function (callback) {
if (typeof netdataNoD3pie === 'undefined' || !netdataNoD3pie) {
// d3pie requires D3
if (!NETDATA.chartLibraries.d3.initialized) {
if (NETDATA.chartLibraries.d3.enabled) {
NETDATA.d3Initialize(function () {
NETDATA.d3pieInitialize(callback);
});
} else {
NETDATA.chartLibraries.d3pie.enabled = false;
if (typeof callback === "function") {
return callback();
}
}
} else {
$.ajax({
url: NETDATA.d3pie_js,
cache: true,
dataType: "script",
xhrFields: {withCredentials: true} // required for the cookie
})
.done(function () {
NETDATA.registerChartLibrary('d3pie', NETDATA.d3pie_js);
})
.fail(function () {
NETDATA.chartLibraries.d3pie.enabled = false;
NETDATA.error(100, NETDATA.d3pie_js);
})
.always(function () {
if (typeof callback === "function") {
return callback();
}
});
}
} else {
NETDATA.chartLibraries.d3pie.enabled = false;
if (typeof callback === "function") {
return callback();
}
}
};
NETDATA.d3pieSetContent = function (state, data, index) {
state.legendFormatValueDecimalsFromMinMax(
data.min,
data.max
);
let content = [];
let colors = state.chartColors();
let len = data.result.labels.length;
for (let i = 1; i < len; i++) {
let label = data.result.labels[i];
let value = data.result.data[index][label];
let color = colors[i - 1];
if (value !== null && value > 0) {
content.push({
label: label,
value: value,
color: color
});
}
}
if (content.length === 0) {
content.push({
label: 'no data',
value: 100,
color: '#666666'
});
}
state.tmp.d3pie_last_slot = index;
return content;
};
NETDATA.d3pieDateRange = function (state, data, index) {
let dt = Math.round((data.before - data.after + 1) / data.points);
let dt_str = NETDATA.seconds4human(dt);
let before = data.result.data[index].time;
let after = before - (dt * 1000);
let d1 = NETDATA.dateTime.localeDateString(after);
let t1 = NETDATA.dateTime.localeTimeString(after);
let d2 = NETDATA.dateTime.localeDateString(before);
let t2 = NETDATA.dateTime.localeTimeString(before);
if (d1 === d2) {
return d1 + ' ' + t1 + ' to ' + t2 + ', ' + dt_str;
}
return d1 + ' ' + t1 + ' to ' + d2 + ' ' + t2 + ', ' + dt_str;
};
NETDATA.d3pieSetSelection = function (state, t) {
if (state.timeIsVisible(t) !== true) {
return NETDATA.d3pieClearSelection(state, true);
}
let slot = state.calculateRowForTime(t);
slot = state.data.result.data.length - slot - 1;
if (slot < 0 || slot >= state.data.result.length) {
return NETDATA.d3pieClearSelection(state, true);
}
if (state.tmp.d3pie_last_slot === slot) {
// we already show this slot, don't do anything
return true;
}
if (state.tmp.d3pie_timer === undefined) {
state.tmp.d3pie_timer = NETDATA.timeout.set(function () {
state.tmp.d3pie_timer = undefined;
NETDATA.d3pieChange(state, NETDATA.d3pieSetContent(state, state.data, slot), NETDATA.d3pieDateRange(state, state.data, slot));
}, 0);
}
return true;
};
NETDATA.d3pieClearSelection = function (state, force) {
if (typeof state.tmp.d3pie_timer !== 'undefined') {
NETDATA.timeout.clear(state.tmp.d3pie_timer);
state.tmp.d3pie_timer = undefined;
}
if (state.isAutoRefreshable() && state.data !== null && force !== true) {
NETDATA.d3pieChartUpdate(state, state.data);
} else {
if (state.tmp.d3pie_last_slot !== -1) {
state.tmp.d3pie_last_slot = -1;
NETDATA.d3pieChange(state, [{label: 'no data', value: 1, color: '#666666'}], 'no data available');
}
}
return true;
};
NETDATA.d3pieChange = function (state, content, footer) {
if (state.d3pie_forced_subtitle === null) {
//state.d3pie_instance.updateProp("header.subtitle.text", state.units_current);
state.d3pie_instance.options.header.subtitle.text = state.units_current;
}
if (state.d3pie_forced_footer === null) {
//state.d3pie_instance.updateProp("footer.text", footer);
state.d3pie_instance.options.footer.text = footer;
}
//state.d3pie_instance.updateProp("data.content", content);
state.d3pie_instance.options.data.content = content;
state.d3pie_instance.destroy();
state.d3pie_instance.recreate();
return true;
};
NETDATA.d3pieChartUpdate = function (state, data) {
return NETDATA.d3pieChange(state, NETDATA.d3pieSetContent(state, data, 0), NETDATA.d3pieDateRange(state, data, 0));
};
NETDATA.d3pieChartCreate = function (state, data) {
state.element_chart.id = 'd3pie-' + state.uuid;
// console.log('id = ' + state.element_chart.id);
let content = NETDATA.d3pieSetContent(state, data, 0);
state.d3pie_forced_title = NETDATA.dataAttribute(state.element, 'd3pie-title', null);
state.d3pie_forced_subtitle = NETDATA.dataAttribute(state.element, 'd3pie-subtitle', null);
state.d3pie_forced_footer = NETDATA.dataAttribute(state.element, 'd3pie-footer', null);
state.d3pie_options = {
header: {
title: {
text: (state.d3pie_forced_title !== null) ? state.d3pie_forced_title : state.title,
color: NETDATA.dataAttribute(state.element, 'd3pie-title-color', NETDATA.themes.current.d3pie.title),
fontSize: NETDATA.dataAttribute(state.element, 'd3pie-title-fontsize', 12),
fontWeight: NETDATA.dataAttribute(state.element, 'd3pie-title-fontweight', "bold"),
font: NETDATA.dataAttribute(state.element, 'd3pie-title-font', "arial")
},
subtitle: {
text: (state.d3pie_forced_subtitle !== null) ? state.d3pie_forced_subtitle : state.units_current,
color: NETDATA.dataAttribute(state.element, 'd3pie-subtitle-color', NETDATA.themes.current.d3pie.subtitle),
fontSize: NETDATA.dataAttribute(state.element, 'd3pie-subtitle-fontsize', 10),
fontWeight: NETDATA.dataAttribute(state.element, 'd3pie-subtitle-fontweight', "normal"),
font: NETDATA.dataAttribute(state.element, 'd3pie-subtitle-font', "arial")
},
titleSubtitlePadding: 1
},
footer: {
text: (state.d3pie_forced_footer !== null) ? state.d3pie_forced_footer : NETDATA.d3pieDateRange(state, data, 0),
color: NETDATA.dataAttribute(state.element, 'd3pie-footer-color', NETDATA.themes.current.d3pie.footer),
fontSize: NETDATA.dataAttribute(state.element, 'd3pie-footer-fontsize', 9),
fontWeight: NETDATA.dataAttribute(state.element, 'd3pie-footer-fontweight', "bold"),
font: NETDATA.dataAttribute(state.element, 'd3pie-footer-font', "arial"),
location: NETDATA.dataAttribute(state.element, 'd3pie-footer-location', "bottom-center") // bottom-left, bottom-center, bottom-right
},
size: {
canvasHeight: state.chartHeight(),
canvasWidth: state.chartWidth(),
pieInnerRadius: NETDATA.dataAttribute(state.element, 'd3pie-pieinnerradius', "45%"),
pieOuterRadius: NETDATA.dataAttribute(state.element, 'd3pie-pieouterradius', "80%")
},
data: {
// none, random, value-asc, value-desc, label-asc, label-desc
sortOrder: NETDATA.dataAttribute(state.element, 'd3pie-sortorder', "value-desc"),
smallSegmentGrouping: {
enabled: NETDATA.dataAttributeBoolean(state.element, "d3pie-smallsegmentgrouping-enabled", false),
value: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-value', 1),
// percentage, value
valueType: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-valuetype', "percentage"),
label: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-label', "other"),
color: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-color', NETDATA.themes.current.d3pie.other)
},
// REQUIRED! This is where you enter your pie data; it needs to be an array of objects
// of this form: { label: "label", value: 1.5, color: "#000000" } - color is optional
content: content
},
labels: {
outer: {
// label, value, percentage, label-value1, label-value2, label-percentage1, label-percentage2
format: NETDATA.dataAttribute(state.element, 'd3pie-labels-outer-format', "label-value1"),
hideWhenLessThanPercentage: NETDATA.dataAttribute(state.element, 'd3pie-labels-outer-hidewhenlessthanpercentage', null),
pieDistance: NETDATA.dataAttribute(state.element, 'd3pie-labels-outer-piedistance', 15)
},
inner: {
// label, value, percentage, label-value1, label-value2, label-percentage1, label-percentage2
format: NETDATA.dataAttribute(state.element, 'd3pie-labels-inner-format', "percentage"),
hideWhenLessThanPercentage: NETDATA.dataAttribute(state.element, 'd3pie-labels-inner-hidewhenlessthanpercentage', 2)
},
mainLabel: {
color: NETDATA.dataAttribute(state.element, 'd3pie-labels-mainLabel-color', NETDATA.themes.current.d3pie.mainlabel), // or 'segment' for dynamic color
font: NETDATA.dataAttribute(state.element, 'd3pie-labels-mainLabel-font', "arial"),
fontSize: NETDATA.dataAttribute(state.element, 'd3pie-labels-mainLabel-fontsize', 10),
fontWeight: NETDATA.dataAttribute(state.element, 'd3pie-labels-mainLabel-fontweight', "normal")
},
percentage: {
color: NETDATA.dataAttribute(state.element, 'd3pie-labels-percentage-color', NETDATA.themes.current.d3pie.percentage),
font: NETDATA.dataAttribute(state.element, 'd3pie-labels-percentage-font', "arial"),
fontSize: NETDATA.dataAttribute(state.element, 'd3pie-labels-percentage-fontsize', 10),
fontWeight: NETDATA.dataAttribute(state.element, 'd3pie-labels-percentage-fontweight', "bold"),
decimalPlaces: 0
},
value: {
color: NETDATA.dataAttribute(state.element, 'd3pie-labels-value-color', NETDATA.themes.current.d3pie.value),
font: NETDATA.dataAttribute(state.element, 'd3pie-labels-value-font', "arial"),
fontSize: NETDATA.dataAttribute(state.element, 'd3pie-labels-value-fontsize', 10),
fontWeight: NETDATA.dataAttribute(state.element, 'd3pie-labels-value-fontweight', "bold")
},
lines: {
enabled: NETDATA.dataAttributeBoolean(state.element, 'd3pie-labels-lines-enabled', true),
style: NETDATA.dataAttribute(state.element, 'd3pie-labels-lines-style', "curved"),
color: NETDATA.dataAttribute(state.element, 'd3pie-labels-lines-color', "segment") // "segment" or a hex color
},
truncation: {
enabled: NETDATA.dataAttributeBoolean(state.element, 'd3pie-labels-truncation-enabled', false),
truncateLength: NETDATA.dataAttribute(state.element, 'd3pie-labels-truncation-truncatelength', 30)
},
formatter: function (context) {
// console.log(context);
if (context.part === 'value') {
return state.legendFormatValue(context.value);
}
if (context.part === 'percentage') {
return context.label + '%';
}
return context.label;
}
},
effects: {
load: {
effect: "none", // none / default
speed: 0 // commented in the d3pie code to speed it up
},
pullOutSegmentOnClick: {
effect: "bounce", // none / linear / bounce / elastic / back
speed: 400,
size: 5
},
highlightSegmentOnMouseover: true,
highlightLuminosity: -0.2
},
tooltips: {
enabled: false,
type: "placeholder", // caption|placeholder
string: "",
placeholderParser: null, // function
styles: {
fadeInSpeed: 250,
backgroundColor: NETDATA.themes.current.d3pie.tooltip_bg,
backgroundOpacity: 0.5,
color: NETDATA.themes.current.d3pie.tooltip_fg,
borderRadius: 2,
font: "arial",
fontSize: 12,
padding: 4
}
},
misc: {
colors: {
background: 'transparent', // transparent or color #
// segments: state.chartColors(),
segmentStroke: NETDATA.dataAttribute(state.element, 'd3pie-misc-colors-segmentstroke', NETDATA.themes.current.d3pie.segment_stroke)
},
gradient: {
enabled: NETDATA.dataAttributeBoolean(state.element, 'd3pie-misc-gradient-enabled', false),
percentage: NETDATA.dataAttribute(state.element, 'd3pie-misc-colors-percentage', 95),
color: NETDATA.dataAttribute(state.element, 'd3pie-misc-gradient-color', NETDATA.themes.current.d3pie.gradient_color)
},
canvasPadding: {
top: 5,
right: 5,
bottom: 5,
left: 5
},
pieCenterOffset: {
x: 0,
y: 0
},
cssPrefix: NETDATA.dataAttribute(state.element, 'd3pie-cssprefix', null)
},
callbacks: {
onload: null,
onMouseoverSegment: null,
onMouseoutSegment: null,
onClickSegment: null
}
};
state.d3pie_instance = new d3pie(state.element_chart, state.d3pie_options);
return true;
};