mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-02 00:40:10 +00:00
Added Vite to frontend builds
This commit is contained in:
parent
daf007c161
commit
2b5d2d7949
118 changed files with 10172 additions and 34001 deletions
|
|
@ -2,446 +2,462 @@
|
|||
|
||||
// Wrapper function
|
||||
export function do_pie(name, update_url, url_params, units, refresh) {
|
||||
var pie = new PieChart(name, update_url, url_params, units, refresh);
|
||||
if (refresh)
|
||||
pie.setInterval(setInterval(function () { pie.update(); }, refresh));
|
||||
const pie = new PieChart(name, update_url, url_params, units, refresh);
|
||||
if (refresh) {
|
||||
pie.setInterval(setInterval(function() {
|
||||
pie.update();
|
||||
}, refresh));
|
||||
}
|
||||
|
||||
// Return new class instance, with
|
||||
return pie;
|
||||
// Return new class instance, with
|
||||
return pie;
|
||||
}
|
||||
|
||||
function PieChart(name, update_url, url_params, units, refresh) {
|
||||
// Add object properties like this
|
||||
this.name = name;
|
||||
this.update_url = update_url;
|
||||
this.url_params = url_params;
|
||||
this.units = units;
|
||||
this.refresh = refresh;
|
||||
|
||||
// Add object properties like this
|
||||
this.name = name;
|
||||
this.update_url = update_url;
|
||||
this.url_params = url_params;
|
||||
this.units = units;
|
||||
this.refresh = refresh;
|
||||
let streakerDataAdded = [];
|
||||
let paths = '';
|
||||
let lines = [];
|
||||
let valueLabels = [];
|
||||
let nameLabels = [];
|
||||
|
||||
let streakerDataAdded = []
|
||||
let paths = ""
|
||||
let lines = []
|
||||
let valueLabels = []
|
||||
let nameLabels = []
|
||||
|
||||
var pieData = [];
|
||||
var oldPieData = [];
|
||||
var filteredPieData = [];
|
||||
var rsp = create_pie_chart(name, units);
|
||||
var arc_group = rsp[0];
|
||||
var donut = rsp[1];
|
||||
var totalValue = rsp[2];
|
||||
var totalUnits = rsp[3];
|
||||
var color = rsp[4];
|
||||
var tweenDuration = rsp[5];
|
||||
var arc = rsp[6];
|
||||
var label_group = rsp[7];
|
||||
var center_group = rsp[8];
|
||||
var r = rsp[9];
|
||||
var textOffset = rsp[10];
|
||||
let pieData = [];
|
||||
let oldPieData = [];
|
||||
let filteredPieData = [];
|
||||
const rsp = create_pie_chart(name, units);
|
||||
const arc_group = rsp[0];
|
||||
const donut = rsp[1];
|
||||
const totalValue = rsp[2];
|
||||
const totalUnits = rsp[3];
|
||||
const color = rsp[4];
|
||||
const tweenDuration = rsp[5];
|
||||
const arc = rsp[6];
|
||||
const label_group = rsp[7];
|
||||
const center_group = rsp[8];
|
||||
const r = rsp[9];
|
||||
const textOffset = rsp[10];
|
||||
|
||||
|
||||
// to run each time data is generated
|
||||
// to run each time data is generated
|
||||
|
||||
this.update = function () {
|
||||
// console.log(this.name);
|
||||
// console.log(this.url_params);
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: this.update_url,
|
||||
data: this.url_params,
|
||||
success: function (content) {
|
||||
let parsed_content;
|
||||
this.update = function() {
|
||||
// console.log(this.name);
|
||||
// console.log(this.url_params);
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: this.update_url,
|
||||
data: this.url_params,
|
||||
success: function(content) {
|
||||
let parsed_content;
|
||||
|
||||
if (typeof (content) == "object")
|
||||
parsed_content = content;
|
||||
else if (typeof (content) == "string")
|
||||
parsed_content = jQuery.parseJSON(content);
|
||||
if (typeof (content) == 'object') {
|
||||
parsed_content = content;
|
||||
} else if (typeof (content) == 'string') {
|
||||
parsed_content = jQuery.parseJSON(content);
|
||||
}
|
||||
|
||||
if (parsed_content)
|
||||
update_pie_chart(parsed_content);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (parsed_content) {
|
||||
update_pie_chart(parsed_content);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// STREAKER CONNECTION ////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
// STREAKER CONNECTION ////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
|
||||
// Needed to draw the pie immediately
|
||||
this.update();
|
||||
this.update();
|
||||
// Needed to draw the pie immediately
|
||||
this.update();
|
||||
this.update();
|
||||
|
||||
// var updateInterval = window.setInterval(update, refresh);
|
||||
// var updateInterval = window.setInterval(update, refresh);
|
||||
|
||||
function compare_by_label(a, b) {
|
||||
if (a.label < b.label) {
|
||||
return -1;
|
||||
} else if (a.label > b.label) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
function compare_by_label(a, b) {
|
||||
if (a.label < b.label) {
|
||||
return -1;
|
||||
} else if (a.label > b.label) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function update_pie_chart(data) {
|
||||
if (data.rsp) // detect REST API v1
|
||||
data = data.rsp;
|
||||
function update_pie_chart(data) {
|
||||
if (data.rsp) // detect REST API v1
|
||||
{
|
||||
data = data.rsp;
|
||||
}
|
||||
|
||||
data.sort(compare_by_label);
|
||||
streakerDataAdded = data;
|
||||
oldPieData = filteredPieData;
|
||||
pieData = donut(streakerDataAdded);
|
||||
data.sort(compare_by_label);
|
||||
streakerDataAdded = data;
|
||||
oldPieData = filteredPieData;
|
||||
pieData = donut(streakerDataAdded);
|
||||
|
||||
var totalOctets = 0;
|
||||
filteredPieData = pieData.filter(filterData);
|
||||
function filterData(element, index, array) {
|
||||
element.name = streakerDataAdded[index].label;
|
||||
element.value = streakerDataAdded[index].value;
|
||||
element.url = streakerDataAdded[index].url;
|
||||
totalOctets += element.value;
|
||||
return (element.value > 0);
|
||||
}
|
||||
let totalOctets = 0;
|
||||
filteredPieData = pieData.filter(filterData);
|
||||
function filterData(element, index, array) {
|
||||
element.name = streakerDataAdded[index].label;
|
||||
element.value = streakerDataAdded[index].value;
|
||||
element.url = streakerDataAdded[index].url;
|
||||
totalOctets += element.value;
|
||||
return (element.value > 0);
|
||||
}
|
||||
|
||||
if ((filteredPieData.length > 0) && (oldPieData.length > 0)) {
|
||||
//REMOVE PLACEHOLDER CIRCLE
|
||||
arc_group.selectAll("circle").remove();
|
||||
if ((filteredPieData.length > 0) && (oldPieData.length > 0)) {
|
||||
// REMOVE PLACEHOLDER CIRCLE
|
||||
arc_group.selectAll('circle').remove();
|
||||
|
||||
if (totalValue) {
|
||||
totalValue.text(function () {
|
||||
var kb = totalOctets / 1024;
|
||||
return kb.toFixed(1);
|
||||
//return bchart.label.abbreviated(totalOctets*8);
|
||||
});
|
||||
}
|
||||
if (totalValue) {
|
||||
totalValue.text(function() {
|
||||
const kb = totalOctets / 1024;
|
||||
return kb.toFixed(1);
|
||||
// return bchart.label.abbreviated(totalOctets*8);
|
||||
});
|
||||
}
|
||||
|
||||
//DRAW ARC PATHS
|
||||
paths = arc_group.selectAll("path").data(filteredPieData);
|
||||
paths.enter().append("svg:path")
|
||||
.attr("stroke", "white")
|
||||
.attr("stroke-width", 0.5)
|
||||
.attr("fill", function (d, i) { return color(i); })
|
||||
.transition()
|
||||
.duration(tweenDuration)
|
||||
.attrTween("d", pieTween);
|
||||
paths
|
||||
.transition()
|
||||
.duration(tweenDuration)
|
||||
.attrTween("d", pieTween);
|
||||
paths.exit()
|
||||
.transition()
|
||||
.duration(tweenDuration)
|
||||
.attrTween("d", removePieTween)
|
||||
.remove();
|
||||
// DRAW ARC PATHS
|
||||
paths = arc_group.selectAll('path').data(filteredPieData);
|
||||
paths.enter().append('svg:path')
|
||||
.attr('stroke', 'white')
|
||||
.attr('stroke-width', 0.5)
|
||||
.attr('fill', function(d, i) {
|
||||
return color(i);
|
||||
})
|
||||
.transition()
|
||||
.duration(tweenDuration)
|
||||
.attrTween('d', pieTween);
|
||||
paths
|
||||
.transition()
|
||||
.duration(tweenDuration)
|
||||
.attrTween('d', pieTween);
|
||||
paths.exit()
|
||||
.transition()
|
||||
.duration(tweenDuration)
|
||||
.attrTween('d', removePieTween)
|
||||
.remove();
|
||||
|
||||
//DRAW TICK MARK LINES FOR LABELS
|
||||
lines = label_group.selectAll("line").data(filteredPieData);
|
||||
lines.enter().append("svg:line")
|
||||
.attr("x1", 0)
|
||||
.attr("x2", 0)
|
||||
.attr("y1", -r - 3)
|
||||
.attr("y2", -r - 8)
|
||||
.attr("stroke", "gray")
|
||||
.attr("transform", function (d) {
|
||||
return "rotate(" + (d.startAngle + d.endAngle) / 2 * (180 / Math.PI) + ")";
|
||||
});
|
||||
lines.transition()
|
||||
.duration(tweenDuration)
|
||||
.attr("transform", function (d) {
|
||||
return "rotate(" + (d.startAngle + d.endAngle) / 2 * (180 / Math.PI) + ")";
|
||||
});
|
||||
lines.exit().remove();
|
||||
// DRAW TICK MARK LINES FOR LABELS
|
||||
lines = label_group.selectAll('line').data(filteredPieData);
|
||||
lines.enter().append('svg:line')
|
||||
.attr('x1', 0)
|
||||
.attr('x2', 0)
|
||||
.attr('y1', -r - 3)
|
||||
.attr('y2', -r - 8)
|
||||
.attr('stroke', 'gray')
|
||||
.attr('transform', function(d) {
|
||||
return 'rotate(' + (d.startAngle + d.endAngle) / 2 * (180 / Math.PI) + ')';
|
||||
});
|
||||
lines.transition()
|
||||
.duration(tweenDuration)
|
||||
.attr('transform', function(d) {
|
||||
return 'rotate(' + (d.startAngle + d.endAngle) / 2 * (180 / Math.PI) + ')';
|
||||
});
|
||||
lines.exit().remove();
|
||||
|
||||
//DRAW LABELS WITH PERCENTAGE VALUES
|
||||
valueLabels = label_group.selectAll("text.value").data(filteredPieData)
|
||||
.attr("dy", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 5;
|
||||
} else {
|
||||
return -7;
|
||||
}
|
||||
})
|
||||
.attr("text-anchor", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return "beginning";
|
||||
} else {
|
||||
return "end";
|
||||
}
|
||||
})
|
||||
.text(function (d) {
|
||||
// DRAW LABELS WITH PERCENTAGE VALUES
|
||||
valueLabels = label_group.selectAll('text.value').data(filteredPieData)
|
||||
.attr('dy', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 5;
|
||||
} else {
|
||||
return -7;
|
||||
}
|
||||
})
|
||||
.attr('text-anchor', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return 'beginning';
|
||||
} else {
|
||||
return 'end';
|
||||
}
|
||||
})
|
||||
.text(function(d) {
|
||||
const percentage = (d.value / totalOctets) * 100;
|
||||
// approssimate the number to the third deciaml digit and show only the first decimal
|
||||
const percentageLabel = percentage.toFixed(1) + '%';
|
||||
return percentageLabel;
|
||||
});
|
||||
|
||||
const percentage = (d.value / totalOctets) * 100;
|
||||
// approssimate the number to the third deciaml digit and show only the first decimal
|
||||
let percentageLabel = percentage.toFixed(1) + "%";
|
||||
return percentageLabel;
|
||||
});
|
||||
valueLabels.enter().append('svg:text')
|
||||
.attr('class', 'value')
|
||||
.attr('transform', function(d) {
|
||||
return 'translate(' + Math.cos(((d.startAngle + d.endAngle - Math.PI) / 2)) * (r + textOffset) + ',' + Math.sin((d.startAngle + d.endAngle - Math.PI) / 2) * (r + textOffset) + ')';
|
||||
})
|
||||
.attr('dy', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 5;
|
||||
} else {
|
||||
return -7;
|
||||
}
|
||||
})
|
||||
.attr('text-anchor', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return 'beginning';
|
||||
} else {
|
||||
return 'end';
|
||||
}
|
||||
}).text(function(d) {
|
||||
if (totalOctets <= 1) return '';
|
||||
const percentage = (d.value / totalOctets) * 100;
|
||||
const percentageLabel = percentage.toFixed(1) + '%';
|
||||
return percentageLabel;
|
||||
});
|
||||
|
||||
valueLabels.enter().append("svg:text")
|
||||
.attr("class", "value")
|
||||
.attr("transform", function (d) {
|
||||
return "translate(" + Math.cos(((d.startAngle + d.endAngle - Math.PI) / 2)) * (r + textOffset) + "," + Math.sin((d.startAngle + d.endAngle - Math.PI) / 2) * (r + textOffset) + ")";
|
||||
})
|
||||
.attr("dy", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 5;
|
||||
} else {
|
||||
return -7;
|
||||
}
|
||||
})
|
||||
.attr("text-anchor", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return "beginning";
|
||||
} else {
|
||||
return "end";
|
||||
}
|
||||
}).text(function (d) {
|
||||
if (totalOctets <= 1) return "";
|
||||
const percentage = (d.value / totalOctets) * 100;
|
||||
let percentageLabel = percentage.toFixed(1) + "%";
|
||||
return percentageLabel;
|
||||
});
|
||||
valueLabels.transition().duration(tweenDuration).attrTween('transform', textTween);
|
||||
valueLabels.exit().remove();
|
||||
|
||||
valueLabels.transition().duration(tweenDuration).attrTween("transform", textTween);
|
||||
valueLabels.exit().remove();
|
||||
// DRAW LABELS WITH ENTITY NAMES
|
||||
nameLabels = label_group.selectAll('text.units').data(filteredPieData)
|
||||
.attr('dy', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 17;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
})
|
||||
.attr('text-anchor', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return 'beginning';
|
||||
} else {
|
||||
return 'end';
|
||||
}
|
||||
}).text(function(d) {
|
||||
return d.name;
|
||||
})
|
||||
.on('click', function(d) {
|
||||
if (d.url) window.location.href = d.url;
|
||||
});
|
||||
|
||||
//DRAW LABELS WITH ENTITY NAMES
|
||||
nameLabels = label_group.selectAll("text.units").data(filteredPieData)
|
||||
.attr("dy", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 17;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
})
|
||||
.attr("text-anchor", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return "beginning";
|
||||
} else {
|
||||
return "end";
|
||||
}
|
||||
}).text(function (d) {
|
||||
return d.name;
|
||||
})
|
||||
.on("click", function (d) { if (d.url) window.location.href = d.url; });
|
||||
nameLabels.enter().append('svg:text')
|
||||
.attr('class', 'units')
|
||||
.attr('transform', function(d) {
|
||||
return 'translate(' + Math.cos(((d.startAngle + d.endAngle - Math.PI) / 2)) * (r + textOffset) + ',' + Math.sin((d.startAngle + d.endAngle - Math.PI) / 2) * (r + textOffset) + ')';
|
||||
})
|
||||
.attr('dy', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 17;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
})
|
||||
.attr('text-anchor', function(d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return 'beginning';
|
||||
} else {
|
||||
return 'end';
|
||||
}
|
||||
}).text(function(d) {
|
||||
return d.name;
|
||||
})
|
||||
.on('click', function(d) {
|
||||
if (d.url) window.location.href = d.url;
|
||||
});
|
||||
|
||||
nameLabels.enter().append("svg:text")
|
||||
.attr("class", "units")
|
||||
.attr("transform", function (d) {
|
||||
return "translate(" + Math.cos(((d.startAngle + d.endAngle - Math.PI) / 2)) * (r + textOffset) + "," + Math.sin((d.startAngle + d.endAngle - Math.PI) / 2) * (r + textOffset) + ")";
|
||||
})
|
||||
.attr("dy", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
|
||||
return 17;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
})
|
||||
.attr("text-anchor", function (d) {
|
||||
if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
|
||||
return "beginning";
|
||||
} else {
|
||||
return "end";
|
||||
}
|
||||
}).text(function (d) {
|
||||
return d.name;
|
||||
})
|
||||
.on("click", function (d) { if (d.url) window.location.href = d.url; });
|
||||
nameLabels.transition().duration(tweenDuration).attrTween('transform', textTween);
|
||||
|
||||
nameLabels.transition().duration(tweenDuration).attrTween("transform", textTween);
|
||||
nameLabels.exit().remove();
|
||||
}
|
||||
}
|
||||
|
||||
nameLabels.exit().remove();
|
||||
}
|
||||
}
|
||||
// /////////////////////////////////////////////////////////
|
||||
// FUNCTIONS //////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// FUNCTIONS //////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
// Interpolate the arcs in data space.
|
||||
function pieTween(d, i) {
|
||||
let s0;
|
||||
let e0;
|
||||
if (oldPieData[i]) {
|
||||
s0 = oldPieData[i].startAngle;
|
||||
e0 = oldPieData[i].endAngle;
|
||||
} else if (!(oldPieData[i]) && oldPieData[i - 1]) {
|
||||
s0 = oldPieData[i - 1].endAngle;
|
||||
e0 = oldPieData[i - 1].endAngle;
|
||||
} else if (!(oldPieData[i - 1]) && oldPieData.length > 0) {
|
||||
s0 = oldPieData[oldPieData.length - 1].endAngle;
|
||||
e0 = oldPieData[oldPieData.length - 1].endAngle;
|
||||
} else {
|
||||
s0 = 0;
|
||||
e0 = 0;
|
||||
}
|
||||
var i = d3.interpolate({startAngle: s0, endAngle: e0}, {startAngle: d.startAngle, endAngle: d.endAngle});
|
||||
return function(t) {
|
||||
const b = i(t);
|
||||
return arc(b);
|
||||
};
|
||||
}
|
||||
|
||||
// Interpolate the arcs in data space.
|
||||
function pieTween(d, i) {
|
||||
var s0;
|
||||
var e0;
|
||||
if (oldPieData[i]) {
|
||||
s0 = oldPieData[i].startAngle;
|
||||
e0 = oldPieData[i].endAngle;
|
||||
} else if (!(oldPieData[i]) && oldPieData[i - 1]) {
|
||||
s0 = oldPieData[i - 1].endAngle;
|
||||
e0 = oldPieData[i - 1].endAngle;
|
||||
} else if (!(oldPieData[i - 1]) && oldPieData.length > 0) {
|
||||
s0 = oldPieData[oldPieData.length - 1].endAngle;
|
||||
e0 = oldPieData[oldPieData.length - 1].endAngle;
|
||||
} else {
|
||||
s0 = 0;
|
||||
e0 = 0;
|
||||
}
|
||||
var i = d3.interpolate({ startAngle: s0, endAngle: e0 }, { startAngle: d.startAngle, endAngle: d.endAngle });
|
||||
return function (t) {
|
||||
var b = i(t);
|
||||
return arc(b);
|
||||
};
|
||||
}
|
||||
function removePieTween(d, i) {
|
||||
s0 = 2 * Math.PI;
|
||||
e0 = 2 * Math.PI;
|
||||
var i = d3.interpolate({startAngle: d.startAngle, endAngle: d.endAngle}, {startAngle: s0, endAngle: e0});
|
||||
return function(t) {
|
||||
const b = i(t);
|
||||
return arc(b);
|
||||
};
|
||||
}
|
||||
|
||||
function removePieTween(d, i) {
|
||||
s0 = 2 * Math.PI;
|
||||
e0 = 2 * Math.PI;
|
||||
var i = d3.interpolate({ startAngle: d.startAngle, endAngle: d.endAngle }, { startAngle: s0, endAngle: e0 });
|
||||
return function (t) {
|
||||
var b = i(t);
|
||||
return arc(b);
|
||||
};
|
||||
}
|
||||
|
||||
function textTween(d, i) {
|
||||
var a;
|
||||
if (oldPieData[i]) {
|
||||
a = (oldPieData[i].startAngle + oldPieData[i].endAngle - Math.PI) / 2;
|
||||
} else if (!(oldPieData[i]) && oldPieData[i - 1]) {
|
||||
a = (oldPieData[i - 1].startAngle + oldPieData[i - 1].endAngle - Math.PI) / 2;
|
||||
} else if (!(oldPieData[i - 1]) && oldPieData.length > 0) {
|
||||
a = (oldPieData[oldPieData.length - 1].startAngle + oldPieData[oldPieData.length - 1].endAngle - Math.PI) / 2;
|
||||
} else {
|
||||
a = 0;
|
||||
}
|
||||
var b = (d.startAngle + d.endAngle - Math.PI) / 2;
|
||||
|
||||
var fn = d3.interpolateNumber(a, b);
|
||||
return function (t) {
|
||||
var val = fn(t);
|
||||
return "translate(" + Math.cos(val) * (r + textOffset) + "," + Math.sin(val) * (r + textOffset) + ")";
|
||||
};
|
||||
}
|
||||
function textTween(d, i) {
|
||||
let a;
|
||||
if (oldPieData[i]) {
|
||||
a = (oldPieData[i].startAngle + oldPieData[i].endAngle - Math.PI) / 2;
|
||||
} else if (!(oldPieData[i]) && oldPieData[i - 1]) {
|
||||
a = (oldPieData[i - 1].startAngle + oldPieData[i - 1].endAngle - Math.PI) / 2;
|
||||
} else if (!(oldPieData[i - 1]) && oldPieData.length > 0) {
|
||||
a = (oldPieData[oldPieData.length - 1].startAngle + oldPieData[oldPieData.length - 1].endAngle - Math.PI) / 2;
|
||||
} else {
|
||||
a = 0;
|
||||
}
|
||||
const b = (d.startAngle + d.endAngle - Math.PI) / 2;
|
||||
|
||||
const fn = d3.interpolateNumber(a, b);
|
||||
return function(t) {
|
||||
const val = fn(t);
|
||||
return 'translate(' + Math.cos(val) * (r + textOffset) + ',' + Math.sin(val) * (r + textOffset) + ')';
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCIONTS ////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
PieChart.prototype.setUrlParams = function (url_params) {
|
||||
this.url_params = url_params;
|
||||
this.forceUpdate();
|
||||
}
|
||||
PieChart.prototype.setUrlParams = function(url_params) {
|
||||
this.url_params = url_params;
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
PieChart.prototype.forceUpdate = function (url_params) {
|
||||
this.stopInterval();
|
||||
this.update();
|
||||
this.startInterval();
|
||||
}
|
||||
PieChart.prototype.forceUpdate = function(url_params) {
|
||||
this.stopInterval();
|
||||
this.update();
|
||||
this.startInterval();
|
||||
};
|
||||
|
||||
PieChart.prototype.setInterval = function (p_pieInterval) {
|
||||
this.pieInterval = p_pieInterval;
|
||||
}
|
||||
PieChart.prototype.setInterval = function(p_pieInterval) {
|
||||
this.pieInterval = p_pieInterval;
|
||||
};
|
||||
|
||||
PieChart.prototype.stopInterval = function () {
|
||||
//disabled graph interval
|
||||
clearInterval(this.pieInterval);
|
||||
}
|
||||
PieChart.prototype.stopInterval = function() {
|
||||
// disabled graph interval
|
||||
clearInterval(this.pieInterval);
|
||||
};
|
||||
|
||||
PieChart.prototype.startInterval = function () {
|
||||
this.pieInterval = setInterval(this.update(), this.refresh)
|
||||
}
|
||||
///////////////////////////////////////////////////////////
|
||||
PieChart.prototype.startInterval = function() {
|
||||
this.pieInterval = setInterval(this.update(), this.refresh);
|
||||
};
|
||||
// /////////////////////////////////////////////////////////
|
||||
// INIT FUNCIONTS ////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
|
||||
function create_pie_chart(name, units) {
|
||||
var w = 500; //380 - Please keep in sync with pie-chart.css
|
||||
var h = 325; //280
|
||||
var ir = 52; //45
|
||||
var textOffset = 14;
|
||||
var tweenDuration = 250;
|
||||
var r = 116; //100;
|
||||
let w = 500; // 380 - Please keep in sync with pie-chart.css
|
||||
let h = 325; // 280
|
||||
let ir = 52; // 45
|
||||
const textOffset = 14;
|
||||
const tweenDuration = 250;
|
||||
let r = 116; // 100;
|
||||
|
||||
if ($(name).hasClass("pie-chart-small")) {
|
||||
w = 330;
|
||||
h = 250;
|
||||
r = w / 5 + 15;
|
||||
ir = r / 2;
|
||||
}
|
||||
if ($(name).hasClass('pie-chart-small')) {
|
||||
w = 330;
|
||||
h = 250;
|
||||
r = w / 5 + 15;
|
||||
ir = r / 2;
|
||||
}
|
||||
|
||||
//D3 helper function to populate pie slice parameters from array data
|
||||
var donut = d3.layout.pie().value(function (d) {
|
||||
if (d.value == 0) { d.value = 1; } // Force to 1, in order to update the graph
|
||||
return d.value;
|
||||
});
|
||||
// D3 helper function to populate pie slice parameters from array data
|
||||
const donut = d3.layout.pie().value(function(d) {
|
||||
if (d.value == 0) {
|
||||
d.value = 1;
|
||||
} // Force to 1, in order to update the graph
|
||||
return d.value;
|
||||
});
|
||||
|
||||
//D3 helper function to create colors from an ordinal scale
|
||||
var color = d3.scale.category20();
|
||||
// D3 helper function to create colors from an ordinal scale
|
||||
const color = d3.scale.category20();
|
||||
|
||||
//D3 helper function to draw arcs, populates parameter "d" in path object
|
||||
var arc = d3.svg.arc()
|
||||
.startAngle(function (d) { return d.startAngle; })
|
||||
.endAngle(function (d) { return d.endAngle; })
|
||||
.innerRadius(ir)
|
||||
.outerRadius(r);
|
||||
// D3 helper function to draw arcs, populates parameter "d" in path object
|
||||
const arc = d3.svg.arc()
|
||||
.startAngle(function(d) {
|
||||
return d.startAngle;
|
||||
})
|
||||
.endAngle(function(d) {
|
||||
return d.endAngle;
|
||||
})
|
||||
.innerRadius(ir)
|
||||
.outerRadius(r);
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// CREATE VIS & GROUPS ////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
// CREATE VIS & GROUPS ////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
|
||||
var vis = d3.select(name).append("svg:svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h)
|
||||
.attr("viewBox", "0 0 " + w + " " + h)
|
||||
.attr("preserveAspectRatio", "xMidYMid");
|
||||
const vis = d3.select(name).append('svg:svg')
|
||||
.attr('width', w)
|
||||
.attr('height', h)
|
||||
.attr('viewBox', '0 0 ' + w + ' ' + h)
|
||||
.attr('preserveAspectRatio', 'xMidYMid');
|
||||
|
||||
//GROUP FOR ARCS/PATHS
|
||||
var arc_group = vis.append("svg:g")
|
||||
.attr("class", "arc")
|
||||
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
|
||||
// GROUP FOR ARCS/PATHS
|
||||
const arc_group = vis.append('svg:g')
|
||||
.attr('class', 'arc')
|
||||
.attr('transform', 'translate(' + (w / 2) + ',' + (h / 2) + ')');
|
||||
|
||||
//GROUP FOR LABELS
|
||||
var label_group = vis.append("svg:g")
|
||||
.attr("class", "label_group")
|
||||
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
|
||||
// GROUP FOR LABELS
|
||||
const label_group = vis.append('svg:g')
|
||||
.attr('class', 'label_group')
|
||||
.attr('transform', 'translate(' + (w / 2) + ',' + (h / 2) + ')');
|
||||
|
||||
//GROUP FOR CENTER TEXT
|
||||
var center_group = vis.append("svg:g")
|
||||
.attr("class", "center_group")
|
||||
.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");
|
||||
// GROUP FOR CENTER TEXT
|
||||
const center_group = vis.append('svg:g')
|
||||
.attr('class', 'center_group')
|
||||
.attr('transform', 'translate(' + (w / 2) + ',' + (h / 2) + ')');
|
||||
|
||||
//PLACEHOLDER GRAY CIRCLE
|
||||
arc_group.append("svg:circle")
|
||||
.attr("fill", "#EFEFEF")
|
||||
.attr("r", r);
|
||||
// PLACEHOLDER GRAY CIRCLE
|
||||
arc_group.append('svg:circle')
|
||||
.attr('fill', '#EFEFEF')
|
||||
.attr('r', r);
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// CENTER TEXT ////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
// CENTER TEXT ////////////////////////////////////////////
|
||||
// /////////////////////////////////////////////////////////
|
||||
|
||||
//WHITE CIRCLE BEHIND LABELS
|
||||
center_group.append("svg:circle")
|
||||
.attr("fill", "white")
|
||||
.attr("r", ir);
|
||||
// WHITE CIRCLE BEHIND LABELS
|
||||
center_group.append('svg:circle')
|
||||
.attr('fill', 'white')
|
||||
.attr('r', ir);
|
||||
|
||||
var totalUnits = null;
|
||||
var totalLabel = null;
|
||||
var totalValue = null;
|
||||
|
||||
if (units) {
|
||||
// "TOTAL" LABEL
|
||||
totalLabel = center_group.append("svg:text")
|
||||
.attr("class", "label")
|
||||
.attr("dy", -15)
|
||||
.attr("text-anchor", "middle") // text-align: right
|
||||
.text("TOTAL");
|
||||
let totalUnits = null;
|
||||
let totalLabel = null;
|
||||
let totalValue = null;
|
||||
|
||||
//TOTAL TRAFFIC VALUE
|
||||
totalValue = center_group.append("svg:text")
|
||||
.attr("class", "total")
|
||||
.attr("dy", 7)
|
||||
.attr("text-anchor", "middle") // text-align: right
|
||||
.text("Waiting...");
|
||||
if (units) {
|
||||
// "TOTAL" LABEL
|
||||
totalLabel = center_group.append('svg:text')
|
||||
.attr('class', 'label')
|
||||
.attr('dy', -15)
|
||||
.attr('text-anchor', 'middle') // text-align: right
|
||||
.text('TOTAL');
|
||||
|
||||
//UNITS LABEL
|
||||
totalUnits = center_group.append("svg:text")
|
||||
.attr("class", "units")
|
||||
.attr("dy", 21)
|
||||
.attr("text-anchor", "middle") // text-align: right
|
||||
.text(units);
|
||||
}
|
||||
// TOTAL TRAFFIC VALUE
|
||||
totalValue = center_group.append('svg:text')
|
||||
.attr('class', 'total')
|
||||
.attr('dy', 7)
|
||||
.attr('text-anchor', 'middle') // text-align: right
|
||||
.text('Waiting...');
|
||||
|
||||
return ([arc_group, donut, totalValue, totalUnits, color, tweenDuration, arc, label_group, center_group, r, textOffset]);
|
||||
// UNITS LABEL
|
||||
totalUnits = center_group.append('svg:text')
|
||||
.attr('class', 'units')
|
||||
.attr('dy', 21)
|
||||
.attr('text-anchor', 'middle') // text-align: right
|
||||
.text(units);
|
||||
}
|
||||
|
||||
return ([arc_group, donut, totalValue, totalUnits, color, tweenDuration, arc, label_group, center_group, r, textOffset]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import { do_pie } from './charts/pie-chart'
|
||||
import {do_pie} from './charts/pie-chart';
|
||||
|
||||
window.do_pie = do_pie
|
||||
window.do_pie = do_pie;
|
||||
|
||||
import { ChartWidget, WidgetUtils } from './widget/widgets'
|
||||
import './sidebar/sidebar'
|
||||
import { ntopChartApex } from "./ntopChartApex";
|
||||
import {ChartWidget, WidgetUtils} from './widget/widgets';
|
||||
import './sidebar/sidebar';
|
||||
import {ntopChartApex} from './ntopChartApex';
|
||||
|
||||
/* datatables.net extensions */
|
||||
import { DataTableFiltersMenu, DataTableUtils, DataTableRenders } from '../utilities/datatable/sprymedia-datatable-utils.js'
|
||||
import {DataTableFiltersMenu, DataTableUtils, DataTableRenders} from '../utilities/datatable/sprymedia-datatable-utils.js';
|
||||
|
||||
window.DataTableUtils = DataTableUtils
|
||||
window.DataTableFiltersMenu = DataTableFiltersMenu
|
||||
window.DataTableRenders = DataTableRenders
|
||||
window.DataTableUtils = DataTableUtils;
|
||||
window.DataTableFiltersMenu = DataTableFiltersMenu;
|
||||
window.DataTableRenders = DataTableRenders;
|
||||
|
||||
window.ChartWidget = ChartWidget;
|
||||
window.WidgetUtils = WidgetUtils;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,114 +1,100 @@
|
|||
const fixSubMenuPosition = ($submenu, $hoverButton) => {
|
||||
const MIN_SPACE = 20;
|
||||
const MIN_HEIGHT = 150;
|
||||
|
||||
const MIN_SPACE = 20;
|
||||
const MIN_HEIGHT = 150;
|
||||
|
||||
let distFromAbove = $hoverButton.position().top;
|
||||
const submenuHeight = $submenu.height();
|
||||
const documentHeight = $(window).height();
|
||||
|
||||
// if the submenu is too high to be shown then set
|
||||
// the overflow on y axis
|
||||
if (submenuHeight + distFromAbove >= documentHeight) {
|
||||
|
||||
const currentSubmenuHeight = documentHeight - distFromAbove;
|
||||
if (currentSubmenuHeight <= MIN_HEIGHT) {
|
||||
distFromAbove = distFromAbove - submenuHeight + $hoverButton.outerHeight();
|
||||
}
|
||||
else {
|
||||
$submenu.css({'max-height': currentSubmenuHeight - MIN_SPACE, 'overflow-y': 'auto'})
|
||||
}
|
||||
let distFromAbove = $hoverButton.position().top;
|
||||
const submenuHeight = $submenu.height();
|
||||
const documentHeight = $(window).height();
|
||||
|
||||
// if the submenu is too high to be shown then set
|
||||
// the overflow on y axis
|
||||
if (submenuHeight + distFromAbove >= documentHeight) {
|
||||
const currentSubmenuHeight = documentHeight - distFromAbove;
|
||||
if (currentSubmenuHeight <= MIN_HEIGHT) {
|
||||
distFromAbove = distFromAbove - submenuHeight + $hoverButton.outerHeight();
|
||||
} else {
|
||||
$submenu.css({'max-height': currentSubmenuHeight - MIN_SPACE, 'overflow-y': 'auto'});
|
||||
}
|
||||
}
|
||||
|
||||
// set the submenu height
|
||||
$submenu.css('top', `${distFromAbove}px`);
|
||||
|
||||
// set the submenu height
|
||||
$submenu.css('top', `${distFromAbove}px`);
|
||||
};
|
||||
|
||||
$(window).on('scroll', function(){
|
||||
|
||||
const UPPER_LIMIT = 32;
|
||||
const windowScrollTop = $(this).scrollTop();
|
||||
|
||||
if (windowScrollTop >= UPPER_LIMIT) {
|
||||
$(`#n-navbar`).addClass("scrolled bg-light");
|
||||
}
|
||||
else {
|
||||
$(`#n-navbar`).removeClass("scrolled bg-light");
|
||||
}
|
||||
$(window).on('scroll', function() {
|
||||
const UPPER_LIMIT = 32;
|
||||
const windowScrollTop = $(this).scrollTop();
|
||||
|
||||
if (windowScrollTop >= UPPER_LIMIT) {
|
||||
$(`#n-navbar`).addClass('scrolled bg-light');
|
||||
} else {
|
||||
$(`#n-navbar`).removeClass('scrolled bg-light');
|
||||
}
|
||||
});
|
||||
|
||||
$(() => {
|
||||
const toggleSidebar = () => {
|
||||
// if the layer doesn't exists then create it
|
||||
if ($(`.sidebar-close-layer`).length == 0) {
|
||||
const $layer = $(`<div class='sidebar-close-layer' style='display:none'></div>`);
|
||||
// when the user clicks on the layer
|
||||
$layer.on('click', function() {
|
||||
// remove active class from sidebar
|
||||
$(`#n-sidebar`).removeClass('active');
|
||||
// hide the layer and remove it from the DOM
|
||||
$layer.fadeOut(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
|
||||
const toggleSidebar = () => {
|
||||
// if the layer doesn't exists then create it
|
||||
if ($(`.sidebar-close-layer`).length == 0) {
|
||||
|
||||
const $layer = $(`<div class='sidebar-close-layer' style='display:none'></div>`);
|
||||
// when the user clicks on the layer
|
||||
$layer.on('click', function(){
|
||||
// remove active class from sidebar
|
||||
$(`#n-sidebar`).removeClass('active');
|
||||
// hide the layer and remove it from the DOM
|
||||
$layer.fadeOut(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
|
||||
// append the layer to the wrapper
|
||||
$(`#wrapper`).append($layer);
|
||||
// show the layer inside the page
|
||||
$layer.fadeIn();
|
||||
}
|
||||
else {
|
||||
// hide the existing layer and destroy it
|
||||
$(`.sidebar-close-layer`).fadeOut(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
|
||||
// show/hide the sidebar
|
||||
$(`#n-sidebar`).toggleClass('active');
|
||||
// append the layer to the wrapper
|
||||
$(`#wrapper`).append($layer);
|
||||
// show the layer inside the page
|
||||
$layer.fadeIn();
|
||||
} else {
|
||||
// hide the existing layer and destroy it
|
||||
$(`.sidebar-close-layer`).fadeOut(function() {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
|
||||
$('#n-sidebar a.submenu').bind({
|
||||
mouseenter: function() {
|
||||
let submenu = $(this).parent().find(`div[id$='submenu']`);
|
||||
fixSubMenuPosition(submenu, $(this));
|
||||
submenu.show()
|
||||
},
|
||||
mouseleave: function() {
|
||||
let submenu = $(this).parent().find(`div[id$='submenu']`);
|
||||
submenu.hide();
|
||||
}
|
||||
});
|
||||
// show/hide the sidebar
|
||||
$(`#n-sidebar`).toggleClass('active');
|
||||
};
|
||||
|
||||
$(`div[id$='submenu']`).bind({
|
||||
mouseenter: function() {
|
||||
$(this).show()
|
||||
},
|
||||
mouseleave: function() {
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
$('#n-sidebar a.submenu').bind({
|
||||
mouseenter: function() {
|
||||
const submenu = $(this).parent().find(`div[id$='submenu']`);
|
||||
fixSubMenuPosition(submenu, $(this));
|
||||
submenu.show();
|
||||
},
|
||||
mouseleave: function() {
|
||||
const submenu = $(this).parent().find(`div[id$='submenu']`);
|
||||
submenu.hide();
|
||||
},
|
||||
});
|
||||
|
||||
/* toggle sidebar display */
|
||||
$(`button[data-bs-toggle='sidebar']`).on('click', function() {
|
||||
toggleSidebar();
|
||||
});
|
||||
$(`div[id$='submenu']`).bind({
|
||||
mouseenter: function() {
|
||||
$(this).show();
|
||||
},
|
||||
mouseleave: function() {
|
||||
$(this).hide();
|
||||
},
|
||||
});
|
||||
|
||||
/* toggle sidebar display */
|
||||
$(`button[data-bs-toggle='sidebar']`).on('click', function() {
|
||||
toggleSidebar();
|
||||
});
|
||||
});
|
||||
|
||||
$(window).on('resize', function() {
|
||||
// re-calc submenu height
|
||||
const $currentSubmenu = $('#n-sidebar').find(`div.show[id$='submenu']`);
|
||||
|
||||
// re-calc submenu height
|
||||
const $currentSubmenu = $('#n-sidebar').find(`div.show[id$='submenu']`);
|
||||
|
||||
if ($currentSubmenu.length > 0) {
|
||||
|
||||
const $hoverButton = $currentSubmenu.parent().find(`a[data-bs-toggle='collapse']`);
|
||||
fixSubMenuPosition($currentSubmenu, $hoverButton);
|
||||
}
|
||||
|
||||
if ($currentSubmenu.length > 0) {
|
||||
const $hoverButton = $currentSubmenu.parent().find(`a[data-bs-toggle='collapse']`);
|
||||
fixSubMenuPosition($currentSubmenu, $hoverButton);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,79 +7,81 @@
|
|||
const DEFINED_WIDGETS = {};
|
||||
/* Used to implement the on click events onto the graph */
|
||||
const DEFINED_EVENTS = {
|
||||
/* On click event used by the flow analyze section, redirect to the current url + a single filter */
|
||||
"db_analyze" : function (event, chartContext, config) {
|
||||
const { dataPointIndex } = config;
|
||||
const { filter } = config.w.config;
|
||||
let value;
|
||||
/* On click event used by the flow analyze section, redirect to the current url + a single filter */
|
||||
'db_analyze': function(event, chartContext, config) {
|
||||
const {dataPointIndex} = config;
|
||||
const {filter} = config.w.config;
|
||||
let value;
|
||||
|
||||
if(config.w.config.filtering_labels)
|
||||
value = config.w.config.filtering_labels[dataPointIndex];
|
||||
if (config.w.config.filtering_labels) {
|
||||
value = config.w.config.filtering_labels[dataPointIndex];
|
||||
}
|
||||
|
||||
if(filter.length == 0 || value === undefined)
|
||||
return;
|
||||
if (filter.length == 0 || value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let status = ntopng_status_manager.get_status();
|
||||
let filters = status.filters;
|
||||
filters.push({id: filter[0], operator: "eq", value: value});
|
||||
// notify that filters status is updated
|
||||
ntopng_events_manager.emit_event(ntopng_events.FILTERS_CHANGE, {filters});
|
||||
},
|
||||
const status = ntopng_status_manager.get_status();
|
||||
const filters = status.filters;
|
||||
filters.push({id: filter[0], operator: 'eq', value: value});
|
||||
// notify that filters status is updated
|
||||
ntopng_events_manager.emit_event(ntopng_events.FILTERS_CHANGE, {filters});
|
||||
},
|
||||
|
||||
"none" : function (event, chartContext, config) {
|
||||
return;
|
||||
},
|
||||
|
||||
/* Standard on click event, redirect to the url */
|
||||
"standard" : function (event, chartContext, config) {
|
||||
const { seriesIndex, dataPointIndex } = config;
|
||||
const { series } = config.w.config;
|
||||
if (seriesIndex === -1) return;
|
||||
if (series === undefined) return;
|
||||
'none': function(event, chartContext, config) {
|
||||
return;
|
||||
},
|
||||
|
||||
const serie = series[seriesIndex];
|
||||
if (serie.base_url !== undefined) {
|
||||
const default_url = (serie.start_url || '')
|
||||
const search = serie.data[dataPointIndex].meta.url_query;
|
||||
location.href = `${serie.base_url}?${default_url}${search}`;
|
||||
}
|
||||
},
|
||||
}
|
||||
/* Standard on click event, redirect to the url */
|
||||
'standard': function(event, chartContext, config) {
|
||||
const {seriesIndex, dataPointIndex} = config;
|
||||
const {series} = config.w.config;
|
||||
if (seriesIndex === -1) return;
|
||||
if (series === undefined) return;
|
||||
|
||||
const serie = series[seriesIndex];
|
||||
if (serie.base_url !== undefined) {
|
||||
const default_url = (serie.start_url || '');
|
||||
const search = serie.data[dataPointIndex].meta.url_query;
|
||||
location.href = `${serie.base_url}?${default_url}${search}`;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFINED_TOOLTIP = {
|
||||
/* On click event used by the flow analyze section, redirect to the current url + a single filter */
|
||||
"format_bytes" : function(value, { config, seriesIndex, dataPointIndex }) {
|
||||
return NtopUtils.bytesToSize(value);
|
||||
},
|
||||
/* On click event used by the flow analyze section, redirect to the current url + a single filter */
|
||||
'format_bytes': function(value, {config, seriesIndex, dataPointIndex}) {
|
||||
return NtopUtils.bytesToSize(value);
|
||||
},
|
||||
|
||||
"format_pkts" : function(value, { config, seriesIndex, dataPointIndex }) {
|
||||
return NtopUtils.formatPackets(value);
|
||||
},
|
||||
'format_pkts': function(value, {config, seriesIndex, dataPointIndex}) {
|
||||
return NtopUtils.formatPackets(value);
|
||||
},
|
||||
|
||||
/* On click event used by the flow analyze section, redirect to the current url + a single filter */
|
||||
"format_value" : function(value, { config, seriesIndex, dataPointIndex }) {
|
||||
return NtopUtils.formatValue(value);
|
||||
},
|
||||
/* On click event used by the flow analyze section, redirect to the current url + a single filter */
|
||||
'format_value': function(value, {config, seriesIndex, dataPointIndex}) {
|
||||
return NtopUtils.formatValue(value);
|
||||
},
|
||||
|
||||
"format_multiple_date" : function(value, { config, seriesIndex, dataPointIndex }) {
|
||||
return new Date(value[0]) + " - " + new Date(value[1])
|
||||
},
|
||||
'format_multiple_date': function(value, {config, seriesIndex, dataPointIndex}) {
|
||||
return new Date(value[0]) + ' - ' + new Date(value[1]);
|
||||
},
|
||||
|
||||
/*
|
||||
/*
|
||||
* This formatter is used by the bubble host map, from the y axis,
|
||||
* used to show the Hosts, with their respective values
|
||||
* used to show the Hosts, with their respective values
|
||||
*/
|
||||
"format_label_from_xy" : function({series, seriesIndex, dataPointIndex, w}) {
|
||||
const serie = w.config.series[seriesIndex]["data"][dataPointIndex];
|
||||
|
||||
const x_value = serie["x"];
|
||||
const y_value = serie["y"];
|
||||
const host_name = serie["meta"]["label"];
|
||||
'format_label_from_xy': function({series, seriesIndex, dataPointIndex, w}) {
|
||||
const serie = w.config.series[seriesIndex]['data'][dataPointIndex];
|
||||
|
||||
const x_axis_title = w.config.xaxis.title.text;
|
||||
const y_axis_title = w.config.yaxis[0].title.text;
|
||||
const x_value = serie['x'];
|
||||
const y_value = serie['y'];
|
||||
const host_name = serie['meta']['label'];
|
||||
|
||||
return (`
|
||||
const x_axis_title = w.config.xaxis.title.text;
|
||||
const y_axis_title = w.config.yaxis[0].title.text;
|
||||
|
||||
return (`
|
||||
<div class='apexcharts-theme-light apexcharts-active' id='test'>
|
||||
<div class='apexcharts-tooltip-title' style='font-family: Helvetica, Arial, sans-serif; font-size: 12px;'>
|
||||
${host_name}
|
||||
|
|
@ -92,18 +94,18 @@ export const DEFINED_TOOLTIP = {
|
|||
<b>${y_axis_title}</b>: ${y_value}
|
||||
</div>
|
||||
</div>
|
||||
</div>`)
|
||||
},
|
||||
"format_label_from_xname" : function({series, seriesIndex, dataPointIndex, w}) {
|
||||
const serie = w.config.series[seriesIndex]["data"][dataPointIndex];
|
||||
const name = serie["name"]
|
||||
const y_value = serie["y"];
|
||||
const host_name = serie["meta"]["label"];
|
||||
</div>`);
|
||||
},
|
||||
'format_label_from_xname': function({series, seriesIndex, dataPointIndex, w}) {
|
||||
const serie = w.config.series[seriesIndex]['data'][dataPointIndex];
|
||||
const name = serie['name'];
|
||||
const y_value = serie['y'];
|
||||
const host_name = serie['meta']['label'];
|
||||
|
||||
const x_axis_title = w.config.xaxis.title.text;
|
||||
const y_axis_title = w.config.yaxis[0].title.text;
|
||||
const x_axis_title = w.config.xaxis.title.text;
|
||||
const y_axis_title = w.config.yaxis[0].title.text;
|
||||
|
||||
return (`
|
||||
return (`
|
||||
<div class='apexcharts-theme-light apexcharts-active' id='test'>
|
||||
<div class='apexcharts-tooltip-title' style='font-family: Helvetica, Arial, sans-serif; font-size: 12px;'>
|
||||
${host_name}
|
||||
|
|
@ -116,400 +118,394 @@ export const DEFINED_TOOLTIP = {
|
|||
<b>${y_axis_title}</b>: ${y_value}
|
||||
</div>
|
||||
</div>
|
||||
</div>`)
|
||||
},
|
||||
}
|
||||
</div>`);
|
||||
},
|
||||
};
|
||||
|
||||
/* Standard Formatter */
|
||||
const DEFAULT_FORMATTER = DEFINED_TOOLTIP["format_value"];
|
||||
const DEFAULT_FORMATTER = DEFINED_TOOLTIP['format_value'];
|
||||
|
||||
export class WidgetUtils {
|
||||
static registerWidget(widget) {
|
||||
if (widget === null) throw new Error(`The passed widget reference is null!`);
|
||||
if (widget.name in DEFINED_WIDGETS) throw new Error(`The widget ${widget.name} is already defined!`);
|
||||
DEFINED_WIDGETS[widget.name] = widget;
|
||||
}
|
||||
|
||||
static registerWidget(widget) {
|
||||
if (widget === null) throw new Error(`The passed widget reference is null!`);
|
||||
if (widget.name in DEFINED_WIDGETS) throw new Error(`The widget ${widget.name} is already defined!`);
|
||||
DEFINED_WIDGETS[widget.name] = widget;
|
||||
}
|
||||
|
||||
static getWidgetByName(widgetName) {
|
||||
if (widgetName in DEFINED_WIDGETS) {
|
||||
return DEFINED_WIDGETS[widgetName];
|
||||
}
|
||||
throw new Error(`Widget ${widgetName} not found!`)
|
||||
static getWidgetByName(widgetName) {
|
||||
if (widgetName in DEFINED_WIDGETS) {
|
||||
return DEFINED_WIDGETS[widgetName];
|
||||
}
|
||||
throw new Error(`Widget ${widgetName} not found!`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a simple wrapper class for the widgets.
|
||||
*/
|
||||
class Widget {
|
||||
constructor(name, datasource = {}, updateTime = 0, additionalParams = {}) {
|
||||
// field containing the data fetched from the datasources provided
|
||||
this._fetchedData = [];
|
||||
|
||||
constructor(name, datasource = {}, updateTime = 0, additionalParams = {}) {
|
||||
this.name = name;
|
||||
|
||||
// field containing the data fetched from the datasources provided
|
||||
this._fetchedData = [];
|
||||
// if 0 then don't update the chart automatically, the time
|
||||
// is expressed in milliseconds
|
||||
this._updateTime = updateTime;
|
||||
|
||||
this.name = name;
|
||||
this._datasource = datasource;
|
||||
this._additionalParams = additionalParams;
|
||||
}
|
||||
|
||||
// if 0 then don't update the chart automatically, the time
|
||||
// is expressed in milliseconds
|
||||
this._updateTime = updateTime;
|
||||
|
||||
this._datasource = datasource;
|
||||
this._additionalParams = additionalParams;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Init the widget.
|
||||
*/
|
||||
async init() {
|
||||
async init() {
|
||||
// register the widget to the DEFINED_WIDGETS object
|
||||
WidgetUtils.registerWidget(this);
|
||||
this._fetchedData = await this._fetchData();
|
||||
|
||||
// register the widget to the DEFINED_WIDGETS object
|
||||
WidgetUtils.registerWidget(this);
|
||||
this._fetchedData = await this._fetchData();
|
||||
|
||||
if (this._updateTime > 0) {
|
||||
setInterval(async () => { await this.update(this._datasource.params); }, this._updateTime);
|
||||
}
|
||||
if (this._updateTime > 0) {
|
||||
setInterval(async () => {
|
||||
await this.update(this._datasource.params);
|
||||
}, this._updateTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Destroy the widget freeing the resources used.
|
||||
*/
|
||||
async destroy() { }
|
||||
async destroy() { }
|
||||
|
||||
/**
|
||||
/**
|
||||
* Force the widget to reload it's data.
|
||||
*/
|
||||
async destroyAndUpdate(datasourceParams = {}) {
|
||||
await this.destroy();
|
||||
await this.update(datasourceParams);
|
||||
async destroyAndUpdate(datasourceParams = {}) {
|
||||
await this.destroy();
|
||||
await this.update(datasourceParams);
|
||||
}
|
||||
|
||||
async updateByUrl(url) {
|
||||
const u = new URL(`${location.origin}${this._datasource.name}`);
|
||||
const entries = ntopng_url_manager.get_url_entries(url);
|
||||
for (const [key, value] of entries) {
|
||||
u.searchParams.set(key, value);
|
||||
}
|
||||
this._datasource.endpoint = u.pathname + u.search;
|
||||
this._fetchedData = await this._fetchData();
|
||||
}
|
||||
|
||||
async update(datasourceParams = {}) {
|
||||
// build the new endpoint
|
||||
const u = new URL(`${location.origin}${this._datasource.name}`);
|
||||
|
||||
for (const [key, value] of Object.entries(datasourceParams)) {
|
||||
u.searchParams.set(key, value);
|
||||
}
|
||||
|
||||
async updateByUrl(url) {
|
||||
const u = new URL(`${location.origin}${this._datasource.name}`);
|
||||
let entries = ntopng_url_manager.get_url_entries(url);
|
||||
for (const [key, value] of entries) {
|
||||
u.searchParams.set(key, value);
|
||||
}
|
||||
this._datasource.endpoint = u.pathname + u.search;
|
||||
this._fetchedData = await this._fetchData();
|
||||
}
|
||||
|
||||
async update(datasourceParams = {}) {
|
||||
// build the new endpoint
|
||||
const u = new URL(`${location.origin}${this._datasource.name}`);
|
||||
this._datasource.endpoint = u.pathname + u.search;
|
||||
this._fetchedData = await this._fetchData();
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(datasourceParams)) {
|
||||
u.searchParams.set(key, value);
|
||||
}
|
||||
|
||||
this._datasource.endpoint = u.pathname + u.search;
|
||||
this._fetchedData = await this._fetchData();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* For each datasources provided to the constructor,
|
||||
* do a GET request to a REST endpoint.
|
||||
*/
|
||||
async _fetchData() {
|
||||
const req = await fetch(`${http_prefix}${this._datasource.endpoint}`);
|
||||
return await req.json();
|
||||
}
|
||||
|
||||
async _fetchData() {
|
||||
const req = await fetch(`${http_prefix}${this._datasource.endpoint}`);
|
||||
return await req.json();
|
||||
}
|
||||
}
|
||||
|
||||
export class ChartWidget extends Widget {
|
||||
constructor(name, type = 'line', datasource = {}, updateTime = 0, additionalParams = {}) {
|
||||
super(name, datasource, updateTime, additionalParams);
|
||||
|
||||
constructor(name, type = 'line', datasource = {}, updateTime = 0, additionalParams = {}) {
|
||||
super(name, datasource, updateTime, additionalParams);
|
||||
this._chartType = type;
|
||||
this._chart = {};
|
||||
this._$htmlChart = document.querySelector(`#canvas-widget-${name}`);
|
||||
}
|
||||
|
||||
this._chartType = type;
|
||||
this._chart = {};
|
||||
this._$htmlChart = document.querySelector(`#canvas-widget-${name}`);
|
||||
}
|
||||
static registerEventCallback(widgetName, eventName, callback) {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const widget = WidgetUtils.getWidgetByName(widgetName);
|
||||
const updatedOptions = {
|
||||
chart: {
|
||||
events: {
|
||||
[eventName]: callback,
|
||||
},
|
||||
},
|
||||
};
|
||||
await widget._chart.updateOptions(updatedOptions);
|
||||
} catch (e) {
|
||||
|
||||
static registerEventCallback(widgetName, eventName, callback) {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const widget = WidgetUtils.getWidgetByName(widgetName);
|
||||
const updatedOptions = {
|
||||
chart: {
|
||||
events: {
|
||||
[eventName]: callback
|
||||
}
|
||||
}
|
||||
};
|
||||
await widget._chart.updateOptions(updatedOptions);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
_generateConfig() {
|
||||
const config = {
|
||||
series: [],
|
||||
tooltip: {
|
||||
enabledOnSeries: [0],
|
||||
x: {
|
||||
show: true,
|
||||
format: 'dd/MM/yyyy HH:mm:ss',
|
||||
},
|
||||
y: {
|
||||
formatter: function(value, { series, seriesIndex, dataPointIndex, w }) {
|
||||
return value;
|
||||
},
|
||||
},
|
||||
z: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
chart: {
|
||||
type: this._chartType,
|
||||
events: {},
|
||||
height: '100%',
|
||||
toolbar: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
formatter: function(value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
formatter: function(value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
zaxis: {
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
}
|
||||
},
|
||||
_generateConfig() {
|
||||
const config = {
|
||||
series: [],
|
||||
tooltip: {
|
||||
enabledOnSeries: [0],
|
||||
x: {
|
||||
show: true,
|
||||
format: 'dd/MM/yyyy HH:mm:ss',
|
||||
},
|
||||
y: {
|
||||
formatter: function(value, {series, seriesIndex, dataPointIndex, w}) {
|
||||
return value;
|
||||
},
|
||||
},
|
||||
z: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
chart: {
|
||||
type: this._chartType,
|
||||
events: {},
|
||||
height: '100%',
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
formatter: function(value) {
|
||||
return value;
|
||||
},
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
formatter: function(value) {
|
||||
return value;
|
||||
},
|
||||
},
|
||||
},
|
||||
zaxis: {
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
},
|
||||
},
|
||||
labels: [],
|
||||
legend: {
|
||||
show: true,
|
||||
fontSize: '14px',
|
||||
position: 'bottom',
|
||||
onItemClick: {
|
||||
toggleDataSeries: true,
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 4,
|
||||
horizontal: true,
|
||||
}
|
||||
},
|
||||
noData: {
|
||||
text: 'No Data',
|
||||
align: 'center',
|
||||
verticalAlign: 'middle',
|
||||
style: {
|
||||
fontSize: '24px'
|
||||
}
|
||||
}
|
||||
};
|
||||
legend: {
|
||||
show: true,
|
||||
fontSize: '14px',
|
||||
position: 'bottom',
|
||||
onItemClick: {
|
||||
toggleDataSeries: true,
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 4,
|
||||
horizontal: true,
|
||||
},
|
||||
},
|
||||
noData: {
|
||||
text: 'No Data',
|
||||
align: 'center',
|
||||
verticalAlign: 'middle',
|
||||
style: {
|
||||
fontSize: '24px',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// check if the additionalParams field contains an apex property,
|
||||
// then merge the two configurations giving priority to the custom one
|
||||
if (this._additionalParams && this._additionalParams.apex) {
|
||||
const mergedConfig = Object.assign(config, this._additionalParams.apex);
|
||||
return mergedConfig;
|
||||
}
|
||||
|
||||
return config;
|
||||
// check if the additionalParams field contains an apex property,
|
||||
// then merge the two configurations giving priority to the custom one
|
||||
if (this._additionalParams && this._additionalParams.apex) {
|
||||
const mergedConfig = Object.assign(config, this._additionalParams.apex);
|
||||
return mergedConfig;
|
||||
}
|
||||
|
||||
_buildTooltip(config, rsp) {
|
||||
debugger;
|
||||
/* By default the areaChart tooltip[y] is overwritten */
|
||||
config["tooltip"]["y"] = {
|
||||
formatter: function(value, { series, seriesIndex, dataPointIndex, w }) {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
return config;
|
||||
}
|
||||
|
||||
/* Changing events if given */
|
||||
if (rsp['tooltip']) {
|
||||
for (const axis in rsp['tooltip']) {
|
||||
if (axis === "x" || axis === "y" || axis === "z") {
|
||||
const formatter = rsp['tooltip'][axis]['formatter'];
|
||||
if(!config['tooltip'][axis])
|
||||
config['tooltip'][axis] = {}
|
||||
_buildTooltip(config, rsp) {
|
||||
debugger;
|
||||
/* By default the areaChart tooltip[y] is overwritten */
|
||||
config['tooltip']['y'] = {
|
||||
formatter: function(value, {series, seriesIndex, dataPointIndex, w}) {
|
||||
return value;
|
||||
},
|
||||
};
|
||||
|
||||
config['tooltip'][axis]['formatter'] = DEFINED_TOOLTIP[formatter] || NtopUtils[formatter]
|
||||
}
|
||||
}
|
||||
|
||||
/* Customizable tooltip requested */
|
||||
if(rsp['tooltip']['custom'])
|
||||
config['tooltip']['custom'] = DEFINED_TOOLTIP[rsp['tooltip']['custom']] || NtopUtils[rsp['tooltip']['custom']]
|
||||
}
|
||||
}
|
||||
|
||||
_buildAxisFormatter(config, axisName) {
|
||||
|
||||
const axis = config[axisName];
|
||||
|
||||
if (axis === undefined || axis.labels === undefined) return;
|
||||
|
||||
// enable formatters
|
||||
if (axis.labels.ntop_utils_formatter !== undefined && axis.labels.ntop_utils_formatter !== 'none') {
|
||||
|
||||
const selectedFormatter = axis.labels.ntop_utils_formatter;
|
||||
|
||||
if (NtopUtils[selectedFormatter] === undefined) {
|
||||
console.error(`xaxis: Formatting function '${selectedFormatter}' didn't found inside NtopUtils.`);
|
||||
}
|
||||
else {
|
||||
axis.labels.formatter = NtopUtils[selectedFormatter];
|
||||
}
|
||||
} // enable formatters
|
||||
}
|
||||
|
||||
_buildDataLabels(config, rsp) {
|
||||
if (rsp["dataLabels"]) {
|
||||
for (const [dataLabelsOpts, data] of Object.entries(rsp["dataLabels"])) {
|
||||
config["dataLabels"][dataLabelsOpts] = data;
|
||||
}
|
||||
}
|
||||
|
||||
let formatter = config["dataLabels"]["formatter"];
|
||||
|
||||
if(formatter && DEFINED_TOOLTIP[formatter]) {
|
||||
config["dataLabels"]["formatter"] = DEFINED_TOOLTIP[formatter];
|
||||
}
|
||||
}
|
||||
|
||||
_buildConfig() {
|
||||
|
||||
const config = this._generateConfig();
|
||||
const rsp = this._fetchedData.rsp;
|
||||
|
||||
// add additional params fetched from the datasource
|
||||
const additionals = ['series', 'xaxis', 'yaxis', 'colors', 'labels', 'fill', 'filter', 'filtering_labels'];
|
||||
|
||||
for (const additional of additionals) {
|
||||
|
||||
if (rsp[additional] === undefined) continue;
|
||||
|
||||
if (config[additional] !== undefined) {
|
||||
config[additional] = Object.assign(config[additional], rsp[additional]);
|
||||
}
|
||||
else {
|
||||
config[additional] = rsp[additional];
|
||||
}
|
||||
}
|
||||
|
||||
/* Changing events if given */
|
||||
if (rsp['events']) {
|
||||
/* Just pass a table of events. e.g. { events = { click = "db_analyze", updated = "standard" } }*/
|
||||
for (const event in rsp['events']) {
|
||||
config['chart']['events'][event] = DEFINED_EVENTS[rsp['events'][event]]
|
||||
}
|
||||
}
|
||||
|
||||
if (rsp['horizontal_chart'] !== undefined) {
|
||||
config['plotOptions']['bar']['horizontal'] = rsp['horizontal_chart'];
|
||||
}
|
||||
|
||||
this._buildTooltip(config, rsp)
|
||||
this._buildAxisFormatter(config, 'xaxis');
|
||||
this._buildAxisFormatter(config, 'yaxis');
|
||||
this._buildDataLabels(config, rsp);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
_initializeChart() {
|
||||
const config = this._buildConfig();
|
||||
this._chartConfig = config;
|
||||
this._chart = new ApexCharts(this._$htmlChart, this._chartConfig);
|
||||
this._chart.render();
|
||||
}
|
||||
|
||||
async init() {
|
||||
await super.init();
|
||||
this._initializeChart();
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
await super.destroy();
|
||||
this._chart.destroy();
|
||||
this._chart = null;
|
||||
}
|
||||
|
||||
async update(datasourceParams = {}) {
|
||||
if(this._chartConfig !== undefined) {
|
||||
if (datasourceParams) {
|
||||
await super.update(datasourceParams);
|
||||
} else {
|
||||
await super.updateByUrl();
|
||||
/* Changing events if given */
|
||||
if (rsp['tooltip']) {
|
||||
for (const axis in rsp['tooltip']) {
|
||||
if (axis === 'x' || axis === 'y' || axis === 'z') {
|
||||
const formatter = rsp['tooltip'][axis]['formatter'];
|
||||
if (!config['tooltip'][axis]) {
|
||||
config['tooltip'][axis] = {};
|
||||
}
|
||||
|
||||
if (this._chart != null) {
|
||||
// expecting that rsp contains an object called series
|
||||
const { colors, series, dataLabels, labels, xaxis, filtering_labels } = this._fetchedData.rsp;
|
||||
// update the colors list
|
||||
this._chartConfig.colors = colors;
|
||||
this._chartConfig.series = series;
|
||||
|
||||
if(xaxis && xaxis.categories)
|
||||
this._chartConfig.xaxis.categories = xaxis.categories;
|
||||
|
||||
if(filtering_labels)
|
||||
this._chartConfig.filtering_labels = filtering_labels;
|
||||
|
||||
if(dataLabels) {
|
||||
let formatter = this._chartConfig.dataLabels.formatter;
|
||||
if(formatter && DEFINED_TOOLTIP[formatter])
|
||||
this._chartConfig.dataLabels.formatter = DEFINED_TOOLTIP[formatter];
|
||||
else
|
||||
this._chartConfig.dataLabels.formatter = DEFAULT_FORMATTER;
|
||||
}
|
||||
|
||||
if(labels)
|
||||
this._chartConfig.labels = labels;
|
||||
|
||||
this._chart.updateOptions(this._chartConfig, true);
|
||||
}
|
||||
config['tooltip'][axis]['formatter'] = DEFINED_TOOLTIP[formatter] || NtopUtils[formatter];
|
||||
}
|
||||
}
|
||||
|
||||
/* Customizable tooltip requested */
|
||||
if (rsp['tooltip']['custom']) {
|
||||
config['tooltip']['custom'] = DEFINED_TOOLTIP[rsp['tooltip']['custom']] || NtopUtils[rsp['tooltip']['custom']];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_buildAxisFormatter(config, axisName) {
|
||||
const axis = config[axisName];
|
||||
|
||||
if (axis === undefined || axis.labels === undefined) return;
|
||||
|
||||
// enable formatters
|
||||
if (axis.labels.ntop_utils_formatter !== undefined && axis.labels.ntop_utils_formatter !== 'none') {
|
||||
const selectedFormatter = axis.labels.ntop_utils_formatter;
|
||||
|
||||
if (NtopUtils[selectedFormatter] === undefined) {
|
||||
console.error(`xaxis: Formatting function '${selectedFormatter}' didn't found inside NtopUtils.`);
|
||||
} else {
|
||||
axis.labels.formatter = NtopUtils[selectedFormatter];
|
||||
}
|
||||
} // enable formatters
|
||||
}
|
||||
|
||||
_buildDataLabels(config, rsp) {
|
||||
if (rsp['dataLabels']) {
|
||||
for (const [dataLabelsOpts, data] of Object.entries(rsp['dataLabels'])) {
|
||||
config['dataLabels'][dataLabelsOpts] = data;
|
||||
}
|
||||
}
|
||||
|
||||
async destroyAndUpdate(datasource = {}) {
|
||||
await super.destroyAndUpdate(datasource);
|
||||
this._initializeChart();
|
||||
const formatter = config['dataLabels']['formatter'];
|
||||
|
||||
if (formatter && DEFINED_TOOLTIP[formatter]) {
|
||||
config['dataLabels']['formatter'] = DEFINED_TOOLTIP[formatter];
|
||||
}
|
||||
}
|
||||
|
||||
_buildConfig() {
|
||||
const config = this._generateConfig();
|
||||
const rsp = this._fetchedData.rsp;
|
||||
|
||||
// add additional params fetched from the datasource
|
||||
const additionals = ['series', 'xaxis', 'yaxis', 'colors', 'labels', 'fill', 'filter', 'filtering_labels'];
|
||||
|
||||
for (const additional of additionals) {
|
||||
if (rsp[additional] === undefined) continue;
|
||||
|
||||
if (config[additional] !== undefined) {
|
||||
config[additional] = Object.assign(config[additional], rsp[additional]);
|
||||
} else {
|
||||
config[additional] = rsp[additional];
|
||||
}
|
||||
}
|
||||
|
||||
/* Changing events if given */
|
||||
if (rsp['events']) {
|
||||
/* Just pass a table of events. e.g. { events = { click = "db_analyze", updated = "standard" } }*/
|
||||
for (const event in rsp['events']) {
|
||||
config['chart']['events'][event] = DEFINED_EVENTS[rsp['events'][event]];
|
||||
}
|
||||
}
|
||||
|
||||
if (rsp['horizontal_chart'] !== undefined) {
|
||||
config['plotOptions']['bar']['horizontal'] = rsp['horizontal_chart'];
|
||||
}
|
||||
|
||||
this._buildTooltip(config, rsp);
|
||||
this._buildAxisFormatter(config, 'xaxis');
|
||||
this._buildAxisFormatter(config, 'yaxis');
|
||||
this._buildDataLabels(config, rsp);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
_initializeChart() {
|
||||
const config = this._buildConfig();
|
||||
this._chartConfig = config;
|
||||
this._chart = new ApexCharts(this._$htmlChart, this._chartConfig);
|
||||
this._chart.render();
|
||||
}
|
||||
|
||||
async init() {
|
||||
await super.init();
|
||||
this._initializeChart();
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
await super.destroy();
|
||||
this._chart.destroy();
|
||||
this._chart = null;
|
||||
}
|
||||
|
||||
async update(datasourceParams = {}) {
|
||||
if (this._chartConfig !== undefined) {
|
||||
if (datasourceParams) {
|
||||
await super.update(datasourceParams);
|
||||
} else {
|
||||
await super.updateByUrl();
|
||||
}
|
||||
|
||||
if (this._chart != null) {
|
||||
// expecting that rsp contains an object called series
|
||||
const {colors, series, dataLabels, labels, xaxis, filtering_labels} = this._fetchedData.rsp;
|
||||
// update the colors list
|
||||
this._chartConfig.colors = colors;
|
||||
this._chartConfig.series = series;
|
||||
|
||||
if (xaxis && xaxis.categories) {
|
||||
this._chartConfig.xaxis.categories = xaxis.categories;
|
||||
}
|
||||
|
||||
if (filtering_labels) {
|
||||
this._chartConfig.filtering_labels = filtering_labels;
|
||||
}
|
||||
|
||||
if (dataLabels) {
|
||||
const formatter = this._chartConfig.dataLabels.formatter;
|
||||
if (formatter && DEFINED_TOOLTIP[formatter]) {
|
||||
this._chartConfig.dataLabels.formatter = DEFINED_TOOLTIP[formatter];
|
||||
} else {
|
||||
this._chartConfig.dataLabels.formatter = DEFAULT_FORMATTER;
|
||||
}
|
||||
}
|
||||
|
||||
if (labels) {
|
||||
this._chartConfig.labels = labels;
|
||||
}
|
||||
|
||||
this._chart.updateOptions(this._chartConfig, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async destroyAndUpdate(datasource = {}) {
|
||||
await super.destroyAndUpdate(datasource);
|
||||
this._initializeChart();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue