parent
a4c23e116d
commit
3f59a07483
@ -1,528 +0,0 @@
|
||||
function Rect(value, name, x, y, w, h){
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.checkHit = function (mouseX, mouseY) {
|
||||
return (mouseX >= x && mouseX <= x + w && mouseY >= y && mouseY <= y + h);
|
||||
}
|
||||
}
|
||||
|
||||
function Circle(value, name, x, y, r){
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.r = r;
|
||||
this.checkHit = function (mouseX, mouseY) {
|
||||
return Math.pow((mouseX - x),2) + Math.pow((mouseY - y),2) <= Math.pow(r, 2);
|
||||
}
|
||||
}
|
||||
|
||||
function PieSlice(value, name, x, y, r, sAngle, eAngle){
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.r = r;
|
||||
this.sAngle = sAngle;
|
||||
this.eAngle = eAngle;
|
||||
this.checkHit = function (mouseX, mouseY) {
|
||||
if (Math.pow((mouseX - x),2) + Math.pow((mouseY - y),2) <= Math.pow(r, 2)){
|
||||
var dy = mouseY - y;
|
||||
var dx = mouseX - x;
|
||||
var theta = Math.atan2(dy, dx); // range (-PI, PI]
|
||||
if (theta < 0) theta += 2*Math.PI;
|
||||
|
||||
return (theta > sAngle && theta < eAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let objects = [];
|
||||
|
||||
function checkHit(pos) {
|
||||
for (let i = 0; i < objects.length; i++){
|
||||
if (objects[i].checkHit(pos.x, pos.y)){
|
||||
return objects[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getLargest(data) {
|
||||
let largest = data[0].values[0];
|
||||
|
||||
data.forEach(function (categ) {
|
||||
for (let i = 0; i < categ.values.length; i++)
|
||||
if (categ.values[i] > largest) {
|
||||
largest = categ.values[i];
|
||||
}
|
||||
});
|
||||
|
||||
return largest;
|
||||
}
|
||||
|
||||
function getSmallest(data) {
|
||||
let smallest = data[0].values[0];
|
||||
|
||||
data.forEach(function (categ) {
|
||||
for (let i = 0; i < categ.values.length; i++)
|
||||
if (categ.values[i] < smallest) {
|
||||
smallest = categ.values[i];
|
||||
}
|
||||
});
|
||||
|
||||
return smallest;
|
||||
}
|
||||
|
||||
function drawAxis(bounds, largest, smallest, arrayLen, ctx, graphSettings, drawValues = true) {
|
||||
ctx.font = "16px Arial";
|
||||
if (graphSettings.y_step <= 0) graphSettings.y_step = 1;
|
||||
|
||||
ctx.beginPath();
|
||||
for (let i = (smallest < 0)?smallest:0; i <= ((largest>=0)?largest:0); i += parseFloat(graphSettings.y_step)){
|
||||
|
||||
ctx.strokeStyle = "#BBB";
|
||||
ctx.lineWidth = 1;
|
||||
let scale = bounds.height - ((largest >= 0)?(bounds.bottom - bounds.xAxis):0);
|
||||
let extreme = (largest<=0)?Math.abs(smallest):Math.abs(largest);
|
||||
let yPos = Math.round((bounds.xAxis - i * scale / extreme));
|
||||
|
||||
//support line
|
||||
if (graphSettings.display_support_lines) {
|
||||
|
||||
ctx.moveTo( bounds.left, yPos );
|
||||
ctx.lineTo( bounds.right, yPos );
|
||||
}
|
||||
|
||||
//Y axis value
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textAlign = "end";
|
||||
ctx.fillText( i, bounds.left - 3, yPos);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
//X axis value
|
||||
if (drawValues) {
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
for (let i = 0; i < arrayLen; i++){
|
||||
let x = bounds.left + bounds.width / (arrayLen - 1) * i;
|
||||
let text = (i + 1).toString();
|
||||
if (graphSettings.custom_x_values !== "")
|
||||
text = graphSettings.custom_x_values.split(';')[i];
|
||||
ctx.fillText(text, x, bounds.bottom + 18);
|
||||
}
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
//X and Y axis
|
||||
ctx.strokeStyle = "black";
|
||||
ctx.lineWidth = "2px";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo( bounds.left, bounds.top );
|
||||
ctx.lineTo( bounds.left, bounds.bottom );
|
||||
ctx.moveTo( bounds.left, bounds.xAxis);
|
||||
ctx.lineTo( bounds.right, bounds.xAxis );
|
||||
ctx.stroke();
|
||||
|
||||
//Axis labels
|
||||
//X axis text
|
||||
ctx.beginPath();
|
||||
ctx.font = "20px Arial";
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(graphSettings.x_label, bounds.width/2 + bounds.left, bounds.height + 2*bounds.top - 5);
|
||||
|
||||
//Y axis text
|
||||
ctx.save();
|
||||
ctx.rotate(-Math.PI / 2);
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(graphSettings.y_label, -(bounds.left + bounds.height/2), 18);
|
||||
ctx.restore();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
function drawTitle(canvas, graphSettings) {
|
||||
let ctx = canvas.getContext("2d");
|
||||
let x = canvas.width / 2;
|
||||
let y = 25;
|
||||
|
||||
ctx.font = "30px Arial";
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText( graphSettings.title, x, y);
|
||||
}
|
||||
|
||||
function drawPoints(ctx, bounds, values, name, arrayLen, largest, color) {
|
||||
ctx.fillStyle = color;
|
||||
let radius = 3;
|
||||
|
||||
for( let i = 0; i < arrayLen; i++ ){
|
||||
ctx.beginPath();
|
||||
if(values[i] === null) continue;
|
||||
let scale = bounds.height - ((largest >= 0)?(bounds.bottom - bounds.xAxis):0);
|
||||
let extreme = (largest<=0)?Math.abs(smallest):Math.abs(largest);
|
||||
let x = bounds.left + bounds.width / (arrayLen - 1) * i;
|
||||
let y = (bounds.xAxis - values[i] / extreme * scale);
|
||||
ctx.arc(x, y, radius, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
|
||||
let new_object = new Circle(values[i], name, x, y, radius);
|
||||
objects.push(new_object);
|
||||
}
|
||||
}
|
||||
|
||||
function drawSlice(ctx, centerX, centerY, radius, startAngle, endAngle, color ){
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(centerX,centerY);
|
||||
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
function getBounds(canvas, graphMargin) {
|
||||
return {
|
||||
top: graphMargin,
|
||||
bottom: canvas.height - graphMargin,
|
||||
left: graphMargin,
|
||||
right: canvas.width - graphMargin,
|
||||
height: canvas.height - 2*graphMargin,
|
||||
width: canvas.width - 2*graphMargin,
|
||||
xAxis: canvas.height - graphMargin
|
||||
};
|
||||
}
|
||||
|
||||
function drawPieChart(canvas, data, graphSettings) {
|
||||
|
||||
let ctx = canvas.getContext("2d");
|
||||
let index = 0;
|
||||
let start_angle = 0;
|
||||
let total_value = 0;
|
||||
let bounds = getBounds(canvas, graphSettings.margin);
|
||||
|
||||
|
||||
data.forEach(function (categ) {
|
||||
let val = categ.values[0];
|
||||
if (val !== null)
|
||||
total_value += val;
|
||||
});
|
||||
|
||||
data.forEach(function (categ) {
|
||||
let val = categ.values[0];
|
||||
let slice_angle = 2 * Math.PI * val / total_value;
|
||||
|
||||
let x = canvas.width/2;
|
||||
let y = canvas.height/2;
|
||||
let r = Math.min(bounds.width/2, bounds.height/2);
|
||||
let end_angle = start_angle + slice_angle;
|
||||
|
||||
drawSlice(ctx, x, y, r, start_angle, end_angle, categ.color);
|
||||
let new_object = new PieSlice(val + " (" + Math.round(val/total_value*100) + "%)", categ.name, x, y, r, start_angle, end_angle);
|
||||
objects.push(new_object);
|
||||
|
||||
start_angle = end_angle;
|
||||
index++;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function drawPointChart(canvas, data, graphSettings){
|
||||
let ctx = canvas.getContext( "2d" );
|
||||
|
||||
let bounds = getBounds(canvas, graphSettings.margin);
|
||||
let largest = getLargest(data);
|
||||
let smallest = getSmallest(data);
|
||||
|
||||
if (smallest < 0)
|
||||
bounds.xAxis = bounds.bottom - (bounds.height / (((largest<=0)?0:Math.abs(largest)) + Math.abs(smallest)) * Math.abs(smallest));
|
||||
let arrayLen = data[0].values.length;
|
||||
|
||||
drawAxis(bounds, largest, smallest, arrayLen, ctx, graphSettings);
|
||||
|
||||
data.display_points = true;
|
||||
data.forEach(function (categ) {
|
||||
//Points
|
||||
if (graphSettings.display_points)
|
||||
drawPoints(ctx, bounds, categ.values, categ.name, arrayLen, largest, categ.color);
|
||||
});
|
||||
}
|
||||
|
||||
function drawLineChart(canvas, data, graphSettings){
|
||||
let ctx = canvas.getContext( "2d" );
|
||||
|
||||
let bounds = getBounds(canvas, graphSettings.margin);
|
||||
let largest = getLargest(data);
|
||||
let smallest = getSmallest(data);
|
||||
|
||||
if (smallest < 0)
|
||||
bounds.xAxis = bounds.bottom - (bounds.height / (((largest<=0)?0:Math.abs(largest)) + Math.abs(smallest)) * Math.abs(smallest));
|
||||
let arrayLen = data[0].values.length;
|
||||
|
||||
drawAxis(bounds, largest, smallest, arrayLen, ctx, graphSettings);
|
||||
|
||||
data.forEach(function (categ) {
|
||||
//Lines
|
||||
ctx.beginPath();
|
||||
ctx.lineJoin = "round";
|
||||
ctx.strokeStyle = categ.color;
|
||||
|
||||
for (let i = 0; i < arrayLen; i++) {
|
||||
if (categ.values[i] === null) continue;
|
||||
|
||||
let scale = bounds.height - ((largest >= 0)?(bounds.bottom - bounds.xAxis):0);
|
||||
let extreme = (largest<=0)?Math.abs(smallest):Math.abs(largest);
|
||||
let x = bounds.left + bounds.width / (arrayLen - 1) * i;
|
||||
let y = (bounds.xAxis - categ.values[i] / extreme * scale);
|
||||
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
|
||||
//Points
|
||||
if (graphSettings.display_points)
|
||||
drawPoints(ctx, bounds, categ.values, categ.name, arrayLen, largest, categ.color);
|
||||
});
|
||||
}
|
||||
|
||||
function drawAreaChart(canvas, data, graphSettings){
|
||||
let ctx = canvas.getContext( "2d" );
|
||||
|
||||
let bounds = getBounds(canvas, graphSettings.margin);
|
||||
let largest = getLargest(data);
|
||||
let smallest = getSmallest(data);
|
||||
|
||||
if (smallest < 0)
|
||||
bounds.xAxis = bounds.bottom - (bounds.height / (((largest<=0)?0:Math.abs(largest)) + Math.abs(smallest)) * Math.abs(smallest));
|
||||
let arrayLen = data[0].values.length;
|
||||
|
||||
drawAxis(bounds, largest, smallest, arrayLen, ctx, graphSettings);
|
||||
|
||||
data.forEach(function (categ) {
|
||||
//Lines
|
||||
ctx.beginPath();
|
||||
ctx.lineJoin = "round";
|
||||
ctx.strokeStyle = categ.color;
|
||||
|
||||
let xmax = 0;
|
||||
for (let i = 0; i < arrayLen; i++) {
|
||||
if (categ.values[i] === null) continue;
|
||||
let scale = bounds.height - ((largest >= 0)?(bounds.bottom - bounds.xAxis):0);
|
||||
let extreme = (largest<=0)?Math.abs(smallest):Math.abs(largest);
|
||||
let x = bounds.left + bounds.width / (arrayLen - 1) * i;
|
||||
let y = (bounds.xAxis - categ.values[i] / extreme * scale);
|
||||
xmax = x;
|
||||
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
ctx.stroke();
|
||||
|
||||
ctx.lineTo(xmax, bounds.xAxis);
|
||||
ctx.lineTo(bounds.left, bounds.xAxis);
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.fillStyle = categ.color;
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
//Points
|
||||
if (graphSettings.display_points)
|
||||
drawPoints(ctx, bounds, categ.values, categ.name, arrayLen, largest, categ.color);
|
||||
});
|
||||
}
|
||||
|
||||
function drawBarChart(canvas, data, graphSettings) {
|
||||
let ctx = canvas.getContext( "2d" );
|
||||
|
||||
let bounds = getBounds(canvas, graphSettings.margin);
|
||||
ctx.shadowOffsetX = 15;
|
||||
ctx.shadowOffsetY = 15;
|
||||
ctx.shadowBlur = 4;
|
||||
|
||||
let largest = getLargest(data);
|
||||
let barCount = data.length;
|
||||
let dataCount = data[0].values.length;
|
||||
|
||||
let smallest = getSmallest(data);
|
||||
|
||||
if (smallest < 0)
|
||||
bounds.xAxis = bounds.bottom - (bounds.height / (((largest<=0)?0:Math.abs(largest)) + Math.abs(smallest)) * Math.abs(smallest));
|
||||
|
||||
drawAxis(bounds, largest, smallest, dataCount, ctx, graphSettings, false);
|
||||
|
||||
let size = bounds.width / dataCount;
|
||||
let innerSize = size * 0.8;
|
||||
let bar_width = innerSize * 0.7 / barCount;
|
||||
|
||||
for (let i = 0; i < dataCount; i++) {
|
||||
let num = 0;
|
||||
data.forEach(function (categ) {
|
||||
ctx.beginPath();
|
||||
let value = categ.values[i];
|
||||
let left = bounds.left + (size * (i + 0.15) + (innerSize * num / barCount));
|
||||
let scale = bounds.height - ((largest >= 0)?(bounds.bottom - bounds.xAxis):0);
|
||||
let extreme = (largest<=0)?Math.abs(smallest):Math.abs(largest);
|
||||
let bar_height = value / extreme * scale;
|
||||
let top = (bounds.xAxis - categ.values[i] / extreme * scale);
|
||||
|
||||
ctx.fillStyle = categ.color;
|
||||
ctx.fillRect(left, top, bar_width, bar_height);
|
||||
|
||||
//x value
|
||||
if (num === 0){
|
||||
let text = (i + 1).toString();
|
||||
if (graphSettings.custom_x_values !== ""){
|
||||
text = graphSettings.custom_x_values.split(';')[i];
|
||||
}
|
||||
ctx.font = "16px Arial";
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(text, bounds.width / dataCount * i + size / 2 + bounds.left, bounds.bottom + 15);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
num++;
|
||||
let new_object = new Rect(value, categ.name, left, top, bar_width, bar_height);
|
||||
objects.push(new_object);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function stackedChart(canvas, data, graphSettings) {
|
||||
let ctx = canvas.getContext( "2d" );
|
||||
|
||||
let bounds = getBounds(canvas, graphSettings.margin);
|
||||
ctx.shadowOffsetX = 15;
|
||||
ctx.shadowOffsetY = 15;
|
||||
ctx.shadowBlur = 4;
|
||||
|
||||
let dataCount = data[0].values.length;
|
||||
|
||||
let largest = 0;
|
||||
for (let i = 0; i < dataCount; i++){
|
||||
let sum = 0;
|
||||
data.forEach(function (categ) {
|
||||
categ.values[i] = Math.abs(categ.values[i]);
|
||||
sum += categ.values[i];
|
||||
});
|
||||
if (sum > largest) largest = sum;
|
||||
}
|
||||
|
||||
let smallest = getSmallest(data);
|
||||
if (smallest < 0)
|
||||
bounds.xAxis = bounds.bottom - (bounds.height / (((largest<=0)?0:Math.abs(largest)) + Math.abs(smallest)) * Math.abs(smallest));
|
||||
|
||||
drawAxis(bounds, largest, smallest, dataCount, ctx, graphSettings, false);
|
||||
|
||||
let size = bounds.width / dataCount;
|
||||
let bar_width = size * 0.7;
|
||||
|
||||
for (let i = 0; i < dataCount; i++) {
|
||||
let last_top = bounds.xAxis;
|
||||
let num = 0;
|
||||
data.forEach(function (categ) {
|
||||
ctx.beginPath();
|
||||
|
||||
let value = categ.values[i];
|
||||
let bar_height = value / largest * bounds.height;
|
||||
let left = bounds.left + (size * (i + 0.15));
|
||||
let top = last_top - bar_height;
|
||||
|
||||
ctx.fillStyle = categ.color;
|
||||
ctx.fillRect(left, top, bar_width, bar_height);
|
||||
|
||||
last_top = top;
|
||||
|
||||
//x value
|
||||
if (num === 0){
|
||||
let text = (i + 1).toString();
|
||||
if (graphSettings.custom_x_values !== ""){
|
||||
text = graphSettings.custom_x_values.split(';')[i];
|
||||
}
|
||||
ctx.font = "16px Arial";
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(text, bounds.width / dataCount * i + size / 2 + bounds.left, bounds.bottom + 15);
|
||||
ctx.stroke();
|
||||
}
|
||||
num++;
|
||||
|
||||
let new_object = new Rect(value, categ.name, left, top, bar_width, bar_height);
|
||||
objects.push(new_object);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resizeCanvas(canvas, parent, legendHeight = 0, bgColor) {
|
||||
|
||||
if (legendHeight > 0) legendHeight += 3.1;
|
||||
//set size
|
||||
canvas.style.width = parent.clientWidth.toString();
|
||||
canvas.style.height = (parent.clientHeight - legendHeight).toString();
|
||||
canvas.width = parent.clientWidth;
|
||||
canvas.height = parent.clientHeight - legendHeight;
|
||||
|
||||
//reset canvas color
|
||||
let ctx = canvas.getContext( "2d" );
|
||||
if (bgColor == null){
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
} else {
|
||||
ctx.fillStyle = bgColor;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
}
|
||||
|
||||
function updateLegend(displayLegend, data) {
|
||||
if (displayLegend){
|
||||
let legendHTML = "";
|
||||
data.forEach(function (categ) {
|
||||
legendHTML += "<div><span style='display:inline-block;width:20px;background-color:" + categ.color + ";'> </span> " + categ.col_name + "</div>";
|
||||
});
|
||||
|
||||
legend.innerHTML = legendHTML;
|
||||
legend.style.display = "block";
|
||||
} else {
|
||||
legend.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
function drawChart(graphSettings, data) {
|
||||
updateLegend(graphSettings.display_legend, data);
|
||||
resizeCanvas(canvas, parent, legend.offsetHeight, graphSettings.backgroundColor);
|
||||
objects = [];
|
||||
|
||||
//Choose the correct graph
|
||||
switch (graphSettings.type) {
|
||||
case "point":
|
||||
drawPointChart(canvas, data, graphSettings);
|
||||
break;
|
||||
case "line":
|
||||
drawLineChart(canvas, data, graphSettings);
|
||||
break;
|
||||
case "pie":
|
||||
drawPieChart(canvas, data, graphSettings);
|
||||
break;
|
||||
case "bar":
|
||||
drawBarChart(canvas, data, graphSettings);
|
||||
break;
|
||||
case "area":
|
||||
drawAreaChart(canvas, data, graphSettings);
|
||||
break;
|
||||
case "stacked":
|
||||
stackedChart(canvas, data, graphSettings);
|
||||
break;
|
||||
}
|
||||
|
||||
if (graphSettings.display_title)
|
||||
drawTitle(canvas, graphSettings);
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
class ChartLoader {
|
||||
constructor(canvas, detectionCanvas, parent, legend, dataDiv) {
|
||||
this.canvas = canvas
|
||||
this.detectionCanvas = detectionCanvas
|
||||
this.parent = parent
|
||||
this.legend = legend
|
||||
this.dataDiv = dataDiv
|
||||
}
|
||||
|
||||
//Načtení dat
|
||||
loadData(code) {
|
||||
fetch("/api/charts/" + code, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
let metadata = data.metadata;
|
||||
metadata.custom_x_values = ""
|
||||
let table = data.table
|
||||
|
||||
if (data !== null) {
|
||||
this.drawChart(metadata, table)
|
||||
this.parent.style.backgroundColor = metadata.backgroundColor
|
||||
}
|
||||
else
|
||||
this.parent.innerHTML = "graph not found."
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
addListener(newChart) {
|
||||
//Click
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
const pos = {
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
}
|
||||
|
||||
var ctx = this.detectionCanvas.getContext('2d');
|
||||
var pixelData = ctx.getImageData(pos.x, pos.y, 1, 1).data;
|
||||
|
||||
if (pixelData[3] === 255) {
|
||||
let index = (pixelData[0] * 256 + pixelData[1]) * 256 + pixelData[2]
|
||||
let obj = newChart.objects[index]
|
||||
|
||||
let divHitBox = this.dataDiv
|
||||
divHitBox.style.display = "block"
|
||||
|
||||
// make the info fit into the chart div
|
||||
if (pos.x + divHitBox.clientWidth <= this.parent.clientWidth - 2)
|
||||
divHitBox.style.left = pos.x + "px"
|
||||
else
|
||||
this.dataDiv.style.left = pos.x - divHitBox.clientWidth + "px"
|
||||
|
||||
if (pos.y + divHitBox.clientHeight <= parent.clientHeight - 2)
|
||||
this.dataDiv.style.top = pos.y + "px"
|
||||
else
|
||||
this.dataDiv.style.top = pos.y - divHitBox.clientHeight + "px"
|
||||
|
||||
this.dataDiv.style.display = "block"
|
||||
this.dataDiv.innerHTML = "<b>" + obj.name + "</b><br><p>" + obj.value + "</p>"
|
||||
}
|
||||
else {
|
||||
this.dataDiv.style.display = "none"
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener("resize", e => {
|
||||
//newChart.updateLegend(graphSettings.displayLegend, data)
|
||||
newChart.resizeCanvas(this.parent, this.legend.offsetHeight)
|
||||
newChart.draw()
|
||||
|
||||
this.detectionCanvas.width = this.canvas.width
|
||||
this.detectionCanvas.height = this.canvas.height
|
||||
this.chart.drawDetectionMap(this.detectionCanvas.getContext("2d"))
|
||||
});
|
||||
}
|
||||
|
||||
drawChart(graphSettings, data) {
|
||||
//objects = []
|
||||
this.chart = new Chart(this.canvas, data, graphSettings)
|
||||
this.chart.updateLegend(graphSettings.displayLegend, this.legend)
|
||||
|
||||
this.chart.resizeCanvas(this.parent, this.legend.offsetHeight)
|
||||
|
||||
this.detectionCanvas.width = this.canvas.width
|
||||
this.detectionCanvas.height = this.canvas.height
|
||||
|
||||
//Choose the correct graph
|
||||
switch (graphSettings.type) {
|
||||
case "point":
|
||||
this.chart = new PointChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "line":
|
||||
this.chart = new LineChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "smoothline":
|
||||
this.chart = new SmoothLineChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "pie":
|
||||
this.chart = new PieChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "donut":
|
||||
this.chart = new DonutChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "bar":
|
||||
this.chart = new BarChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "area":
|
||||
this.chart = new AreaChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "smootharea":
|
||||
this.chart = new SmoothAreaChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
case "stacked":
|
||||
this.chart = new StackedChart(this.canvas, data, graphSettings)
|
||||
break
|
||||
}
|
||||
|
||||
this.chart.draw()
|
||||
this.chart.drawDetectionMap(this.detectionCanvas.getContext("2d"))
|
||||
|
||||
this.addListener(this.chart)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
class DonutChart extends Chart {
|
||||
constructor(canvas, data, settings) {
|
||||
super(canvas, data, settings)
|
||||
}
|
||||
|
||||
draw() {
|
||||
let index = 0
|
||||
let start_angle = 0
|
||||
let total_value = 0
|
||||
|
||||
this.data.forEach(categ => {
|
||||
let val = categ.values[0]
|
||||
if (val !== null)
|
||||
total_value += val
|
||||
})
|
||||
|
||||
this.clear()
|
||||
|
||||
this.data.forEach(categ => {
|
||||
let val = categ.values[0]
|
||||
let slice_angle = 2 * Math.PI * val / total_value
|
||||
|
||||
let x = this.canvas.width / 2
|
||||
let y = this.canvas.height / 2
|
||||
let r = Math.min(this.bounds.width / 2, this.bounds.height / 2)
|
||||
let end_angle = start_angle + slice_angle
|
||||
|
||||
this.ctx.fillStyle = categ.color
|
||||
let new_slice = new DonutSlice(this.ctx, val + " (" + Math.round(val / total_value * 100) + "%)", categ.col_name, x, y, r, start_angle, end_angle, r / 2)
|
||||
new_slice.draw()
|
||||
this.objects.push(new_slice)
|
||||
|
||||
start_angle = end_angle
|
||||
index++
|
||||
})
|
||||
|
||||
if (this.settings.displayTitle)
|
||||
this.drawTitle()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
class SmoothAreaChart extends PointChart {
|
||||
constructor(canvas, data, settings) {
|
||||
super(canvas, data, settings)
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.clear()
|
||||
this.drawAxis()
|
||||
|
||||
this.data.forEach(categ => {
|
||||
//Lines
|
||||
this.ctx.beginPath()
|
||||
this.ctx.lineJoin = "round"
|
||||
this.ctx.strokeStyle = categ.color
|
||||
|
||||
let x = this.bounds.left
|
||||
let y = (this.bounds.xAxis - categ.values[0] / this.extreme * this.scale)
|
||||
this.ctx.moveTo(x, y)
|
||||
let xmax = 0
|
||||
|
||||
for (let i = 0; i < this.dataLen - 1; i++) {
|
||||
let x1 = this.bounds.left + this.bounds.width / (this.dataLen - 1) * i
|
||||
let y1 = (this.bounds.xAxis - categ.values[i] / this.extreme * this.scale)
|
||||
|
||||
let x2 = this.bounds.left + this.bounds.width / (this.dataLen - 1) * (i + 1)
|
||||
let y2 = (this.bounds.xAxis - categ.values[i + 1] / this.extreme * this.scale)
|
||||
|
||||
let xm = (x1 + x2) / 2
|
||||
let xl = (x1 + xm) / 2
|
||||
let xr = (x2 + xm) / 2
|
||||
|
||||
this.ctx.bezierCurveTo(xl, y1, xr, y2, x2, y2);
|
||||
xmax = x2
|
||||
}
|
||||
|
||||
this.ctx.lineTo(xmax, this.bounds.xAxis)
|
||||
this.ctx.lineTo(this.bounds.left, this.bounds.xAxis)
|
||||
this.ctx.globalAlpha = 0.5
|
||||
this.ctx.fillStyle = categ.color
|
||||
this.ctx.closePath()
|
||||
this.ctx.fill()
|
||||
|
||||
this.ctx.globalAlpha = 1
|
||||
})
|
||||
|
||||
// Points
|
||||
if (this.settings.displayPoints)
|
||||
this.data.forEach(categ => {this.drawPoints(categ.values, categ.col_name, categ.color)})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
class SmoothLineChart extends PointChart {
|
||||
constructor(canvas, data, settings) {
|
||||
super(canvas, data, settings)
|
||||
}
|
||||
|
||||
draw() {
|
||||
this.clear()
|
||||
this.drawAxis()
|
||||
|
||||
this.data.forEach(categ => {
|
||||
this.ctx.beginPath()
|
||||
this.ctx.lineJoin = "round"
|
||||
this.ctx.strokeStyle = categ.color
|
||||
|
||||
let x = this.bounds.left
|
||||
let y = (this.bounds.xAxis - categ.values[0] / this.extreme * this.scale)
|
||||
this.ctx.moveTo(x, y)
|
||||
|
||||
for (let i = 0; i < this.dataLen - 1; i++) {
|
||||
let x1 = this.bounds.left + this.bounds.width / (this.dataLen - 1) * i
|
||||
let y1 = (this.bounds.xAxis - categ.values[i] / this.extreme * this.scale)
|
||||
|
||||
let x2 = this.bounds.left + this.bounds.width / (this.dataLen - 1) * (i + 1)
|
||||
let y2 = (this.bounds.xAxis - categ.values[i + 1] / this.extreme * this.scale)
|
||||
|
||||
let xm = (x1 + x2) / 2
|
||||
let xl = (x1 + xm) / 2
|
||||
let xr = (x2 + xm) / 2
|
||||
|
||||
this.ctx.bezierCurveTo(xl, y1, xr, y2, x2, y2);
|
||||
}
|
||||
this.ctx.stroke()
|
||||
this.ctx.closePath()
|
||||
})
|
||||
|
||||
// Points
|
||||
if (this.settings.displayPoints)
|
||||
this.data.forEach(categ => {this.drawPoints(categ.values, categ.col_name, categ.color)})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
:root {
|
||||
--legend-height: 30px
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
#chartCanvas,
|
||||
#detectionCanvas {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#graphLegend {
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#graphLegend div {
|
||||
display: inline;
|
||||
margin: 0 10px 0 10px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
#dataDiv {
|
||||
display: none;
|
||||
position: absolute;
|
||||
height: 35px;
|
||||
width: 70px;
|
||||
background-color: white;
|
||||
border: 1px solid lightgrey;
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#dataDiv p {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#dataDiv b {
|
||||
position: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#detectionCanvas {
|
||||
opacity: 0;
|
||||
image-rendering: pixelated;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
Loading…
Reference in new issue