Dynamically filling 4 canvases based on length input - javascript

I have created 4 different canvases in design file of my aspx file.
The first 3 having length 300 and last having length 100.
There are various 10 different length inputs coming dynamically for these. Once the length crosses 300, I am unable to switch to 2nd canvas.
Here goes my code:-
<canvas id="canvas1" width="300" height="50"></canvas>
<canvas id="canvas2" width="300" height="50"></canvas>
<canvas id="canvas3" width="300" height="50"></canvas>
<canvas id="canvas4" width="100" height="50"></canvas>
<script type="text/javascript">
var prod1head = '<%=head[0]%>';
var prod2head = '<%=head[1]%>';
var prod3head = '<%=head[2]%>';
var prod4head = '<%=head[3]%>';
var prod5head = '<%=head[4]%>';
var prod6head = '<%=head[5]%>';
var prod7head = '<%=head[6]%>';
var prod8head = '<%=head[7]%>';
var prod9head = '<%=head[8]%>';
var prod10head = '<%=head[9]%>';
var prod1color = '<%=prd_color[0]%>';
var prod2color = '<%=prd_color[1]%>';
var prod3color = '<%=prd_color[2]%>';
var prod4color = '<%=prd_color[3]%>';
var prod5color = '<%=prd_color[4]%>';
var prod6color = '<%=prd_color[5]%>';
var prod7color = '<%=prd_color[6]%>';
var prod8color = '<%=prd_color[7]%>';
var prod9color = '<%=prd_color[8]%>';
var prod10color = '<%=prd_color[9]%>';
var c = document.getElementById("canvas1");
var ctx = c.getContext("2d");
ctx.fillStyle = prod1color;
ctx.fillRect(0, 0, prod1head, 50);
ctx.fillStyle = prod2color;
ctx.fillRect(prod1head, 0, prod2head, 50);
ctx.fillStyle = prod3color;
ctx.fillRect(prod2head, 0, prod3head, 50);
ctx.fillStyle = prod4color;
ctx.fillRect(prod3head, 0, prod4head, 50);
ctx.fillStyle = prod5color;
ctx.fillRect(prod4head, 0, prod5head, 50);
ctx.fillStyle = prod6color;
ctx.fillRect(prod5head, 0, prod6head, 50);
ctx.fillStyle = prod7color;
ctx.fillRect(prod6head, 0, prod7head, 50);
ctx.fillStyle = prod8color;
ctx.fillRect(prod7head, 0, prod8head, 50);
ctx.fillStyle = prod9color;
ctx.fillRect(prod8head, 0, prod9head, 50);
ctx.fillStyle = prod10color;
ctx.fillRect(prod9head, 0, prod10head, 50);
</script>

You could just draw the same shape to all canvas with an offset by the position of the canvas...
In your code you have not really attempted much, you have only one ctx variable, but you have 4 canvases, the first it to loop over all your canvas and add the needed information to an array, that we can later loop and do the drawing.
Instead of the many fillRect you have on your code, we can create a common function that we call with the right params it will draw in all the canvases taking the offset into account, the offset we can calculate using getBoundingClientRect, you can read more about it here:
https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
See a working prototype below:
var canvases = []
for (let i = 1; i < 5; i++) {
const c = document.getElementById("canvas" + i)
canvases.push({
ctx: c.getContext("2d"),
rect: c.getBoundingClientRect()
})
}
function fillRect(color, x, y, w, h) {
canvases.forEach((c) => {
c.ctx.beginPath()
c.ctx.fillStyle = color;
c.ctx.fillRect(x - c.rect.left, y - c.rect.top, w, h)
})
}
function strokeArc(color, x, y, r, lw) {
canvases.forEach((c) => {
c.ctx.beginPath()
c.ctx.lineWidth = lw;
c.ctx.strokeStyle = color;
c.ctx.arc(x - c.rect.left, y - c.rect.top, r, 0, 2 * Math.PI);
c.ctx.stroke();
})
}
fillRect("red", 10, 10, 100, 28)
fillRect("blue", 20, 20, 500, 20)
fillRect("black", 2, 2, 6, 200)
fillRect("black", 300, 2, 6, 200)
strokeArc("cyan", 220, 160, 150, 5)
strokeArc("black", 300, 50, 30, 20)
body {
margin: 0px
}
canvas {
border: 1px solid
}
<canvas id="canvas1" width="300" height="50"></canvas>
<canvas id="canvas2" width="300" height="50"></canvas>
<canvas id="canvas3" width="300" height="50"></canvas>
<canvas id="canvas4" width="100" height="50"></canvas>
That should output something like:

Related

javascript my arc is not showing up or moving across the screen

hello i am trying to make a white circle move across a black box in javascript my circle is not showing up the big black box does but the circle does not show up i dont know why i am loading the page in google chrome here is the code
<html>
<head>
<title>paddle</title>
</head>
<body>
<canvas id="myCanvas" width="800" height="600"></canvas>
<script>
var canvas
var canvasContext
var ballX = 5
window.onload = function() {
var fps = 30;
setInterval(updateAll, 1000)
canvas = document.getElementById("myCanvas");
canvasContext = canvas.getContext("2d")
canvasContext.fillStyle = "black"
canvasContext.fillRect(0, 0, canvas.width, canvas.height)
}
function updateAll() {
ballX++
canvasContext.fillStyle = "white";
canvasContext.beginPath()
canvasContext.arc(ballX, 100, 10, 0, Math.PI*2, true);
canvasContext.stroke()
}
</script>
</body>
</html>
The problem is that you are using stroke to draw the circle but you have not set the stroke style which is by default black. So you are drawing a black circle on a black background. Hence no see circle.
Also it is best to use requestAnimationFrame to animate rather than set interval.
Example animating a circle
requestAnimationFrame(animationLoop);
const ctx = myCanvas.getContext("2d");
var ballX = 5;
var speed = 1
const radius = 10;
const fps = 30;
var frameCount = 0;
function animationLoop() {
if (frameCount % (60 / fps) === 0) {
ctx.fillStyle = "black"
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
draw();
}
frameCount ++;
requestAnimationFrame(animationLoop);
}
function draw() {
ballX = (ballX + speed) % (ctx.canvas.width + radius * 2);
ctx.strokeStyle = "white";
ctx.lineWidth = 2;
ctx.beginPath()
ctx.arc(ballX - radius, 20, 10, 0, Math.PI * 2);
ctx.stroke()
}
<canvas id="myCanvas" width="600" height="40"></canvas>

How to undraw the a rectangle when recalling a function [duplicate]

This question already has answers here:
How to clear the canvas for redrawing
(25 answers)
Closed 3 years ago.
I want to make a rectangle that moves from the right to the left.
I could draw a new rectangle in the left of the previous one but i couldn't erase the previous one.
Here is my code:
let cvs = document.getElementById("canvas");
let ctx = cvs.getContext('2d');
let firstpos = 400;
let blocks = [];
blocks[0] = {
x: 400,
y: Math.floor(Math.random() * 360)
}
function draw() {
for (var i = 0; i < blocks.length; i++) {
ctx.beginPath()
ctx.fillStyle = "white";
ctx.fillRect(blocks[i].x, 0, 70, blocks[i].y);
ctx.fill();
blocks[i].x -= 0;
}
requestAnimationFrame(draw);
}
draw()
#canvas {
background-color: #000;
}
<canvas id="canvas" width="1000" height="500"></canvas>
Working snippet
Take advantage of CanvasRenderingContext2D.clearRect()
let cvs = document.getElementById("canvas");
let ctx = cvs.getContext('2d');
let firstpos = 400;
let blocks = [];
blocks[0] = {
x: 0,
y: Math.floor(Math.random() * 360)
}
function draw() {
blocks[0].x++;
ctx.clearRect(0, 0, canvas.width, canvas.height); // canvas clear up
for (var i = 0; i < blocks.length; i++) {
ctx.beginPath()
ctx.fillStyle = "white";
ctx.fillRect(blocks[i].x, 0, 70, blocks[i].y);
ctx.fill();
blocks[i].x -= 0;
}
requestAnimationFrame(draw);
}
setInterval(draw, 500)
#canvas {
background-color: #000;
}
<canvas id="canvas" width="1000" height="500"></canvas>
It's not possible to "undraw" something in canvas. However, you can clear the canvas on each frame with clearRect and re-draw everything in a new position.
Additionally, the current code uses blocks[i].x -= 0; which won't change the animation state even with a clear and redraw.
Parameters to fillRect appear incorrect or mislabeled. ctx.fillRect(blocks[i].x, 0, 70, blocks[i].y); should be ctx.fillRect(blocks[i].x, blocks[i].y, width, height);. There's also no need for creating a path or calling fill for this method.
It's typical to encapsulate all data for a block inside the object. We need a color, speed and x/y/height/width.
Note that y: Math.floor(Math.random() * 360) can result in a height of zero.
Here's a simple example of moving a block on the canvas:
const cvs = document.getElementById("canvas");
cvs.width = innerWidth;
cvs.height = innerHeight;
const ctx = cvs.getContext("2d");
const blocks = [{
x: innerWidth - 50,
y: 20,
velocityX: -1,
width: 50,
height: 50,
color: "white"
}];
(function draw() {
ctx.clearRect(0, 0, cvs.width, cvs.height);
for (const block of blocks) {
ctx.fillStyle = block.color;
ctx.fillRect(block.x, block.y, block.width, block.height);
block.x += block.velocityX;
}
requestAnimationFrame(draw);
})();
#canvas {
background-color: #000;
}
<canvas id="canvas"></canvas>

Redraw or delete the existing canvas and create a new one with modified content

I am trying to delete the existing canvas and create a new one with the modified content (of the old one).
Below is the code I have tried.
/* Identifying the Canvas child inside the div parent */
var c = document.getElementById("myCanvasDiv"),
canv = '',
cv = '';
for (i = 0; i < c.childElementCount; i++) {
console.log(c.children[i].nodeName);
if (c.children[i].nodeName == "CANVAS") {
//console.log(c.children[i].getContext('2d'));
canv = c.children[i];
cv = c.children[i].getContext('2d');
}
}
var new_cv = cv
var items = new_cv.canvas.aa.nodes.bi.ud
var keys = []
/* Retrieving the keys */
for (var i in items){
//console.log(items[i].value.Zd["key"]);
keys.push(i + "|" +items[i].value.Zd["key"]);
}
/* Modifying the Content */
for (var i in items){
var strVal = items[i].value.Zd["key"];
//console.log(items[i].value.Zd["key"]);
for (var j in keys){
if(items[i].value.Zd["key"] && items[i].value.Zd["key"].substring(0,items[i].value.Zd["key"].length-1) == keys[j].split("|")[1]){
items[i].value.Zd["key"] = keys[j].split("|")[1];
}
}
console.log(strVal + "----->" + items[i].value.Zd["key"]);
}
/* Trying to reset the canvas content */
for (i = 0; i < c.childElementCount; i++) {
if (c.children[i].nodeName == "CANVAS") {
/*c.removeChild(c.children[i]);
var newcanvas = document.createElement("canvas");
newcanvas.id="canvas1";
newcanvas.getContext = new_cv;
c.appendChild(newcanvas);*/
//cHeight = c.children[i].height;
//cWidth = c.children[i].width;
//cv.clearRect(0,0,c.children[i].width,c.children[i].height);
//c.children[i] = new_cv;
//cv.setContext(new_cv);
canv.getContext = new_cv;
console.log(cv);
}
}
is there any way I can achieve this.
Thanks in advance.
The simplest way to do it is this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 50, 50);
ctx.clearRect(0,0, c.width, c.height);
ctx.fillStyle = "black";
ctx.fillRect(10, 10, 50, 50);
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<button onclick="copy()">Copy</button>
<p id="cont"> FillStyle Content</p>
However if you want to use pixel manipulation (much more expensive) you can do this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 50, 50);
var imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
// for every pixel if the red channel value is 255 (i.e. red) then make it black (0)
for (var i = 0; i < imgData.data.length; i += 4) {
if (imgData.data[i + 0] == 255) {
imgData.data[i + 0] = 0;
}
}
// put the modified image back
ctx.putImageData(imgData, 0, 0);
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<button onclick="copy()">Copy</button>
<p id="cont"> FillStyle Content</p>

How to restart canvas drawing?

When I click start, I get whole circle. But when I click clean and again start, previously part of the circle remaining and straight line appear.
DEMO: https://fiddle.jshell.net/1xhkfk73/
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var draw = 0;
var stepDraw = 0;
ctx.strokeStyle = "#FF0000";
ctx.translate(0.5, 0.5);
var delay = 30;
var drawing = 0;
function drawCircle(steps) {
draw = ((2 * Math.PI) / steps);
stepDraw = draw;
drawing = setInterval(function() {
ctx.arc(400, 200, 120, draw, draw, false);
ctx.stroke();
draw += stepDraw;
}, delay)
}
$("#click").click(function() {
drawCircle(120);
});
$("#clean").click(function() {
clearInterval(drawing);
ctx.clearRect(0, 0, 800, 400);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="click">start</span>
<span id="clean">clean</span>
<canvas id="myCanvas" class="center-block" width="800" height="400">
Canvas not supported!
</canvas>
Try this.
You need to have your path closed.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var draw = 0;
var stepDraw = 0;
ctx.strokeStyle = "#FF0000";
ctx.translate(0.5, 0.5);
var delay = 30;
var drawing = 0;
function drawCircle(steps) {
draw = ((2 * Math.PI) / steps);
stepDraw = draw;
drawing = setInterval(function() {
ctx.beginPath();
ctx.arc(400, 200, 120, draw, draw+stepDraw, false);
ctx.stroke();
draw += stepDraw;
}, delay)
}
$("#click").click(function() {
drawCircle(120);
});
$("#clean").click(function() {
clearInterval(drawing);
ctx.clearRect(0, 0, 800, 400);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="click">start</span>
<span id="clean">clean</span>
<canvas id="myCanvas" class="center-block" width="800" height="400">
Canvas not supported!
</canvas>

Canvas: Multiple Radial Progress bar

i have a little problem, i have made 3 radial progress bars with canvas and js (following more or less the guide on thecodeplayer.com).
The result is almost good, and it's working, the problem is that if i have multiple bars the last one takes the percentage from the first. In my example the first is 65% and the last should be 88% but it take the data-attribute from the first.
Here is the code
Javascript:
window.onload = function(){
var canvas = document.getElementsByTagName('canvas');
for (var i = 0; i < canvas.length; i++) {
progressBar(canvas[i].id);
}
// load the canvas
function progressBar(canvasId) {
var canvas = document.getElementById(canvasId);
var ctx = canvas.getContext('2d');
// declare some variables
var cWidth = canvas.width;
var cHeight = canvas.height;
var progressColor = 'lightblue';
var circleColor = '#333';
var rawPerc = canvas.getAttribute('data-perc');
var definition = canvas.getAttribute('data-text');
var perc = parseInt(rawPerc);
var degrees = 0;
var endDegrees = (360*perc)/100;
var lineWidth = 10; // The 'brush' size
console.log(canvasId+' '+perc);
function getDegrees() {
if(degrees < endDegrees) {
degrees++;
}
else {
clearInterval(degreesCall);
}
drawProgressBar();
}
function drawProgressBar() {
//clear the canvas after every instance
ctx.clearRect(0,0,cWidth,cHeight);
// let's draw the background circle
ctx.beginPath();
ctx.strokeStyle = circleColor;
ctx.lineWidth = lineWidth -1;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0, Math.PI*2, false);
ctx.stroke();
var radians = 0; // We need to convert the degrees to radians
radians = degrees * Math.PI/180;
// let's draw the actual progressBar
ctx.beginPath();
ctx.strokeStyle = progressColor;
ctx.lineWidth = lineWidth;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0 - 90*Math.PI/180, radians - 90*Math.PI/180, false);
ctx.stroke();
// let's get the text
ctx.fillStyle = progressColor;
ctx.font = '20px Arial';
var outputTextPerc = Math.floor(degrees/360*100)+'%';
var outputTextPercWidth = ctx.measureText(outputTextPerc).width;
var outputTextDefinitionWidth = ctx.measureText(definition).width;
ctx.fillText(outputTextPerc, cWidth/2 - outputTextPercWidth/2, cHeight/2 - 10);
ctx.fillText(definition, cWidth/2 - outputTextDefinitionWidth/2, cHeight/2 + 15);
}
degreesCall = setInterval(getDegrees, 10/(degrees - endDegrees));
}
}
(sorry for the bad indend)
HTML:
<canvas id="canvas-3" width="300" height="300" data-text="Radial 1" data-perc="65"></canvas>
<canvas id="canvas-4" width="300" height="300" data-text="Radial 2" data-perc="90"></canvas>
<canvas id="canvas-1" width="450" height="450" data-text="Radial 3" data-perc="88"></canvas>
I have made a working jsfiddle at http://jsfiddle.net/ranqgnr8/.
Any idea why it's taking tha first percentage?
thanks to all who are reading.
EDIT:
the strange thing is that in the console log the percentage is right.
You forgot to define the degreesCall variable, so it ends up in the global space and you override the same interval
var canvas = document.getElementsByTagName('canvas');
for (var i = 0; i < canvas.length; i++) {
progressBar(canvas[i].id);
}
// load the canvas
function progressBar(canvasId) {
var degreesCall;
var canvas = document.getElementById(canvasId);
var ctx = canvas.getContext('2d');
// declare some variables
var cWidth = canvas.width;
var cHeight = canvas.height;
var progressColor = 'lightblue';
var circleColor = '#333';
var rawPerc = canvas.getAttribute('data-perc');
var definition = canvas.getAttribute('data-text');
var perc = parseInt(rawPerc);
var degrees = 0;
var endDegrees = (360*perc)/100;
var lineWidth = 10; // The 'brush' size
console.log(canvasId+' '+perc);
function getDegrees() {
if(degrees < endDegrees) {
degrees++;
}
else {
clearInterval(degreesCall);
}
drawProgressBar();
}
function drawProgressBar() {
//clear the canvas after every instance
ctx.clearRect(0,0,cWidth,cHeight);
// let's draw the background circle
ctx.beginPath();
ctx.strokeStyle = circleColor;
ctx.lineWidth = lineWidth -1;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0, Math.PI*2, false);
ctx.stroke();
var radians = 0; // We need to convert the degrees to radians
radians = degrees * Math.PI/180;
// let's draw the actual progressBar
ctx.beginPath();
ctx.strokeStyle = progressColor;
ctx.lineWidth = lineWidth;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0 - 90*Math.PI/180, radians - 90*Math.PI/180, false);
ctx.stroke();
// let's get the text
ctx.fillStyle = progressColor;
ctx.font = '20px Arial';
var outputTextPerc = Math.floor(degrees/360*100)+'%';
var outputTextPercWidth = ctx.measureText(outputTextPerc).width;
var outputTextDefinitionWidth = ctx.measureText(definition).width;
ctx.fillText(outputTextPerc, cWidth/2 - outputTextPercWidth/2, cHeight/2 - 10);
ctx.fillText(definition, cWidth/2 - outputTextDefinitionWidth/2, cHeight/2 + 15);
}
degreesCall = setInterval(getDegrees, 10/(degrees - endDegrees));
}
body {
padding-top: 100px;
background: #555;
}
canvas {
display: inline-block;
margin: auto;
}
<canvas id="canvas-3" width="300" height="300" data-text="Radial 1" data-perc="65"></canvas>
<canvas id="canvas-4" width="300" height="300" data-text="Radial 2" data-perc="90"></canvas>
<canvas id="canvas-1" width="450" height="450" data-text="Radial 3" data-perc="88"></canvas>

Categories