Javascript asynchronous filling bars using callbacks - javascript

I am new to javascript and unfortunately (or fortunately?) have tackle with the issue of asynchronous events in js. I know we should use callbacks and I did try using them with no good results.
There are 3 functions that each fills a bar, how could I use callbacks to make the bars fill one after the other?
var x1 = 0;
var x2 = 0;
var x3 = 0;
var lifeRemaining = 100 - (getPercentage(age, lifeExpectancy) + getPercentage(
effLifeRemaining, lifeExpectancy));
function ShowBar1() {
if (x1 < getPercentage(age, lifeExpectancy)) {
x1 += 1;
var y1 = "width: " + x1.toString() + "%";
progressBar1.setAttribute("style", y1);
progressBar1.textContent = x1.toString() + "%";
}
}
function ShowBar2() {
if (x2 < getPercentage(effLifeRemaining, lifeExpectancy)) {
x2 += 1;
var y2 = "width: " + x2.toString() + "%";
progressBar2.setAttribute("style", y2);
progressBar2.textContent = x2.toString() + "%"
}
}
function ShowBar3() {
if (x3 < lifeRemaining) {
x3 += 1;
var y3 = "width: " + x3.toString() + "%";
progressBar3.setAttribute("style", y3);
progressBar3.textContent = x3.toString() + "%";
}
}
setInterval(ShowBar1, 50);
setInterval(ShowBar2, 50);
setInterval(ShowBar3, 50);

You do not need to use interval if you have callback. You can refer below for sample callback:
var x1 = 0;
var x2 = 0;
var x3 = 0;
var lifeRemaining = 100 - (getPercentage(age, lifeExpectancy) + getPercentage(
effLifeRemaining, lifeExpectancy));
function ShowBar1(callback) {
if (x1 < getPercentage(age, lifeExpectancy)) {
x1 += 1;
var y1 = "width: " + x1.toString() + "%";
progressBar1.setAttribute("style", y1);
progressBar1.textContent = x1.toString() + "%";
}
return callback;
}
function ShowBar2(callback) {
if (x2 < getPercentage(effLifeRemaining, lifeExpectancy)) {
x2 += 1;
var y2 = "width: " + x2.toString() + "%";
progressBar2.setAttribute("style", y2);
progressBar2.textContent = x2.toString() + "%"
}
return callback;
}
function ShowBar3() {
if (x3 < lifeRemaining) {
x3 += 1;
var y3 = "width: " + x3.toString() + "%";
progressBar3.setAttribute("style", y3);
progressBar3.textContent = x3.toString() + "%";
}
}
var bar2 = ShowBar1(ShowBar2);
var bar3 = bar2(ShowBar3);
bar3();
You can refer below for callback that executes the 3 function with a 50 ms delay. I just remove extra code for simplification.
function ShowBar1(callback, callback2) {
console.log('ShowBar1');
callback(callback2);
}
function ShowBar2(callback) {
console.log('ShowBar2');
callback();
}
function ShowBar3() {
console.log('ShowBar3');
setTimeout(ShowBar1, 50, ShowBar2, ShowBar3);
}
ShowBar1(ShowBar2, ShowBar3);

All your three Intervals running together forever in parallel
You have to do something like this:
var x1 = 0;
var x2 = 0;
var x3 = 0;
var lifeRemaining = 100 - (getPercentage(age, lifeExpectancy) + getPercentage(
effLifeRemaining, lifeExpectancy));
var curInterval;
curInterval = setInterval(ShowBar1, 50)
function ShowBar1() {
if (x1 < getPercentage(age, lifeExpectancy)) {
x1 += 1;
var y1 = "width: " + x1 + "%";
progressBar1.setAttribute("style", y1);
progressBar1.textContent = x1 + "%";
} else {
clearInterval(curInterval);
curInterval = setInterval(ShowBar2, 50)
}
}
function ShowBar2() {
if (x2 < getPercentage(effLifeRemaining, lifeExpectancy)) {
x2 += 1;
var y2 = "width: " + x2 + "%";
progressBar2.setAttribute("style", y2);
progressBar2.textContent = x2 + "%"
} else {
clearInterval(curInterval);
curInterval = setInterval(ShowBar3, 50)
}
}
function ShowBar3() {
if (x3 < lifeRemaining) {
x3 += 1;
var y3 = "width: " + x3 + "%";
progressBar3.setAttribute("style", y3);
progressBar3.textContent = x3 + "%";
} else {
clearInterval(curInterval);
}
}

Here, finally solved it, using call backs, all three bars start filling one after the other, see
function ShowBar1(callback) {
var x1 = 0;
var y1;
progressBar2.setAttribute("style", "width: 0%");
progressBar3.setAttribute("style", "width: 0%");
var test = setInterval(function() {
x1 += 1;
y1 = "width: " + x1.toString() + "%";
progressBar1.setAttribute("style", y1);
progressBar1.textContent = x1.toString() + "%";
if (x1 === getPercentage(age, lifeExpectancy)) {
clearInterval(test);
callback(); //bar 2 starts filling using callback
}
}, 50);
}
function ShowBar2() {
var x2 = 0;
var y2;
var test2 = setInterval(function() {
x2 += 1;
y2 = "width: " + x2.toString() + "%";
progressBar2.setAttribute("style", y2);
progressBar2.textContent = x2.toString() + "%"
if (x2 === getPercentage(effLifeRemaining,
lifeExpectancy)) {
clearInterval(test2); //bar 3 starts filling from this point
var x3 = 0;
var y3;
var test3 = setInterval(function() {
x3 += 1;
y3 = "width: " + x3.toString() + "%";
progressBar3.setAttribute("style", y3);
progressBar3.textContent = x3.toString() +
"%";
if (x3 == lifeRemaining) {
clearInterval(test3);
}
}, 50);
}
}, 50);
}
ShowBar1(ShowBar2);

Related

JS chart > data to outer space

I am using this chart, with the data in the original var oData it works fantastic. But when I add my values the cart is drawn anywhere but not is the chart it self. The strange thing is, when I change this original data the chart is updated correctly! Any suggestions?
Original data with no issues:
var oData = {
"2008": 10,
"2009": 39.9,
"2010": 17,
"2011": 30.0,
"2012": 5.3,
"2013": 38.4,
"2014": 15.7,
"2015": 9.0
};
When I change this data to there are no issues:
var oData = {
"2008": 100,
"2009": 390.9,
"2010": 170,
"2011": 300.0,
"2012": 50.3,
"2013": 380.4,
"2014": 150.7,
"2015": 90.0
};
My data:
var oData = {
"1220": 262,
"1120": 338,
"1020": 244,
"0920": 314,
"0820": 311,
"0720": 302,
"0620": 300,
"0520": 269,
"0420": 232,
"0320": 347
};
var label = document.querySelector(".label");
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cw = c.width = 700;
var ch = c.height = 350;
var cx = cw / 2,
cy = ch / 2;
var rad = Math.PI / 180;
var frames = 0;
ctx.lineWidth = 1;
ctx.strokeStyle = "#999";
ctx.fillStyle = "#ccc";
ctx.font = "14px monospace";
var grd = ctx.createLinearGradient(0, 0, 0, cy);
grd.addColorStop(0, "hsla(167,72%,60%,1)");
grd.addColorStop(1, "hsla(167,72%,60%,0)");
var oData = {
"2008": 10,
"2009": 39.9,
"2010": 17,
"2011": 30.0,
"2012": 5.3,
"2013": 38.4,
"2014": 15.7,
"2015": 9.0
};
var valuesRy = [];
var propsRy = [];
for (var prop in oData) {
valuesRy.push(oData[prop]);
propsRy.push(prop);
}
var vData = 4;
var hData = valuesRy.length;
var offset = 50.5; //offset chart axis
var chartHeight = ch - 2 * offset;
var chartWidth = cw - 2 * offset;
var t = 1 / 7; // curvature : 0 = no curvature
var speed = 2; // for the animation
var A = {
x: offset,
y: offset
}
var B = {
x: offset,
y: offset + chartHeight
}
var C = {
x: offset + chartWidth,
y: offset + chartHeight
}
/*
A ^
| |
+ 25
|
|
|
+ 25
|__|_________________________________ C
B
*/
// CHART AXIS -------------------------
ctx.beginPath();
ctx.moveTo(A.x, A.y);
ctx.lineTo(B.x, B.y);
ctx.lineTo(C.x, C.y);
ctx.stroke();
// vertical ( A - B )
var aStep = (chartHeight - 50) / (vData);
var Max = Math.ceil(arrayMax(valuesRy) / 10) * 10;
var Min = Math.floor(arrayMin(valuesRy) / 10) * 10;
var aStepValue = (Max - Min) / (vData);
console.log("aStepValue: " + aStepValue); //8 units
var verticalUnit = aStep / aStepValue;
var a = [];
ctx.textAlign = "right";
ctx.textBaseline = "middle";
for (var i = 0; i <= vData; i++) {
if (i == 0) {
a[i] = {
x: A.x,
y: A.y + 25,
val: Max
}
} else {
a[i] = {}
a[i].x = a[i - 1].x;
a[i].y = a[i - 1].y + aStep;
a[i].val = a[i - 1].val - aStepValue;
}
drawCoords(a[i], 3, 0);
}
//horizontal ( B - C )
var b = [];
ctx.textAlign = "center";
ctx.textBaseline = "hanging";
var bStep = chartWidth / (hData + 1);
for (var i = 0; i < hData; i++) {
if (i == 0) {
b[i] = {
x: B.x + bStep,
y: B.y,
val: propsRy[0]
};
} else {
b[i] = {}
b[i].x = b[i - 1].x + bStep;
b[i].y = b[i - 1].y;
b[i].val = propsRy[i]
}
drawCoords(b[i], 0, 3)
}
function drawCoords(o, offX, offY) {
ctx.beginPath();
ctx.moveTo(o.x - offX, o.y - offY);
ctx.lineTo(o.x + offX, o.y + offY);
ctx.stroke();
ctx.fillText(o.val, o.x - 2 * offX, o.y + 2 * offY);
}
//----------------------------------------------------------
// DATA
var oDots = [];
var oFlat = [];
var i = 0;
for (var prop in oData) {
oDots[i] = {}
oFlat[i] = {}
oDots[i].x = b[i].x;
oFlat[i].x = b[i].x;
oDots[i].y = b[i].y - oData[prop] * verticalUnit - 25;
oFlat[i].y = b[i].y - 25;
oDots[i].val = oData[b[i].val];
i++
}
///// Animation Chart ///////////////////////////
//var speed = 3;
function animateChart() {
requestId = window.requestAnimationFrame(animateChart);
frames += speed; //console.log(frames)
ctx.clearRect(60, 0, cw, ch - 60);
for (var i = 0; i < oFlat.length; i++) {
if (oFlat[i].y > oDots[i].y) {
oFlat[i].y -= speed;
}
}
drawCurve(oFlat);
for (var i = 0; i < oFlat.length; i++) {
ctx.fillText(oDots[i].val, oFlat[i].x, oFlat[i].y - 25);
ctx.beginPath();
ctx.arc(oFlat[i].x, oFlat[i].y, 3, 0, 2 * Math.PI);
ctx.fill();
}
if (frames >= Max * verticalUnit) {
window.cancelAnimationFrame(requestId);
}
}
requestId = window.requestAnimationFrame(animateChart);
/////// EVENTS //////////////////////
c.addEventListener("mousemove", function(e) {
label.innerHTML = "";
label.style.display = "none";
this.style.cursor = "default";
var m = oMousePos(this, e);
for (var i = 0; i < oDots.length; i++) {
output(m, i);
}
}, false);
function output(m, i) {
ctx.beginPath();
ctx.arc(oDots[i].x, oDots[i].y, 20, 0, 2 * Math.PI);
if (ctx.isPointInPath(m.x, m.y)) {
//console.log(i);
label.style.display = "block";
label.style.top = (m.y + 10) + "px";
label.style.left = (m.x + 10) + "px";
label.innerHTML = "<strong>" + propsRy[i] + "</strong>: " + valuesRy[i] + "%";
c.style.cursor = "pointer";
}
}
// CURVATURE
function controlPoints(p) {
// given the points array p calculate the control points
var pc = [];
for (var i = 1; i < p.length - 1; i++) {
var dx = p[i - 1].x - p[i + 1].x; // difference x
var dy = p[i - 1].y - p[i + 1].y; // difference y
// the first control point
var x1 = p[i].x - dx * t;
var y1 = p[i].y - dy * t;
var o1 = {
x: x1,
y: y1
};
// the second control point
var x2 = p[i].x + dx * t;
var y2 = p[i].y + dy * t;
var o2 = {
x: x2,
y: y2
};
// building the control points array
pc[i] = [];
pc[i].push(o1);
pc[i].push(o2);
}
return pc;
}
function drawCurve(p) {
var pc = controlPoints(p); // the control points array
ctx.beginPath();
//ctx.moveTo(p[0].x, B.y- 25);
ctx.lineTo(p[0].x, p[0].y);
// the first & the last curve are quadratic Bezier
// because I'm using push(), pc[i][1] comes before pc[i][0]
ctx.quadraticCurveTo(pc[1][1].x, pc[1][1].y, p[1].x, p[1].y);
if (p.length > 2) {
// central curves are cubic Bezier
for (var i = 1; i < p.length - 2; i++) {
ctx.bezierCurveTo(pc[i][0].x, pc[i][0].y, pc[i + 1][1].x, pc[i + 1][1].y, p[i + 1].x, p[i + 1].y);
}
// the first & the last curve are quadratic Bezier
var n = p.length - 1;
ctx.quadraticCurveTo(pc[n - 1][0].x, pc[n - 1][0].y, p[n].x, p[n].y);
}
//ctx.lineTo(p[p.length-1].x, B.y- 25);
ctx.stroke();
ctx.save();
ctx.fillStyle = grd;
ctx.fill();
ctx.restore();
}
function arrayMax(array) {
return Math.max.apply(Math, array);
};
function arrayMin(array) {
return Math.min.apply(Math, array);
};
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return { //objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
body {
margin: 0;
overflow: hidden;
background: #152B39;
font-family: Courier, monospace;
font-size: 14px;
color:#ccc;
}
.wrapper {
display: block;
margin: 5em auto;
border: 1px solid #555;
width: 700px;
height: 350px;
position: relative;
}
p{text-align:center;}
.label {
height: 1em;
padding: .3em;
background: rgba(255, 255, 255, .8);
position: absolute;
display: none;
color:#333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<canvas id='c'></canvas>
<div class="label">text</div>
</div>
<p>Please mouse over the dots</p>
var label = document.querySelector(".label");
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cw = c.width = 700;
var ch = c.height = 350;
var cx = cw / 2,
cy = ch / 2;
var rad = Math.PI / 180;
var frames = 0;
ctx.lineWidth = 1;
ctx.strokeStyle = "#999";
ctx.fillStyle = "#ccc";
ctx.font = "14px monospace";
var grd = ctx.createLinearGradient(0, 0, 0, cy);
grd.addColorStop(0, "hsla(167,72%,60%,1)");
grd.addColorStop(1, "hsla(167,72%,60%,0)");
var oData = {
"2008": 100,
"2009": 390.9,
"2010": 170,
"2011": 300.0,
"2012": 50.3,
"2013": 380.4,
"2014": 150.7,
"2015": 90.0
};
var valuesRy = [];
var propsRy = [];
for (var prop in oData) {
valuesRy.push(oData[prop]);
propsRy.push(prop);
}
var vData = 4;
var hData = valuesRy.length;
var offset = 50.5; //offset chart axis
var chartHeight = ch - 2 * offset;
var chartWidth = cw - 2 * offset;
var t = 1 / 7; // curvature : 0 = no curvature
var speed = 2; // for the animation
var A = {
x: offset,
y: offset
}
var B = {
x: offset,
y: offset + chartHeight
}
var C = {
x: offset + chartWidth,
y: offset + chartHeight
}
/*
A ^
| |
+ 25
|
|
|
+ 25
|__|_________________________________ C
B
*/
// CHART AXIS -------------------------
ctx.beginPath();
ctx.moveTo(A.x, A.y);
ctx.lineTo(B.x, B.y);
ctx.lineTo(C.x, C.y);
ctx.stroke();
// vertical ( A - B )
var aStep = (chartHeight - 50) / (vData);
var Max = Math.ceil(arrayMax(valuesRy) / 10) * 10;
var Min = Math.floor(arrayMin(valuesRy) / 10) * 10;
var aStepValue = (Max - Min) / (vData);
console.log("aStepValue: " + aStepValue); //8 units
var verticalUnit = aStep / aStepValue;
var a = [];
ctx.textAlign = "right";
ctx.textBaseline = "middle";
for (var i = 0; i <= vData; i++) {
if (i == 0) {
a[i] = {
x: A.x,
y: A.y + 25,
val: Max
}
} else {
a[i] = {}
a[i].x = a[i - 1].x;
a[i].y = a[i - 1].y + aStep;
a[i].val = a[i - 1].val - aStepValue;
}
drawCoords(a[i], 3, 0);
}
//horizontal ( B - C )
var b = [];
ctx.textAlign = "center";
ctx.textBaseline = "hanging";
var bStep = chartWidth / (hData + 1);
for (var i = 0; i < hData; i++) {
if (i == 0) {
b[i] = {
x: B.x + bStep,
y: B.y,
val: propsRy[0]
};
} else {
b[i] = {}
b[i].x = b[i - 1].x + bStep;
b[i].y = b[i - 1].y;
b[i].val = propsRy[i]
}
drawCoords(b[i], 0, 3)
}
function drawCoords(o, offX, offY) {
ctx.beginPath();
ctx.moveTo(o.x - offX, o.y - offY);
ctx.lineTo(o.x + offX, o.y + offY);
ctx.stroke();
ctx.fillText(o.val, o.x - 2 * offX, o.y + 2 * offY);
}
//----------------------------------------------------------
// DATA
var oDots = [];
var oFlat = [];
var i = 0;
for (var prop in oData) {
oDots[i] = {}
oFlat[i] = {}
oDots[i].x = b[i].x;
oFlat[i].x = b[i].x;
oDots[i].y = b[i].y - oData[prop] * verticalUnit - 25;
oFlat[i].y = b[i].y - 25;
oDots[i].val = oData[b[i].val];
i++
}
///// Animation Chart ///////////////////////////
//var speed = 3;
function animateChart() {
requestId = window.requestAnimationFrame(animateChart);
frames += speed; //console.log(frames)
ctx.clearRect(60, 0, cw, ch - 60);
for (var i = 0; i < oFlat.length; i++) {
if (oFlat[i].y > oDots[i].y) {
oFlat[i].y -= speed;
}
}
drawCurve(oFlat);
for (var i = 0; i < oFlat.length; i++) {
ctx.fillText(oDots[i].val, oFlat[i].x, oFlat[i].y - 25);
ctx.beginPath();
ctx.arc(oFlat[i].x, oFlat[i].y, 3, 0, 2 * Math.PI);
ctx.fill();
}
if (frames >= Max * verticalUnit) {
window.cancelAnimationFrame(requestId);
}
}
requestId = window.requestAnimationFrame(animateChart);
/////// EVENTS //////////////////////
c.addEventListener("mousemove", function(e) {
label.innerHTML = "";
label.style.display = "none";
this.style.cursor = "default";
var m = oMousePos(this, e);
for (var i = 0; i < oDots.length; i++) {
output(m, i);
}
}, false);
function output(m, i) {
ctx.beginPath();
ctx.arc(oDots[i].x, oDots[i].y, 20, 0, 2 * Math.PI);
if (ctx.isPointInPath(m.x, m.y)) {
//console.log(i);
label.style.display = "block";
label.style.top = (m.y + 10) + "px";
label.style.left = (m.x + 10) + "px";
label.innerHTML = "<strong>" + propsRy[i] + "</strong>: " + valuesRy[i] + "%";
c.style.cursor = "pointer";
}
}
// CURVATURE
function controlPoints(p) {
// given the points array p calculate the control points
var pc = [];
for (var i = 1; i < p.length - 1; i++) {
var dx = p[i - 1].x - p[i + 1].x; // difference x
var dy = p[i - 1].y - p[i + 1].y; // difference y
// the first control point
var x1 = p[i].x - dx * t;
var y1 = p[i].y - dy * t;
var o1 = {
x: x1,
y: y1
};
// the second control point
var x2 = p[i].x + dx * t;
var y2 = p[i].y + dy * t;
var o2 = {
x: x2,
y: y2
};
// building the control points array
pc[i] = [];
pc[i].push(o1);
pc[i].push(o2);
}
return pc;
}
function drawCurve(p) {
var pc = controlPoints(p); // the control points array
ctx.beginPath();
//ctx.moveTo(p[0].x, B.y- 25);
ctx.lineTo(p[0].x, p[0].y);
// the first & the last curve are quadratic Bezier
// because I'm using push(), pc[i][1] comes before pc[i][0]
ctx.quadraticCurveTo(pc[1][1].x, pc[1][1].y, p[1].x, p[1].y);
if (p.length > 2) {
// central curves are cubic Bezier
for (var i = 1; i < p.length - 2; i++) {
ctx.bezierCurveTo(pc[i][0].x, pc[i][0].y, pc[i + 1][1].x, pc[i + 1][1].y, p[i + 1].x, p[i + 1].y);
}
// the first & the last curve are quadratic Bezier
var n = p.length - 1;
ctx.quadraticCurveTo(pc[n - 1][0].x, pc[n - 1][0].y, p[n].x, p[n].y);
}
//ctx.lineTo(p[p.length-1].x, B.y- 25);
ctx.stroke();
ctx.save();
ctx.fillStyle = grd;
ctx.fill();
ctx.restore();
}
function arrayMax(array) {
return Math.max.apply(Math, array);
};
function arrayMin(array) {
return Math.min.apply(Math, array);
};
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return { //objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
body {
margin: 0;
overflow: hidden;
background: #152B39;
font-family: Courier, monospace;
font-size: 14px;
color:#ccc;
}
.wrapper {
display: block;
margin: 5em auto;
border: 1px solid #555;
width: 700px;
height: 350px;
position: relative;
}
p{text-align:center;}
.label {
height: 1em;
padding: .3em;
background: rgba(255, 255, 255, .8);
position: absolute;
display: none;
color:#333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<canvas id='c'></canvas>
<div class="label">text</div>
</div>
<p>Please mouse over the dots</p>
var label = document.querySelector(".label");
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cw = c.width = 700;
var ch = c.height = 350;
var cx = cw / 2,
cy = ch / 2;
var rad = Math.PI / 180;
var frames = 0;
ctx.lineWidth = 1;
ctx.strokeStyle = "#999";
ctx.fillStyle = "#ccc";
ctx.font = "14px monospace";
var grd = ctx.createLinearGradient(0, 0, 0, cy);
grd.addColorStop(0, "hsla(167,72%,60%,1)");
grd.addColorStop(1, "hsla(167,72%,60%,0)");
var oData = {
"1220": 262,
"1120": 338,
"1020": 244,
"0920": 314,
"0820": 311,
"0720": 302,
"0620": 300,
"0520": 269,
"0420": 232,
"0320": 347
};
var valuesRy = [];
var propsRy = [];
for (var prop in oData) {
valuesRy.push(oData[prop]);
propsRy.push(prop);
}
var vData = 4;
var hData = valuesRy.length;
var offset = 50.5; //offset chart axis
var chartHeight = ch - 2 * offset;
var chartWidth = cw - 2 * offset;
var t = 1 / 7; // curvature : 0 = no curvature
var speed = 2; // for the animation
var A = {
x: offset,
y: offset
}
var B = {
x: offset,
y: offset + chartHeight
}
var C = {
x: offset + chartWidth,
y: offset + chartHeight
}
/*
A ^
| |
+ 25
|
|
|
+ 25
|__|_________________________________ C
B
*/
// CHART AXIS -------------------------
ctx.beginPath();
ctx.moveTo(A.x, A.y);
ctx.lineTo(B.x, B.y);
ctx.lineTo(C.x, C.y);
ctx.stroke();
// vertical ( A - B )
var aStep = (chartHeight - 50) / (vData);
var Max = Math.ceil(arrayMax(valuesRy) / 10) * 10;
var Min = Math.floor(arrayMin(valuesRy) / 10) * 10;
var aStepValue = (Max - Min) / (vData);
console.log("aStepValue: " + aStepValue); //8 units
var verticalUnit = aStep / aStepValue;
var a = [];
ctx.textAlign = "right";
ctx.textBaseline = "middle";
for (var i = 0; i <= vData; i++) {
if (i == 0) {
a[i] = {
x: A.x,
y: A.y + 25,
val: Max
}
} else {
a[i] = {}
a[i].x = a[i - 1].x;
a[i].y = a[i - 1].y + aStep;
a[i].val = a[i - 1].val - aStepValue;
}
drawCoords(a[i], 3, 0);
}
//horizontal ( B - C )
var b = [];
ctx.textAlign = "center";
ctx.textBaseline = "hanging";
var bStep = chartWidth / (hData + 1);
for (var i = 0; i < hData; i++) {
if (i == 0) {
b[i] = {
x: B.x + bStep,
y: B.y,
val: propsRy[0]
};
} else {
b[i] = {}
b[i].x = b[i - 1].x + bStep;
b[i].y = b[i - 1].y;
b[i].val = propsRy[i]
}
drawCoords(b[i], 0, 3)
}
function drawCoords(o, offX, offY) {
ctx.beginPath();
ctx.moveTo(o.x - offX, o.y - offY);
ctx.lineTo(o.x + offX, o.y + offY);
ctx.stroke();
ctx.fillText(o.val, o.x - 2 * offX, o.y + 2 * offY);
}
//----------------------------------------------------------
// DATA
var oDots = [];
var oFlat = [];
var i = 0;
for (var prop in oData) {
oDots[i] = {}
oFlat[i] = {}
oDots[i].x = b[i].x;
oFlat[i].x = b[i].x;
oDots[i].y = b[i].y - oData[prop] * verticalUnit - 25;
oFlat[i].y = b[i].y - 25;
oDots[i].val = oData[b[i].val];
i++
}
///// Animation Chart ///////////////////////////
//var speed = 3;
function animateChart() {
requestId = window.requestAnimationFrame(animateChart);
frames += speed; //console.log(frames)
ctx.clearRect(60, 0, cw, ch - 60);
for (var i = 0; i < oFlat.length; i++) {
if (oFlat[i].y > oDots[i].y) {
oFlat[i].y -= speed;
}
}
drawCurve(oFlat);
for (var i = 0; i < oFlat.length; i++) {
ctx.fillText(oDots[i].val, oFlat[i].x, oFlat[i].y - 25);
ctx.beginPath();
ctx.arc(oFlat[i].x, oFlat[i].y, 3, 0, 2 * Math.PI);
ctx.fill();
}
if (frames >= Max * verticalUnit) {
window.cancelAnimationFrame(requestId);
}
}
requestId = window.requestAnimationFrame(animateChart);
/////// EVENTS //////////////////////
c.addEventListener("mousemove", function(e) {
label.innerHTML = "";
label.style.display = "none";
this.style.cursor = "default";
var m = oMousePos(this, e);
for (var i = 0; i < oDots.length; i++) {
output(m, i);
}
}, false);
function output(m, i) {
ctx.beginPath();
ctx.arc(oDots[i].x, oDots[i].y, 20, 0, 2 * Math.PI);
if (ctx.isPointInPath(m.x, m.y)) {
//console.log(i);
label.style.display = "block";
label.style.top = (m.y + 10) + "px";
label.style.left = (m.x + 10) + "px";
label.innerHTML = "<strong>" + propsRy[i] + "</strong>: " + valuesRy[i] + "%";
c.style.cursor = "pointer";
}
}
// CURVATURE
function controlPoints(p) {
// given the points array p calculate the control points
var pc = [];
for (var i = 1; i < p.length - 1; i++) {
var dx = p[i - 1].x - p[i + 1].x; // difference x
var dy = p[i - 1].y - p[i + 1].y; // difference y
// the first control point
var x1 = p[i].x - dx * t;
var y1 = p[i].y - dy * t;
var o1 = {
x: x1,
y: y1
};
// the second control point
var x2 = p[i].x + dx * t;
var y2 = p[i].y + dy * t;
var o2 = {
x: x2,
y: y2
};
// building the control points array
pc[i] = [];
pc[i].push(o1);
pc[i].push(o2);
}
return pc;
}
function drawCurve(p) {
var pc = controlPoints(p); // the control points array
ctx.beginPath();
//ctx.moveTo(p[0].x, B.y- 25);
ctx.lineTo(p[0].x, p[0].y);
// the first & the last curve are quadratic Bezier
// because I'm using push(), pc[i][1] comes before pc[i][0]
ctx.quadraticCurveTo(pc[1][1].x, pc[1][1].y, p[1].x, p[1].y);
if (p.length > 2) {
// central curves are cubic Bezier
for (var i = 1; i < p.length - 2; i++) {
ctx.bezierCurveTo(pc[i][0].x, pc[i][0].y, pc[i + 1][1].x, pc[i + 1][1].y, p[i + 1].x, p[i + 1].y);
}
// the first & the last curve are quadratic Bezier
var n = p.length - 1;
ctx.quadraticCurveTo(pc[n - 1][0].x, pc[n - 1][0].y, p[n].x, p[n].y);
}
//ctx.lineTo(p[p.length-1].x, B.y- 25);
ctx.stroke();
ctx.save();
ctx.fillStyle = grd;
ctx.fill();
ctx.restore();
}
function arrayMax(array) {
return Math.max.apply(Math, array);
};
function arrayMin(array) {
return Math.min.apply(Math, array);
};
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return { //objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
body {
margin: 0;
overflow: hidden;
background: #152B39;
font-family: Courier, monospace;
font-size: 14px;
color:#ccc;
}
.wrapper {
display: block;
margin: 5em auto;
border: 1px solid #555;
width: 700px;
height: 350px;
position: relative;
}
p{text-align:center;}
.label {
height: 1em;
padding: .3em;
background: rgba(255, 255, 255, .8);
position: absolute;
display: none;
color:#333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<canvas id='c'></canvas>
<div class="label">text</div>
</div>
<p>Please mouse over the dots</p>

Why does html canvas line animation work but not after already drawing a line

I can draw a line dot by dot, but if I draw the line fully first, then try the dots, all the dots come at once.
So see code, in the window_onload function, if I instead call pathAll instead of startRedDots you can see what I mean. It will draw the line, then all the red dots come at once and not sure why.
<script type="text/javascript">
var pauseAmount = 300;
var m1, c1;
var pathInt;
var points1 = [new Vector(10, 10),new Vector(500, 500)];
function Vector(x, y)
{
this.X = x;
this.Y = y;
}
var counter;
var startX;
var startY;
var endX;
var endY;
var amount;
function resetVars() {
counter=0;
startX = points1[counter].X;
startY = points1[counter].Y;
endX = points1[counter+1].X;
endY = points1[counter+1].Y;
amount = 0;
c1.strokeStyle = "lightgrey";
c1.lineWidth = 15;
c1.lineCap = "round";
c1.setLineDash([1, 30]);
}
window.onload = function()
{
m1 = document.querySelector("#b");
c1 = m1.getContext("2d");
resetVars();
//pathInt = setTimeout(function(){ pathAll(); }, 1);
pathInt = setInterval(function(){ startRedDots(); }, pauseAmount);
};
function pathAll() {
c1.moveTo(startX, startY);
c1.lineTo(endX, endY);
c1.stroke();
resetVars();
setTimeout(function(){ startRedDots(); }, 2500);
}
function startRedDots() {
c1.strokeStyle = "red";;
pathInt = setInterval(function(){ oneAtATime(); }, pauseAmount);
}
function oneAtATime() {
c1.moveTo(startX, startY);
c1.lineTo(startX + (endX - startX) * amount, startY + (endY - startY) * amount);
//alert(startX + (endX - startX) * amount);
if (points1[counter+1].X < points1[counter].X) {
if(points1[counter+1].X < Math.round(eval(startX + (endX - startX) * amount))) {
c1.stroke();
}
else {
clearInterval(pathInt);
}
}
else if (points1[counter+1].X > points1[counter].X) {
if(points1[counter+1].X > Math.round(eval(startX + (endX - startX) * amount))) {
//alert(startX + (endX - startX) * amount);
c1.stroke();
}
else {
clearInterval(pathInt);
}
}
else if (points1[counter+1].X == points1[counter].X) {
if(points1[counter+1].X == Math.round(eval(startX + (endX - startX) * amount))) {
c1.stroke();
}
else {
clearInterval(pathInt);
}
}
amount += 0.01;
}
</script>
<canvas id="b" width="600" height="600" style="position:absolute;top:50px;left:50px;"></canvas>
OK I have it working if anyone interested...just need to add 'c1.beginPath();' as first line in oneAtATime function.

Why is this html5 canvas animation so intensive?

I create this animaiton using canvas and converting svg's to canvas shapes. Most times it runs it heats up my computer and the fan starts going.
Just wondering if there is something about the code, html5 canvas, canvas paths or the animation recursion that is so intensive?
View on codepen: https://codepen.io/benbyford-the-lessful/pen/ZjjVdR?editors=1010#
// check program is being run
console.log('bg animation running...');
// setup canvas
var canvas = document.getElementById('bgCanvas');
var ctx = canvas.getContext('2d')
// redo this - canvas size
//
var width = window.innerWidth,
height = window.innerHeight;
canvas.width = width * 2;
canvas.height = height * 2;
var gridSquareWidth = 20;
var gridWidth = (width * 2) / gridSquareWidth,
gridHeight = (height * 2) / gridSquareWidth;
var grid = [];
// create default grid array
for (var x = 0; x < gridWidth; x++) {
grid[x] = [];
for (var y = 0; y < gridHeight; y++) {
var rand = getRandomArbitrary(0,5);
var rand2 = getRandomArbitrary(0,2);
if(rand2 == 1 || x < (gridWidth / 4) || x > (gridWidth / 2) || y < (gridHeight / 4) || y > (gridHeight / 2)){
rand--;
}
if(rand > 2) grid[x][y] = 1;
}
}
//
// main update function
//
var animationSpeed = 0.1;
var animationSpeedCount = 0;
var running = true;
function update(dt) {
if(running){
animationSpeedCount += dt;
if(animationSpeedCount > animationSpeed){
moveGrid();
animationSpeedCount = 0;
}
draw();
}
}
var noOfFrames = 3;
var waveOffset = 15;
var increment = 0;
function moveGrid() {
var x = increment;
var x2 = increment - noOfFrames - waveOffset;
// add frmae wave
for (var i = 0; i < noOfFrames; i++) {
moveONeFrameForward(x, true);
x--;
}
// go back frmae wave
for (var i = 0; i < noOfFrames; i++) {
moveONeFrameForward(x2, false);
x2--;
}
// var x column, add of subtract by 1
function moveONeFrameForward(x, add){
if(x < 0){
x = Math.ceil(gridWidth + x);
}
if(x > 0 && x < gridWidth){
for (var y = 0; y < gridHeight; y++) {
if(grid[x][y] > 0){
if(add){
grid[x][y] = grid[x][y] + 1;
}else{
if(grid[x][y] > 1) grid[x][y] = grid[x][y] - 1;
}
}
}
}
}
// increment column
increment += 1;
if(increment > gridWidth){
increment = 0;
// stop running
// running = false;
}
}
var fills = ["#eeeeee","#efefef","#fefefe","#ffffff"];
function draw() {
// clear canvas to white
ctx.fillStyle = '#dddddd';
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var x = 0; x < gridWidth; x++) {
for (var y = 0; y < gridHeight; y++) {
var offsetX = x * gridSquareWidth;
var offsetY = y * gridSquareWidth;
var frame = 0;
switch (grid[x][y]) {
case 1:
frame = 1
break;
case 2:
frame = 2;
break;
case 3:
frame = 3;
break;
case 4:
frame = 4;
break;
default:
}
if(frame) drawframe(ctx, frame, offsetX, offsetY, fills);
}
}
}
// The main game loop
var lastTime = 0;
function gameLoop() {
var now = Date.now();
var dt = (now - lastTime) / 1000.0;
update(dt);
lastTime = now;
window.requestAnimationFrame(gameLoop);
};
// start game
gameLoop();
//
// UTILITIES
//
// cross browser requestAnimationFrame - https://gist.github.com/mrdoob/838785
if ( !window.requestAnimationFrame ) {
window.requestAnimationFrame = ( function() {
return window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(
/* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
window.setTimeout( callback, 1000 / 60 );
};
})();
}
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
var frame1Center = 4.1;
var frame2Center = 2.1;
function drawframe(ctx, frame, x, y, fills) {
ctx.strokeStyle = 'rgba(0,0,0,0)';
ctx.lineCap = 'butt';
ctx.lineJoin = 'miter';
ctx.miterLimit = 4;
ctx.fillStyle = fills[frame-1];
switch (frame) {
case 1:
ctx.beginPath();
ctx.moveTo(3.1+x+frame1Center,0+y);
ctx.lineTo(0.6+x+frame1Center,0+y);
ctx.bezierCurveTo(0.3+x+frame1Center,0+y,0+x+frame1Center,0.3+y,0+x+frame1Center,0.6+y);
ctx.lineTo(0.3+x+frame1Center,12.1+y);
ctx.bezierCurveTo(0.3+x+frame1Center,12.4+y,0.6+x+frame1Center,12.7+y,0.8999999999999999+x+frame1Center,12.7+y);
ctx.lineTo(3.4+x+frame1Center,12.7+y);
ctx.bezierCurveTo(3.6999999999999997+x+frame1Center,12.7+y,4+x+frame1Center,12.399999999999999+y,4+x+frame1Center,12.1+y);
ctx.lineTo(4+x+frame1Center,0.6+y);
ctx.bezierCurveTo(4.1+x+frame1Center,0.3+y,3.7+x+frame1Center,0+y,3.1+x+frame1Center,0+y);
ctx.closePath();
ctx.fill();
ctx.stroke();
break;
case 2 || 6:
ctx.beginPath();
ctx.moveTo(4.4+x+frame2Center,0+y);
ctx.bezierCurveTo(3.1+x+frame2Center,0+y,0+x+frame2Center,0.8+y,0+x+frame2Center,2.1+y);
ctx.bezierCurveTo(0+x+frame2Center,3.4000000000000004+y,0.3+x+frame2Center,12.5+y,1.6+x+frame2Center,12.799999999999999+y);
ctx.bezierCurveTo(2.8+x+frame2Center,13+y,6+x+frame2Center,12+y,6+x+frame2Center,10.7+y);
ctx.bezierCurveTo(6+x+frame2Center,9.1+y,5.7+x+frame2Center,0+y,4.4+x+frame2Center,0+y);
ctx.closePath();
ctx.fill();
ctx.stroke();
break;
case 3 || 5:
ctx.beginPath();
ctx.moveTo(5.2+x,0 +y);
ctx.bezierCurveTo(7.5 +x,0+y,9.3+x,6.5+y,9.3 +x,8.7+y);
ctx.bezierCurveTo(9.3+x,10.899999999999999+y,6.300000000000001+x,12.799999999999999+y,4.1000000000000005+x,12.799999999999999+y);
ctx.bezierCurveTo(1.9000000000000004+x,12.799999999999999+y,0+x,6.3+y,0+x,4.1+y);
ctx.bezierCurveTo(0+x,1.8999999999999995+y,3+x,0+y,5.2+x,0+y);
ctx.closePath();
ctx.fill();
ctx.stroke();
break;
case 4:
ctx.beginPath();
ctx.arc(5.9+x,6.3+y,5.8,0,6.283185307179586,true);
ctx.closePath();
ctx.fill();
ctx.stroke();
break;
default:
}
};
It's a bit hard to tell exactly "why", but there are definitely some things that could be improved.
First, you are drawing twice as big as what is needed.
Set you canvas size to the rendered one, and you'll probably see a big improvement in performances.
Then, you are drawing a lot of sub-path at every draw (and setting a lot of times the context's properties for nothing).
You could try to merge all these sub-paths in bigger ones, grouped by fillStyle, so that the rasterizer works only four times per frame. This can also improve performances a bit.
But the approach I would personally take, is to pre-render all the 4 different states on 4 different canvases. Then, use only drawImage to draw the required strip.
In best case, you end up with only 4 calls to drawImage, in worth one, with 8 calls.
Here is a rough proof of concept:
// setup canvas
var canvas = document.getElementById('bgCanvas');
var ctx = canvas.getContext('2d')
// don't set it twice as big as needed
var width = window.innerWidth,
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
var gridSquareWidth = 10;
var gridWidth = (width) / gridSquareWidth,
gridHeight = (height) / gridSquareWidth;
var grid = [];
// create default grid array
for (var x = 0; x < gridWidth; x++) {
grid[x] = [];
for (var y = 0; y < gridHeight; y++) {
var rand = getRandomArbitrary(0, 5);
var rand2 = getRandomArbitrary(0, 2);
if (rand2 == 1 || x < (gridWidth / 4) || x > (gridWidth / 2) || y < (gridHeight / 4) || y > (gridHeight / 2)) {
rand--;
}
if (rand > 2) grid[x][y] = 1;
}
}
var fills = ["#eeeeee", "#efefef", "#fefefe", "#ffffff"];
var frame1Center = 4.1;
var frame2Center = 2.1;
// the 4 points drawers
var drawers = [draw0, draw1, draw2, draw3];
// initialise our four possible states
var states = [
initState(0),
initState(1),
initState(2),
initState(3)
];
//
// main update function
//
var running = true;
var speed = 2;
var waveWidth = 200;
var waveMargin = gridSquareWidth * 4;
var waveStart = 0;
var waveEnd = waveWidth;
// start game
update();
function initState(status) {
var c = canvas.cloneNode();
var ctx = c.getContext('2d');
ctx.scale(0.5, 0.5); // to circumvent values being set for scale(2)
ctx.beginPath(); // single path
ctx.fillStyle = fills[status];
for (var x = 0; x < gridWidth; x++) {
for (var y = 0; y < gridHeight; y++) {
if (grid[x][y]) {
drawers[status](ctx, x * gridSquareWidth * 2, y * gridSquareWidth * 2);
}
}
}
ctx.fill(); // single fill
return c;
}
function draw0(ctx, x, y) {
ctx.moveTo(3.1 + x + frame1Center, 0 + y);
ctx.lineTo(0.6 + x + frame1Center, 0 + y);
ctx.bezierCurveTo(0.3 + x + frame1Center, 0 + y, 0 + x + frame1Center, 0.3 + y, 0 + x + frame1Center, 0.6 + y);
ctx.lineTo(0.3 + x + frame1Center, 12.1 + y);
ctx.bezierCurveTo(0.3 + x + frame1Center, 12.4 + y, 0.6 + x + frame1Center, 12.7 + y, 0.8999999999999999 + x + frame1Center, 12.7 + y);
ctx.lineTo(3.4 + x + frame1Center, 12.7 + y);
ctx.bezierCurveTo(3.6999999999999997 + x + frame1Center, 12.7 + y, 4 + x + frame1Center, 12.399999999999999 + y, 4 + x + frame1Center, 12.1 + y);
ctx.lineTo(4 + x + frame1Center, 0.6 + y);
ctx.bezierCurveTo(4.1 + x + frame1Center, 0.3 + y, 3.7 + x + frame1Center, 0 + y, 3.1 + x + frame1Center, 0 + y);
ctx.closePath();
}
function draw1(ctx, x, y) {
ctx.moveTo(4.4 + x + frame2Center, 0 + y);
ctx.bezierCurveTo(3.1 + x + frame2Center, 0 + y, 0 + x + frame2Center, 0.8 + y, 0 + x + frame2Center, 2.1 + y);
ctx.bezierCurveTo(0 + x + frame2Center, 3.4000000000000004 + y, 0.3 + x + frame2Center, 12.5 + y, 1.6 + x + frame2Center, 12.799999999999999 + y);
ctx.bezierCurveTo(2.8 + x + frame2Center, 13 + y, 6 + x + frame2Center, 12 + y, 6 + x + frame2Center, 10.7 + y);
ctx.bezierCurveTo(6 + x + frame2Center, 9.1 + y, 5.7 + x + frame2Center, 0 + y, 4.4 + x + frame2Center, 0 + y);
ctx.closePath();
}
function draw2(ctx, x, y) {
ctx.moveTo(5.2 + x, 0 + y);
ctx.bezierCurveTo(7.5 + x, 0 + y, 9.3 + x, 6.5 + y, 9.3 + x, 8.7 + y);
ctx.bezierCurveTo(9.3 + x, 10.899999999999999 + y, 6.300000000000001 + x, 12.799999999999999 + y, 4.1000000000000005 + x, 12.799999999999999 + y);
ctx.bezierCurveTo(1.9000000000000004 + x, 12.799999999999999 + y, 0 + x, 6.3 + y, 0 + x, 4.1 + y);
ctx.bezierCurveTo(0 + x, 1.8999999999999995 + y, 3 + x, 0 + y, 5.2 + x, 0 + y);
ctx.closePath();
}
function draw3(ctx, x, y) {
ctx.moveTo(5.9 + x, 6.3 + y);
ctx.arc(5.9 + x, 6.3 + y, 5.8, 0, 2 * Math.PI);
}
function update(dt) {
if (running) {
draw();
moveGrid();
}
window.requestAnimationFrame(update);
}
function moveGrid() {
waveStart = (waveStart + speed) % canvas.width;
waveEnd = (waveStart + waveWidth) % canvas.width;
}
function draw() {
ctx.fillStyle = '#dddddd';
ctx.fillRect(0, 0, canvas.width, canvas.height);
var x = 0;
// the roll logic is a bit dirty... sorry.
if (waveEnd < waveStart) {
x = waveEnd - waveWidth;
drawStrip(1, x, waveMargin);
x = waveEnd - waveWidth + waveMargin;
drawStrip(3, x, (waveWidth - (waveMargin * 2)));
x = waveEnd - waveMargin;
drawStrip(2, x, waveMargin);
x = waveEnd;
}
drawStrip(0, x, waveStart - x);
drawStrip(1, waveStart, waveMargin);
drawStrip(3, waveStart + waveMargin, waveWidth - (waveMargin * 2));
drawStrip(2, waveStart + (waveWidth - waveMargin), waveMargin);
drawStrip(0, waveEnd, canvas.width - Math.max(waveEnd, waveStart));
}
function drawStrip(state, x, w) {
if(x < 0) w = w + x;
if (w <= 0) return;
x = Math.max(x, 0);
ctx.drawImage(states[state],
Math.max(x, 0), 0, w, canvas.height,
Math.max(x, 0), 0, w, canvas.height
);
}
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
:root,body,canvas {margin: 0}
<canvas id="bgCanvas"></canvas>

How to GET fill color of HTML5 canvas element?

There is grid of 10,000 squares, when the cursor hovers over any one of the squares its colour should change and the color of the squares should revert back to its original color once the mouse cursor is no longer over the aforementioned square.
So to revert those squares back to their original color I need their fill color/style.
Although the canvas has a pattern in practice the colors may be random on the grid.
EDIT: The functionality has still not been achieved using getImageData(),code has been written with the function.
Here is the code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
var x = 0,
i = 0;
var y = 0,
j = 0;
slotSize = 10;
for (x = 0, i = 0; i < 100; x += slotSize, i++) {
for (y = 0, j = 0; j < 100; y += slotSize, j++) {
if ((Math.floor(i / 10)) % 2 == 0 && (Math.floor(j / 10)) % 2 == 0) //required for creating the pattern
{
ctx.fillStyle = "red"
} else {
ctx.fillStyle = "yellow";
}
ctx.strokeRect(x, y, slotSize, slotSize);
ctx.fillRect(x, y, slotSize, slotSize);
}
}
function getCursorPosition(canvas, event) {
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
return {
x: x,
y: y
}
}
var basex = 20,
basey = 20;
function occupy(style, row, col) {
console.log("occupy called with" + style)
ctx.fillStyle = style;
cx = slotSize * row;
cy = slotSize * col;
ctx.fillRect(cx, cy, slotSize, slotSize);
ctx.strokeRect(cx, cy, slotSize, slotSize);
}
var row = 0,
col = 0;
function highlight(event) //
{
var coords = getCursorPosition(canvas, event);
var x = coords.x;
var y = coords.y;
if (row != Math.floor(x / slotSize) || col != Math.floor(y / slotSize)) {
var color = getColor(row, col); //working errantly
occupy(color, row, col); //<--- problem line used to get the orginal color of boxes back
row = Math.floor(x / slotSize); //to truncate to int since all number are float by default
col = Math.floor(y / slotSize);
document.getElementById("info").innerHTML = x + "," + y + " " + row + "," + col;
occupy("#ffffff", row, col); // highlighting color
}
}
function getColor(row, col) {
var x = slotSize * row;
var y = slotSize * col;
var dat = ctx.getImageData(x, y, 1, 1);
console.log(dat.data[0] + " " + dat.data[1] + " " + dat.data[2]);
var color = "#" + rgbToHex(dat.data[0], dat.data[1], dat.data[2]);
return color;
}
function rgbToHex(r, g, b) {
if (r <= 255 && g <= 255 && b <= 255) {
rh = r.toString(16);
gh = g.toString(16);
bh = b.toString(16);
while (rh.length < 2) {
rh = "0" + rh;
}
while (gh.length < 2) {
gh = "0" + gh;
}
while (bh.length < 2) {
bh = "0" + bh;
}
color = rh + gh + bh;
console.log(color + " " + rh + " " + gh + " " + bh);
return color;
} else
console.log("invalid color values" + r + " " + g + " " + b);
}
function clear(event) {
var coords = relMouseCoords(event);
row = (coords.x / slotSize);
col = (coords.y / slotSize);
occupy("#ffffff", row, col);
}
document.getElementById("b").setAttribute("onClick", "occupy('red',1,2)");
document.getElementById("canvas").setAttribute("onmousemove", "highlight(event)");
document.getElementById("canvas").setAttribute("onmouseout", "clear(event)");
<table>
<tr>
<td>
<canvas id="canvas" width="1000" height="1000" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</td>
<td>
<button id="b">fill</button>
<p id="info"></p>
</td>
</tr>
</table>
Every time you highlight a square, you first save its original color. Then, when you un-highlight it, simply apply the color back.
And if you don't have a color value store somewhere (for example, if you're randomly building the board on a pixel level), you can always read the hovering pixel color.

Defining value that doesnt change

I realise the title might be misleading, but did not know how to phrase it any other way.
The problem im facing is that I draw up a SVG panel from a JSON object, and in that object there is moving parts that is being controlled by a server that is sending values to us. I get the moving part to be in the right position, but after awhile it keeps adding X position to itself so much that it goes out of the border, which its not meant to do. Basically what it does is add X+X+X repeatedly from the initialposition, but I want it to consider the initialposition first when calculating a new position to be at.
Here is the function behind that, I tried having an if statement that checked for a variable standardX and standardY, while they were set as undefined it would set obj.transform.baseVal.getItem(length).matrix.e as the value to it, but that did not work.
Any tips on any workaround?
Thanks in advance.
var moveX = function(elem, i) {
return function () {
var stepvalue = 6.25;
var step = "0";
var x1 = "0";
var y1 = "0";
var obj = elem.dyn[i].obj;
var standardX = obj.transform.baseVal.getItem(length).matrix.e;
var standardY = obj.transform.baseVal.getItem(length).matrix.f;
console.log(elem.value);
if (elem.value <= elem.dyn[i].rlow) {
step = 0;
x1 = standardY;
y1 = standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
} else if (elem.value > elem.dyn[i].rlow && elem.value <= elem.dyn[i].rhigh) {
step = stepvalue * elem.value;
x1 = step -25;
y1 = standardY;
x1 += standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
} else {
step = stepvalue * elem.dyn[i].rhigh;
x1 = step -25;
y1 = standardY;
x1 += standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
}
}};
Not really sure as we don't have access to the whole code.
From what I gather the problem you're having is that you are initializing standardX and standardY at every call of the function.
You might want to initialize them when you declare the function, like so :
var moveX = function(elem, i) {
return function () {
var stepvalue = 6.25;
var step = "0";
var x1 = "0";
var y1 = "0";
var obj = elem.dyn[i].obj;
console.log(elem.value);
if (elem.value <= elem.dyn[i].rlow) {
step = 0;
x1 = moveX.standardY;
y1 = moveX.standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
} else if (elem.value > elem.dyn[i].rlow && elem.value <= elem.dyn[i].rhigh) {
step = stepvalue * elem.value;
x1 = step -25;
y1 = moveX.standardY;
x1 += moveX.standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
} else {
step = stepvalue * elem.dyn[i].rhigh;
x1 = step -25;
y1 = moveX.standardY;
x1 += moveX.standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
}
};
};
moveX.standardX = obj.transform.baseVal.getItem(length).matrix.e;
moveX.standardY = obj.transform.baseVal.getItem(length).matrix.f;
Another option might be the following, if it needs some kind of dynamic initialization.
var moveX = function(elem, i) {
var standardX = obj.transform.baseVal.getItem(length).matrix.e;
var standardY = obj.transform.baseVal.getItem(length).matrix.f;
return function () {
var stepvalue = 6.25;
var step = "0";
var x1 = "0";
var y1 = "0";
var obj = elem.dyn[i].obj;
console.log(elem.value);
if (elem.value <= elem.dyn[i].rlow) {
step = 0;
x1 = standardY;
y1 = standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
} else if (elem.value > elem.dyn[i].rlow && elem.value <= elem.dyn[i].rhigh) {
step = stepvalue * elem.value;
x1 = step -25;
y1 = standardY;
x1 += standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
} else {
step = stepvalue * elem.dyn[i].rhigh;
x1 = step -25;
y1 = standardY;
x1 += standardX;
obj.setAttribute("transform", "translate("+ x1 + "," + y1 +")");
}
};
};
To be noted that all of this is possible because you can access variables declared outside the current function.
You can find more on function scope and context switch in this article.

Categories