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:
JavaScript
x
66
66
1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
<meta charset="UTF-8">
5
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7
</head>
8
<body>
9
<script>
10
setInterval(timing, 1000);
11
12
var canvas1 = document.createElement("canvas");
13
canvas1.id = "canvas-1";
14
document.body.appendChild(canvas1);
15
canvas1.width = 500;
16
canvas1.height = 500;
17
canvas1.style.backgroundColor = "#3d3d3b";
18
var radius = (canvas1.height/2) * 0.9;
19
20
var ctx = canvas1.getContext("2d");
21
22
ctx.beginPath();
23
ctx.arc(250,250,radius,0,2*Math.PI);
24
ctx.fillStyle = "white";
25
ctx.fill();
26
27
ctx.beginPath();
28
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
29
ctx.fillStyle = '#333';
30
ctx.fill();
31
32
ctx.beginPath();
33
ctx.lineWidth = radius * 0.05;
34
ctx.stroke();
35
ctx.font = "40px Georgia"
36
ctx.textBaseline="middle";
37
ctx.textAlign="center";
38
for (i=1;i<13;i++){
39
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
40
}
41
42
function timing(){
43
44
const d = new Date();
45
46
ctx.beginPath();
47
ctx.moveTo(250,250);
48
ctx.lineWidth = radius*0.01;
49
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
50
ctx.stroke();
51
52
ctx.beginPath();
53
ctx.moveTo(250,250);
54
ctx.lineWidth = radius*0.03;
55
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
56
ctx.stroke();
57
58
ctx.beginPath();
59
ctx.moveTo(250,250);
60
ctx.lineWidth = radius*0.05;
61
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
62
ctx.stroke();
63
}
64
</script>
65
</body>
66
</html>
I have tried to use “ctx.globalCompositeOperation = “destination-over”;”, however not successful:
JavaScript
1
75
75
1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
<meta charset="UTF-8">
5
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7
</head>
8
<body>
9
<script>
10
setInterval(timing, 1000);
11
12
var canvas1 = document.createElement("canvas");
13
canvas1.id = "canvas-1";
14
document.body.appendChild(canvas1);
15
canvas1.width = 500;
16
canvas1.height = 500;
17
canvas1.style.backgroundColor = "#3d3d3b";
18
var radius = (canvas1.height/2) * 0.9;
19
20
var ctx = canvas1.getContext("2d");
21
22
ctx.beginPath();
23
ctx.arc(250,250,radius,0,2*Math.PI);
24
ctx.fillStyle = "white";
25
ctx.fill();
26
27
ctx.beginPath();
28
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
29
ctx.fillStyle = '#333';
30
ctx.fill();
31
32
ctx.beginPath();
33
ctx.lineWidth = radius * 0.05;
34
ctx.stroke();
35
ctx.font = "40px Georgia"
36
ctx.textBaseline="middle";
37
ctx.textAlign="center";
38
for (i=1;i<13;i++){
39
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
40
}
41
42
function timing(){
43
const d = new Date();
44
45
ctx.beginPath();
46
ctx.arc(250,250,radius,0,2*Math.PI);
47
ctx.fillStyle = "white";
48
ctx.fill();
49
ctx.globalCompositeOperation = "destination-over";
50
ctx.beginPath();
51
ctx.moveTo(250,250);
52
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);
53
ctx.stroke();
54
55
ctx.beginPath();
56
ctx.moveTo(250,250);
57
ctx.lineWidth = radius*0.01;
58
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
59
ctx.stroke();
60
61
ctx.beginPath();
62
ctx.moveTo(250,250);
63
ctx.lineWidth = radius*0.03;
64
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
65
ctx.stroke();
66
67
ctx.beginPath();
68
ctx.moveTo(250,250);
69
ctx.lineWidth = radius*0.05;
70
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
71
ctx.stroke();
72
}
73
</script>
74
</body>
75
</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:
JavaScript
1
34
34
1
<html>
2
<body>
3
4
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
5
</canvas>
6
<button onclick="myFunction()">Click me</button>
7
8
<script>
9
var c = document.getElementById("myCanvas");
10
var ctx = c.getContext("2d");
11
ctx.beginPath();
12
ctx.arc(50, 50, 50, 0, 2*Math.PI);
13
ctx.fillStyle = 'red';
14
ctx.fill();
15
ctx.beginPath();
16
ctx.moveTo(50,50);
17
ctx.lineTo(90,90);
18
ctx.stroke();
19
20
function myFunction() {
21
ctx.beginPath();
22
ctx.arc(50, 50, 50, 0, 2*Math.PI);
23
ctx.fillStyle = 'red';
24
ctx.fill();
25
ctx.globalCompositeOperation = "destination-over";
26
ctx.beginPath();
27
ctx.moveTo(50,50);
28
ctx.lineTo(90,90);
29
ctx.stroke();}
30
31
</script>
32
33
</body>
34
</html>
Advertisement
Answer
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 thetiming
function will only deal with the overlayed canvas - In the
timing
function, start by clearing that overlay canvas
JavaScript
1
65
65
1
setInterval(timing, 1000);
2
3
// Create second canvas that will overlay the first
4
var canvas2 = document.createElement("canvas");
5
canvas2.width = 500;
6
canvas2.height = 500;
7
canvas2.style.position = "absolute";
8
document.body.appendChild(canvas2);
9
10
var canvas1 = document.createElement("canvas");
11
canvas1.id = "canvas-1";
12
document.body.appendChild(canvas1);
13
canvas1.width = 500;
14
canvas1.height = 500;
15
canvas1.style.backgroundColor = "#3d3d3b";
16
var radius = (canvas1.height/2) * 0.9;
17
18
var ctx = canvas1.getContext("2d");
19
20
ctx.beginPath();
21
ctx.arc(250,250,radius,0,2*Math.PI);
22
ctx.fillStyle = "white";
23
ctx.fill();
24
25
ctx.beginPath();
26
ctx.arc(250, 250, radius * 0.1, 0, 2 * Math.PI);
27
ctx.fillStyle = '#333';
28
ctx.fill();
29
30
ctx.beginPath();
31
ctx.lineWidth = radius * 0.05;
32
ctx.stroke();
33
ctx.font = "40px Georgia"
34
ctx.textBaseline="middle";
35
ctx.textAlign="center";
36
for (i=1;i<13;i++){
37
ctx.fillText(i.toString(), 250+(Math.sin(i*Math.PI/6)*radius*0.8), 250-Math.cos(i*Math.PI/6)*radius*0.8);
38
}
39
40
// Switch the context to the overlayed canvas
41
ctx = canvas2.getContext("2d");
42
43
function timing(){
44
// Clear the second canvas (only)
45
ctx.clearRect(0, 0, 500, 500);
46
const d = new Date();
47
48
ctx.beginPath();
49
ctx.moveTo(250,250);
50
ctx.lineWidth = radius*0.01;
51
ctx.lineTo(250+(Math.sin(d.getSeconds()*Math.PI/30)*radius*0.85), 250-Math.cos(d.getSeconds()*Math.PI/30)*radius*0.85);
52
ctx.stroke();
53
54
ctx.beginPath();
55
ctx.moveTo(250,250);
56
ctx.lineWidth = radius*0.03;
57
ctx.lineTo(250+(Math.sin(d.getMinutes()*Math.PI/30)*radius*0.78), 250-Math.cos(d.getMinutes()*Math.PI/30)*radius*0.78);
58
ctx.stroke();
59
60
ctx.beginPath();
61
ctx.moveTo(250,250);
62
ctx.lineWidth = radius*0.05;
63
ctx.lineTo(250+(Math.sin(d.getHours()*Math.PI/6)*radius*0.7), 250-Math.cos(d.getHours()*Math.PI/6)*radius*0.7);
64
ctx.stroke();
65
}