main
František Špaček 2 years ago
parent 3f59a07483
commit 3d021713d1

@ -17,6 +17,9 @@ framework:
php_errors: php_errors:
log: true log: true
profiler:
collect: false
when@test: when@test:
framework: framework:
test: true test: true

@ -1,6 +1,7 @@
class ChartLoader { class ChartLoader {
constructor(canvas, detectionCanvas, parent, legend, dataDiv) { constructor(canvas, effectCanvas, detectionCanvas, parent, legend, dataDiv) {
this.canvas = canvas this.canvas = canvas
this.effectCanvas = effectCanvas
this.detectionCanvas = detectionCanvas this.detectionCanvas = detectionCanvas
this.parent = parent this.parent = parent
this.legend = legend this.legend = legend
@ -38,33 +39,80 @@ class ChartLoader {
x: e.clientX, x: e.clientX,
y: e.clientY 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 ctx = this.detectionCanvas.getContext('2d');
let index = (pixelData[0] * 256 + pixelData[1]) * 256 + pixelData[2]
let obj = newChart.objects[index]
let divHitBox = this.dataDiv // Get neigboring pixels
divHitBox.style.display = "block" let imageData = Array.from(ctx.getImageData(pos.x - 2, pos.y - 2, 5, 5).data)
//console.log(imageData)
// Convert into indexes
let indexes = []
while (imageData.length > 0) {
let pixel = imageData.splice(0, 4)
// only if alpha is 100%
if (pixel[3] === 255) {
let index = (pixel[0] * 256 + pixel[1]) * 256 + pixel[2]
indexes.push(index)
}
}
function mode(array)
{
if(array.length == 0)
return null;
var modeMap = {};
var maxEl = array[0], maxCount = 1;
for(var i = 0; i < array.length; i++)
{
var el = array[i];
if(modeMap[el] == null)
modeMap[el] = 1;
else
modeMap[el]++;
if(modeMap[el] > maxCount)
{
maxEl = el;
maxCount = modeMap[el];
}
}
return maxEl;
}
// To avoid edge cases because of anti aliasing
let mostCommonIndex = mode(indexes)
if (mostCommonIndex !== null) {
let obj = newChart.objects[mostCommonIndex]
// Effect
let effectCtx = this.effectCanvas.getContext("2d")
effectCtx.clearRect(0, 0, effectCanvas.width, effectCanvas.height)
this.effectCanvas.style.opacity = 1
newChart.drawEffect(effectCtx, [obj])
this.dataDiv.style.display = "block"
// make the info fit into the chart div // make the info fit into the chart div
if (pos.x + divHitBox.clientWidth <= this.parent.clientWidth - 2) if (pos.x + this.dataDiv.clientWidth <= this.parent.clientWidth - 2)
divHitBox.style.left = pos.x + "px" this.dataDiv.style.left = pos.x + "px"
else else
this.dataDiv.style.left = pos.x - divHitBox.clientWidth + "px" this.dataDiv.style.left = pos.x - this.dataDiv.clientWidth + "px"
if (pos.y + divHitBox.clientHeight <= parent.clientHeight - 2) if (pos.y + this.dataDiv.clientHeight <= parent.clientHeight - 2)
this.dataDiv.style.top = pos.y + "px" this.dataDiv.style.top = pos.y + "px"
else else
this.dataDiv.style.top = pos.y - divHitBox.clientHeight + "px" this.dataDiv.style.top = pos.y - this.dataDiv.clientHeight + "px"
this.dataDiv.style.display = "block" this.dataDiv.style.display = "block"
this.dataDiv.innerHTML = "<b>" + obj.name + "</b><br><p>" + obj.value + "</p>" this.dataDiv.innerHTML = "<b>" + obj.name + "</b><br><p>" + obj.value + "</p>"
} }
else { else {
this.dataDiv.style.display = "none" this.dataDiv.style.display = "none"
this.effectCanvas.style.opacity = 0
} }
}) })
@ -73,22 +121,22 @@ class ChartLoader {
newChart.resizeCanvas(this.parent, this.legend.offsetHeight) newChart.resizeCanvas(this.parent, this.legend.offsetHeight)
newChart.draw() newChart.draw()
this.detectionCanvas.width = this.canvas.width setTimeout(() => {
this.detectionCanvas.height = this.canvas.height this.effectCanvas.width = this.canvas.width
this.chart.drawDetectionMap(this.detectionCanvas.getContext("2d")) this.effectCanvas.height = this.canvas.height
this.detectionCanvas.width = this.canvas.width
this.detectionCanvas.height = this.canvas.height
this.chart.drawDetectionMap(this.detectionCanvas.getContext("2d"))
}, 0)
}); });
} }
drawChart(graphSettings, data) { drawChart(graphSettings, data) {
//objects = []
this.chart = new Chart(this.canvas, data, graphSettings) this.chart = new Chart(this.canvas, data, graphSettings)
this.chart.updateLegend(graphSettings.displayLegend, this.legend)
this.chart.updateLegend(graphSettings.displayLegend, this.legend)
this.chart.resizeCanvas(this.parent, this.legend.offsetHeight) this.chart.resizeCanvas(this.parent, this.legend.offsetHeight)
this.detectionCanvas.width = this.canvas.width
this.detectionCanvas.height = this.canvas.height
//Choose the correct graph //Choose the correct graph
switch (graphSettings.type) { switch (graphSettings.type) {
case "point": case "point":
@ -120,8 +168,20 @@ class ChartLoader {
break break
} }
console.time("1")
this.chart.draw() this.chart.draw()
this.chart.drawDetectionMap(this.detectionCanvas.getContext("2d")) console.timeEnd("1")
setTimeout(() => {
console.time("2")
this.effectCanvas.width = this.canvas.width
this.effectCanvas.height = this.canvas.height
this.detectionCanvas.width = this.canvas.width
this.detectionCanvas.height = this.canvas.height
this.chart.drawDetectionMap(this.detectionCanvas.getContext("2d"))
console.timeEnd("2")
}, 0); {
}
this.addListener(this.chart) this.addListener(this.chart)
} }

@ -34,15 +34,18 @@ class BarChart extends Chart {
/*if (this.settings.custom_x_values !== "") /*if (this.settings.custom_x_values !== "")
text = this.settings.custom_x_values.split(';')[i]*/ text = this.settings.custom_x_values.split(';')[i]*/
this.ctx.beginPath()
this.ctx.font = "16px Arial" this.ctx.font = "16px Arial"
this.ctx.fillStyle = "black" this.ctx.fillStyle = "black"
this.ctx.textAlign = "center" this.ctx.textAlign = "center"
this.ctx.fillText(text, this.bounds.width / this.dataLen * i + size / 2 + this.bounds.left, this.bounds.bottom + 15) this.ctx.fillText(text, this.bounds.width / this.dataLen * i + size / 2 + this.bounds.left, this.bounds.bottom + 15)
this.ctx.stroke() this.ctx.stroke()
this.ctx.closePath()
} }
num++ num++
this.ctx.fillStyle = categ.color this.ctx.fillStyle = categ.color
this.ctx.lineWidth = 0
let new_object = new Rectangle(this.ctx, value, categ.col_name, left, top, bar_width, bar_height) let new_object = new Rectangle(this.ctx, value, categ.col_name, left, top, bar_width, bar_height)
new_object.draw() new_object.draw()
this.objects.push(new_object) this.objects.push(new_object)

@ -10,8 +10,6 @@ class Shape {
this.index = Shape.globalIndex++ this.index = Shape.globalIndex++
} }
checkHit() { return false }
draw() { } draw() { }
} }
@ -22,15 +20,11 @@ class Rectangle extends Shape {
this.h = h this.h = h
} }
checkHit(mouseX, mouseY) {
return (mouseX >= this.x && mouseX <= this.x + this.w
&& mouseY >= this.y && mouseY <= this.y + this.h)
}
draw(ctx = this.ctx) { draw(ctx = this.ctx) {
ctx.beginPath() ctx.beginPath()
ctx.fillRect(this.x, this.y, this.w, this.h) ctx.rect(this.x, this.y, this.w, this.h)
ctx.closePath() ctx.fill()
//ctx.closePath()
} }
} }
@ -40,16 +34,11 @@ class Circle extends Shape {
this.r = r this.r = r
} }
checkHit(mouseX, mouseY) {
return Math.pow((mouseX - this.x), 2) + Math.pow((mouseY - this.y), 2) <= Math.pow(this.r, 2);
}
draw(ctx = this.ctx) { draw(ctx = this.ctx) {
ctx.beginPath() ctx.beginPath()
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI) ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI)
ctx.fill() ctx.fill()
ctx.stroke() //ctx.closePath()
ctx.closePath()
} }
} }
@ -60,26 +49,13 @@ class PieSlice extends Circle {
this.eAngle = eAngle this.eAngle = eAngle
} }
checkHit(mouseX, mouseY) {
if (super.checkHit(mouseX, mouseY)) {
var dy = mouseY - this.y
var dx = mouseX - this.x
var theta = Math.atan2(dy, dx) // range (-PI, PI]
if (theta < 0)
theta += 2 * Math.PI
return (theta > this.sAngle && theta < this.eAngle)
}
return false
}
draw(ctx = this.ctx) { draw(ctx = this.ctx) {
ctx.beginPath() ctx.beginPath()
ctx.moveTo(this.x, this.y) ctx.moveTo(this.x, this.y)
ctx.arc(this.x, this.y, this.r, this.sAngle, this.eAngle) ctx.arc(this.x, this.y, this.r, this.sAngle, this.eAngle)
ctx.lineTo(this.x, this.y)
ctx.fill() ctx.fill()
ctx.closePath() //ctx.closePath()
} }
} }
@ -91,11 +67,12 @@ class DonutSlice extends PieSlice {
draw(ctx = this.ctx) { draw(ctx = this.ctx) {
ctx.beginPath() ctx.beginPath()
ctx.moveTo(this.x, this.y) // move to start of the slice using polar coordinates
ctx.moveTo(this.x + this.r2 * Math.cos(this.sAngle), this.y + this.r2 * Math.sin(this.sAngle))
ctx.arc(this.x, this.y, this.r, this.sAngle, this.eAngle, false) ctx.arc(this.x, this.y, this.r, this.sAngle, this.eAngle, false)
ctx.arc(this.x, this.y, this.r2, this.eAngle, this.sAngle, true) ctx.arc(this.x, this.y, this.r2, this.eAngle, this.sAngle, true)
ctx.fill() ctx.fill()
ctx.closePath() //ctx.closePath()
} }
} }
@ -166,13 +143,13 @@ class Chart {
return result return result
} }
checkHit(pos) { /*checkHit(pos) {
for (let i = 0; i < this.objects.length; i++) for (let i = 0; i < this.objects.length; i++)
if (this.objects[i].checkHit(pos.x, pos.y)) if (this.objects[i].checkHit(pos.x, pos.y))
return this.objects[i] return this.objects[i]
return null return null
} }*/
drawTitle() { drawTitle() {
let x = this.canvas.width / 2 let x = this.canvas.width / 2
@ -221,16 +198,40 @@ class Chart {
} }
drawDetectionMap(ctx) { drawDetectionMap(ctx) {
ctx.moveTo(0.5, 0.5)
ctx.lineWidth = 3
this.objects.forEach(object => { this.objects.forEach(object => {
let color = "#" + object.index.toString(16).padStart(6, '0') let color = "#" + object.index.toString(16).padStart(6, '0')
ctx.fillStyle = color ctx.fillStyle = color
ctx.strokeStyle = color ctx.strokeStyle = color
ctx.lineWidth = 3
object.draw(ctx) object.draw(ctx)
}) })
} }
drawEffect(ctx, objects) {
objects.forEach(object => {
ctx.globalCompositeOperation = "source-over"
ctx.fillStyle = 'rgba(0,0,0,1)'
ctx.strokeStyle = 'rgba(0,0,0,0)'
object.draw(ctx)
ctx.stroke()
ctx.globalCompositeOperation = "source-out"
ctx.lineWidth = 3
ctx.fillStyle = 'rgba(0,0,0,0)'
ctx.strokeStyle = 'rgba(0,0,0,0.7)'
ctx.stroke()
ctx.globalCompositeOperation = "source-over"
ctx.fillStyle = 'rgba(255,255,255,0.2)'
ctx.strokeStyle = 'rgba(0,0,0,0)'
object.draw(ctx)
ctx.stroke()
})
}
drawAxis(displayAxisValues = this.settings.displayAxisValues) { drawAxis(displayAxisValues = this.settings.displayAxisValues) {
this.ctx.font = this.settings.labelFont.size + "px " + this.settings.labelFont.font this.ctx.font = this.settings.labelFont.size + "px " + this.settings.labelFont.font
if (this.settings.yStep <= 0 || !this.settings.yStep) this.settings.yStep = 1 if (this.settings.yStep <= 0 || !this.settings.yStep) this.settings.yStep = 1

@ -41,11 +41,13 @@ class StackedChart extends Chart {
/*if (this.settings.custom_x_values !== "") /*if (this.settings.custom_x_values !== "")
text = this.settings.custom_x_values.split(';')[i]*/ text = this.settings.custom_x_values.split(';')[i]*/
this.ctx.beginPath()
this.ctx.font = "16px Arial" this.ctx.font = "16px Arial"
this.ctx.fillStyle = "black" this.ctx.fillStyle = "black"
this.ctx.textAlign = "center" this.ctx.textAlign = "center"
this.ctx.fillText(text, this.bounds.width / this.dataLen * i + size / 2 + this.bounds.left, this.bounds.bottom + 15) this.ctx.fillText(text, this.bounds.width / this.dataLen * i + size / 2 + this.bounds.left, this.bounds.bottom + 15)
this.ctx.stroke() this.ctx.stroke()
this.ctx.closePath()
} }
num++ num++

@ -9,6 +9,7 @@ body {
} }
#chartCanvas, #chartCanvas,
#effectCanvas,
#detectionCanvas { #detectionCanvas {
grid-column: 1; grid-column: 1;
grid-row: 1; grid-row: 1;
@ -58,6 +59,8 @@ html {
#detectionCanvas { #detectionCanvas {
opacity: 0; opacity: 0;
image-rendering: pixelated; }
image-rendering: crisp-edges;
#effectCanvas {
transition: opacity 0.3s;
} }

@ -27,12 +27,13 @@
document.addEventListener("DOMContentLoaded", function(event){ document.addEventListener("DOMContentLoaded", function(event){
let canvas = document.getElementById("chartCanvas") let canvas = document.getElementById("chartCanvas")
let effectCanvas = document.getElementById("effectCanvas")
let detectionCanvas = document.getElementById("detectionCanvas") let detectionCanvas = document.getElementById("detectionCanvas")
let parent = document.body let parent = document.body
let legend = document.getElementById("graphLegend") let legend = document.getElementById("graphLegend")
let dataDiv = document.getElementById("dataDiv") let dataDiv = document.getElementById("dataDiv")
let chartLoader = new ChartLoader(canvas, detectionCanvas, parent, legend, dataDiv) let chartLoader = new ChartLoader(canvas, effectCanvas, detectionCanvas, parent, legend, dataDiv)
chartLoader.loadData({{ code }}) chartLoader.loadData({{ code }})
}) })
</script> </script>
@ -40,6 +41,7 @@
{% block body %} {% block body %}
<canvas id="chartCanvas"></canvas> <canvas id="chartCanvas"></canvas>
<canvas id="effectCanvas"></canvas>
<canvas id="detectionCanvas"></canvas> <canvas id="detectionCanvas"></canvas>
<div id="graphLegend"></div> <div id="graphLegend"></div>
<div id="dataDiv"></div> <div id="dataDiv"></div>

Loading…
Cancel
Save

Powered by TurnKey Linux.