Related
Below is my preliminary Javascript code for making a analog clock. My main problem is I don't know how to clear the "previous second lines" on the clock surface:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script>
setInterval(timing, 1000);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
function timing(){
const d = new Date();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
</script>
</body>
</html>
I have tried to use "ctx.globalCompositeOperation = "destination-over";", however not successful:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script>
setInterval(timing, 1000);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
function timing(){
const d = new Date();
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineTo(250+(Math.sin((d.getSeconds()-1)*Math.PI/30)*radius*0.85), 250-Math.cos((d.getSeconds()-1)*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
</script>
</body>
</html>
Could you tell me how to clear these "previous second lines" by using globalCompositeOperation if such function can really do in my case? Thanks.
The reason i believe it is possible to do it through globalCompositeOperation, is because i had tried some test as below:
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
</canvas>
<button onclick="myFunction()">Click me</button>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(50, 50, 50, 0, 2*Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(90,90);
ctx.stroke();
function myFunction() {
ctx.beginPath();
ctx.arc(50, 50, 50, 0, 2*Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(90,90);
ctx.stroke();}
</script>
</body>
</html>
The globalCompositeOperation property cannot really be used for this purpose.
You can however do this:
Create a second canvas element that overlays the first (using position: absolute). It is transparent, so the other canvas will be seen through it.
After drawing the background on the original canvas, switch the context (ctx) to the second canvas, so that the timing function will only deal with the overlayed canvas
In the timing function, start by clearing that overlay canvas
setInterval(timing, 1000);
// Create second canvas that will overlay the first
var canvas2 = document.createElement("canvas");
canvas2.width = 500;
canvas2.height = 500;
canvas2.style.position = "absolute";
document.body.appendChild(canvas2);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
// Switch the context to the overlayed canvas
ctx = canvas2.getContext("2d");
function timing(){
// Clear the second canvas (only)
ctx.clearRect(0, 0, 500, 500);
const d = new Date();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
You should probably be re-drawing the clockface for every new date that you render. I broke it down into individual pieces and used Promises but sure these were not strictly necessary.
(() => {
let cnvs;
let ctxt;
let radius;
const buildcanvas = () => new Promise((resolve, reject) => {
cnvs = document.createElement("canvas");
cnvs.id = "canvas-1";
cnvs.width = 500;
cnvs.height = 500;
cnvs.style.backgroundColor = "#3d3d3b";
document.body.appendChild(cnvs);
resolve(true)
});
const buildclockface = () => new Promise((resolve, reject) => {
radius = (cnvs.height / 2) * 0.9;
ctxt = cnvs.getContext("2d");
ctxt.beginPath();
ctxt.arc(250, 250, radius, 0, 2 * Math.PI);
ctxt.fillStyle = "white";
ctxt.fill();
ctxt.beginPath();
ctxt.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctxt.fillStyle = '#333';
ctxt.fill();
ctxt.beginPath();
ctxt.lineWidth = radius * 0.05;
ctxt.stroke();
ctxt.font = "40px Georgia"
ctxt.textBaseline = "middle";
ctxt.textAlign = "center";
for (i = 1; i < 13; i++) {
ctxt.fillText(
i.toString(),
250 + (Math.sin(i * Math.PI / 6) * radius * 0.8),
250 - (Math.cos(i * Math.PI / 6) * radius * 0.8)
);
}
resolve(true)
});
const showtime = (d) => new Promise((resolve, reject) => {
let d = new Date();
buildclockface();
secondhand(d);
minutehand(d);
hourhand(d);
});
const secondhand = (d) => {
ctxt.beginPath();
ctxt.moveTo(250, 250);
ctxt.lineWidth = radius * 0.01;
ctxt.lineTo(250 + (Math.sin(d.getSeconds() * Math.PI / 30) * radius * 0.85), 250 - Math.cos(d.getSeconds() * Math.PI / 30) * radius * 0.85);
ctxt.stroke();
}
const minutehand = (d) => {
ctxt.beginPath();
ctxt.moveTo(250, 250);
ctxt.lineWidth = radius * 0.03;
ctxt.lineTo(250 + (Math.sin(d.getMinutes() * Math.PI / 30) * radius * 0.78), 250 - Math.cos(d.getMinutes() * Math.PI / 30) * radius * 0.78);
ctxt.stroke();
}
const hourhand = (d) => {
ctxt.beginPath();
ctxt.moveTo(250, 250);
ctxt.lineWidth = radius * 0.05;
ctxt.lineTo(250 + (Math.sin(d.getHours() * Math.PI / 6) * radius * 0.7), 250 - Math.cos(d.getHours() * Math.PI / 6) * radius * 0.7);
ctxt.stroke();
}
buildcanvas()
.then(bool => setInterval(showtime, 1000))
.catch(err => alert(err))
})();
classic case of redraw the background here, nice little program though :)
setInterval(timing, 1000);
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
function timing(){
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
const d = new Date();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}//timing
i just reread your post and you were asking about globalCompositeOperation
if you really dont want to redraw the background, and use globalCompositeOperation,
the globalCompositeOperation appears to operate only on filled areas, ie not lines
you would have to store your draw coordinates for each hand, redraw each hand at the old position - to remove it, then calculate new draw coordinates, draw and save
but check this out
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width=500;
canvas.height=500;
var ctx = canvas.getContext("2d");
ctx.globalCompositeOperation = 'xor';
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineWidth = 1;
ctx.lineTo(250,250);
ctx.strokeStyle = '#ff0000'
ctx.stroke();
ctx.beginPath();
ctx.moveTo(50,250);
ctx.lineWidth = 1;
ctx.lineTo(250,50);
ctx.strokeStyle = '#ff0000'
ctx.stroke();
ctx.fillStyle='blue';
ctx.fillRect(20,20,60,60);
seems to show it wouldnt work for your clock hands
After some further research of the globalCompositeOperation, I find it is necessary to add another instruction to tell the program that the globalCompositeOperation restore to its previous state once the "previous second line" is cleared, therefore i further modified my program as below, and eventually it proof that using globalCompositeOperation can solve the problem. However, I had to admit that simply redraw the clock background each time should be better solution in this case.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Analog Clock-4 (using globalCompositeOperation)</title>
</head>
<body>
<script>
var canvas1 = document.createElement("canvas");
canvas1.id = "canvas-1";
document.body.appendChild(canvas1);
canvas1.width = 500;
canvas1.height = 500;
canvas1.style.backgroundColor = "#3d3d3b";
var radius = (canvas1.height/2) * 0.9;
var ctx = canvas1.getContext("2d");
setInterval(timing, 1000);
function timing(){
const d = new Date();
ctx.beginPath();
ctx.arc(250,250,radius,0,2*Math.PI);
ctx.fillStyle = "white";
ctx.fill();
ctx.beginPath();
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.beginPath();
ctx.lineWidth = radius * 0.05;
ctx.stroke();
ctx.font = "40px Georgia"
ctx.textBaseline="middle";
ctx.textAlign="center";
for (i=1;i<13;i++){
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
}
ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineTo(250+(Math.sin((d.getSeconds()-1)*Math.PI/30)*radius*0.5), 250-Math.cos((d.getSeconds()-1)*Math.PI/30)*radius*0.5);
ctx.stroke();
ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.01;
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.03;
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(250,250);
ctx.lineWidth = radius*0.05;
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
ctx.stroke();
}
</script>
</body>
</html>
How do I make a row of triangles?
Here's the code I have so far.
I'm new I don't know what to do here.
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126, 300);
ctx.lineTo(200, 400);
ctx.lineTo(50, 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You can use the iteration (i) and multiply it by the spacing you want and add it to the x value.
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = coolCanvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126+(i*170), 300);
ctx.lineTo(200+(i*170), 400);
ctx.lineTo(50+(i*170), 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You should use a variable to add to the X positions and increment as you want :
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let delta = 0;
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126 + delta, 300);
ctx.lineTo(200 + delta, 400);
ctx.lineTo(50 + delta, 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
delta += 174;
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You can create a separate function to handle drawing the triangles, then pass in the xStart as the base x-coordinate value for any triangle to be drawn. Then in the showDrawing function, run a loop and multiply the i variable to some spacing value. In your code, your triangle is 150 pixels wide and starts at x-value of 50, so I multiplied the i value by 200 for consistency in my solution code.
Additionally, I highly advise using the variable name you set (coolCanvas) as the reference to the canvas or set this variable to be named canvas instead. If you only ever set the canvas once and reference it once, you can probably skip setting the reference altogether:
let ctx = document.getElementById("canvas").getContext("2d");
function drawTriangle(ctx, xStart) {
ctx.lineWidth = 5;
ctx.strokeStyle = "blue";
ctx.fillStyle = "purple";
ctx.beginPath();
ctx.moveTo(xStart + 126, 300);
ctx.lineTo(xStart + 200, 400);
ctx.lineTo(xStart + 50, 400);
ctx.closePath();
ctx.fill()
ctx.stroke();
}
function showDrawing() {
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
drawTriangle(ctx, i * 200);
}
}
document.getElementById("draw").addEventListener("click", showDrawing);
canvas {
border: 3px solid #000000;
}
<div><button id="draw">Drawing</button></div>
<div><canvas id="canvas" width="1500" height="700"></canvas></div>
I was able to stub out a static image using the canvas arch() method, and I have a for loop, but I'm stuck on why the for loop doesn't subtract from the circle variable down to number selected. I'm stuck on how create a for loop that would make the circles change size and appropriately alternate color as a user moves the slider.
//Canvas constants
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 200;
//Slider
let slider = document.getElementById("myRange");
let bandWidth = document.getElementById("bandWidth");
bandWidth.innerHTML = slider.value;
slider.oninput = function() {
bandWidth.innerHTML = this.value;
// console.log(this.value);
let input = this.value;
let circle = radius;
for(input; input <= circle; circle -= input){
//console.log(circle);
//I don't know why the loop does work correctly above 30...
}
}
//Figure out how to get the below in a for loop...
//Stubbed out what circles would look like at 25.
// the first circle has a band with of 25
//first circle
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
//Second circle
ctx.beginPath();
ctx.arc(centerX, centerY, 175, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
//Third Circle
ctx.beginPath();
ctx.arc(centerX, centerY, 150, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
//Fourth Circle
ctx.beginPath();
ctx.arc(centerX, centerY, 125, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
//Fifth
ctx.beginPath();
ctx.arc(centerX, centerY, 100, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
//Sixth
ctx.beginPath();
ctx.arc(centerX, centerY, 75, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
//Seventh
ctx.beginPath();
ctx.arc(centerX, centerY, 50, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
//Eigth
ctx.beginPath();
ctx.arc(centerX, centerY, 25, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BullsEye</title>
</head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border: 2px solid black"></canvas>
<br>
<div>BandWidth:</div>
<!--Slider input-->
<!--onChnage will update the bandwith value-->
<input type="range" id="myRange" value="25" min="5" max="50" step="5">
<p>Current BandWith:
<span id="bandWidth"></span>
</p>
<script src="bullsEye.js"></script>
</body>
</html>
Your code seems to work fine with some minor corrections.
I've introduced an additional variable i in the loop to keep track of the current iteration and alternate between colors.
//Canvas constants
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 200;
//Slider
let slider = document.getElementById("myRange");
let bandWidth = document.getElementById("bandWidth");
bandWidth.innerHTML = slider.value;
function draw() {
bandWidth.innerHTML = this.value;
// console.log(this.value);
let input = this.value;
let circle = radius;
ctx.clearRect(0, 0, canvas.width, canvas.height)
for(let i = 0; input <= circle; circle -= input, i++){
// console.log(circle);
ctx.beginPath();
ctx.arc(centerX, centerY, circle, 0, 2 * Math.PI, false);
ctx.fillStyle = i % 2 === 0 ? 'red' : 'blue';
ctx.fill();
}
}
slider.oninput = draw;
draw.call(slider);
<canvas id="myCanvas" width="400" height="400" style="border: 2px solid black"></canvas>
<br>
<div>BandWidth:</div>
<!--Slider input-->
<!--onChnage will update the bandwith value-->
<input type="range" id="myRange" value="25" min="5" max="50" step="5">
<p>Current BandWith:
<span id="bandWidth"></span>
</p>
I am trying to style the closePath() on my canvas but am at a loss on how to do that, as a matter of fact I would actually like all the lines to have a different style, for this question lets stick to getting different colors. ! As you can see I have a triangle, how can I have differing strokestyles for each line? Here is link to the Code Pen
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.moveTo(20, 140);
ctx.lineTo(120, 10);
ctx.strokeStyle = "green";
ctx.lineTo(220, 140);
ctx.closePath();
ctx.strokeStyle = "blue";
ctx.stroke();
<canvas id="canvas"></canvas>
You would need to have the three lines as three separate paths.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(20, 140);
ctx.lineTo(120, 10);
ctx.strokeStyle = "red";
ctx.stroke();
ctx.beginPath();
ctx.moveTo(120, 10);
ctx.lineTo(220, 140);
ctx.strokeStyle = "green";
ctx.stroke();
ctx.beginPath();
ctx.moveTo(220, 140);
ctx.lineTo(20, 140);
ctx.strokeStyle = "blue";
ctx.stroke();
<canvas id="canvas"></canvas>
Each segment needs to be coloured.
function qsa(sel,par=document){return par.querySelectorAll(sel)}
window.addEventListener('load', onLoaded, false);
function onLoaded(evt)
{
draw();
}
class vec2d
{
constructor(x=0,y=0)
{
this.x = x;
this.y = y;
}
}
function draw()
{
var verts = [ new vec2d(20,140), new vec2d(120, 10), new vec2d(220,140) ];
var colours = ['red', 'green', 'blue'];
let can = qsa('canvas')[0];
let ctx = can.getContext('2d');
var numLineSegs = verts.length;
for (var lineSegIndex=0; lineSegIndex<numLineSegs; lineSegIndex++)
{
var index1 = lineSegIndex;
var index2 = (lineSegIndex+1)%verts.length;
ctx.beginPath();
ctx.strokeStyle = colours[index1];
ctx.moveTo(verts[index1].x, verts[index1].y);
ctx.lineTo(verts[index2].x, verts[index2].y);
ctx.stroke();
}
ctx.closePath();
}
<canvas width=512 height=512></canvas>
I'm drawing canvas and have put in some shapes and text and I want to move the text inside the canvas like the text bar animated from left to right
As you can see, when I'm moving the text is moving not like it supposed to be.
How can I fix it?
<script>
var pointX, pointY , w , h ;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = window.innerWidth;
c.height = window.innerHeight;
ctx.clearRect(0, 0, ctx.canvas.width,ctx.canvas.height);
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(10,0,720,576);
ctx.closePath();
ctx.beginPath();
ctx.fillStyle='grey';
ctx.fillRect(10,525,720,50);
ctx.closePath();
ctx.beginPath();
var start = 10;
setInterval(function(){
start += 4;
ctx.font = "30px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "left";
ctx.fillText("Hello World",start, 560);
}, 40);
ctx.closePath();
pointX = 690;
pointY = 550;
w = 30;
h = 20;
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(pointX,pointY,w,h);
ctx.closePath();
</script>
<!DOCTYPE html>
<html>
<head>
<script src ="js/jquery-3.3.1.min.js" ></script>
<link href ="css/bootstrap.min.css" rel="stylesheet">
<script src ="js/bootstrap.min.js" ></script>
<meta charset="utf-8">
<meta name = "viewport" content = "width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0"/>
</head>
<body dir="rtl" id="tbodyid">
<canvas id="myCanvas" width="1050" height="1050" class="col-12 col-s-12" >
</canvas>
</body>
</html>
As I've commented, inside your setInterval function you should add ctx.clearRect(0,0,c.width,c.height). Also you have to redraw everything else. So I've putted your shapes inside functions, and I'm calling those functions inside setInterval too.
var pointX, pointY , w , h ;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = 1000;
c.height = 650;
ctx.clearRect(0, 0, ctx.canvas.width,ctx.canvas.height);
function drawShape1(){
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(10,0,720,576);
ctx.closePath();
ctx.beginPath();
ctx.fillStyle='grey';
ctx.fillRect(10,525,720,50);
ctx.closePath();
}
function drawShape2(){
pointX = 690;
pointY = 550;
w = 30;
h = 20;
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(pointX,pointY,w,h);
ctx.closePath();
}
var start = 10;
setInterval(function(){
ctx.clearRect(0,0,c.width,c.height)
drawShape1()
start += 4;
ctx.font = "30px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "left";
ctx.fillText("Hello World",start, 560);
drawShape2()
}, 40);
<canvas id="myCanvas" width="1000" height="650" class="col-12 col-s-12" ></canvas>
However if you want to try using requestAnimationFrame instead of setInterval this is how to do it:
Since requestAnimationFrame runs at 60 frames per sec I've changed start += 4; to start += 2;
var pointX, pointY , w , h ;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = 1000;
c.height = 650;
ctx.clearRect(0, 0, ctx.canvas.width,ctx.canvas.height);
function drawShape1(){
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(10,0,720,576);
ctx.closePath();
ctx.beginPath();
ctx.fillStyle='grey';
ctx.fillRect(10,525,720,50);
ctx.closePath();
}
function drawShape2(){
pointX = 690;
pointY = 550;
w = 30;
h = 20;
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(pointX,pointY,w,h);
ctx.closePath();
}
var start = 10;
function frame(){
requestAnimationFrame(frame)
ctx.clearRect(0,0,c.width,c.height)
drawShape1()
start += 2;
ctx.font = "30px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "left";
ctx.fillText("Hello World",start, 560);
drawShape2()
}
frame()
<canvas id="myCanvas" width="1050" height="1050" class="col-12 col-s-12" >
</canvas>
<canvas id="myCanvas" width="1050" height="1050" class="col-12 col-s-12" >
</canvas>
<script>
var pointX, pointY , w , h ;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
c.width = 1000;
c.height = 650;
ctx.clearRect(0, 0, ctx.canvas.width,ctx.canvas.height);
function drawShape1(){
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(10,0,720,70);
ctx.closePath();
ctx.beginPath();
ctx.fillStyle='gold';
ctx.fillRect(10,10,720,50);
ctx.closePath();
}
function drawShape2(){
pointX = 690;
pointY = 30;
w = 30;
h = 20;
ctx.beginPath();
ctx.strokeStyle='red';
ctx.strokeRect(pointX,pointY,w,h);
ctx.closePath();
}
var start = 10;
function frame(){
requestAnimationFrame(frame)
ctx.clearRect(0,0,c.width,c.height)
drawShape1()
start += 2;
ctx.font = "30px Arial";
ctx.fillStyle = "red";
ctx.textAlign = "left";
ctx.fillText("Hello World",start, 50);
if (start > 576) start = 0;
drawShape2()
}
frame()
</script>