我正在尝试用HTML 5的canvas元素制作一个时钟。
我要做的是每秒做一行,然后删除上一行。
我想使用globalCompositeOperation='xor';
绘制另一行来删除上一行,但它不起作用!
以下是代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Clock</title>
</head>
<body onload="spin()">
<canvas id="myCanvas" width="578" height="400"></canvas>
<script>
var firstTime = 0;
var prevX=null;
var prevY=null;
function spin() {
//get the canvas element
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//get the right angle for the clock hand
var date = new Date;
var seconds = date.getSeconds();
var a = seconds*6;
var angleRadian = a*Math.PI/180;
var angle = 1/2*Math.PI - angleRadian;
if(a > 360)
a = 0;
//Erase the previous line, if it has been drawn.
if(prevX!=null)
erasePrevLine(angle, canvas, context);
//draw line
drawLine(angle, 100, canvas, context);
//repeat for the next second
setTimeout(spin, 500);
}
function drawLine(angle, radius, canvas, context) {
var centerX = canvas.width/2;
var centerY = canvas.height/2;
var xTarget = centerX + Math.cos(angle)*radius;
var yTarget = centerY - Math.sin(angle)*radius;
//save this state to be erased
prevX = xTarget;
prevY = yTarget;
//draw
context.beginPath();
context.moveTo(centerX,centerY);
context.lineTo(xTarget, yTarget);
context.stroke();
}
function erasePrevLine(angle, canvas, context) {
context.globalCompositeOperation = 'xor';
var centerX = canvas.width/2;
var centerY = canvas.height/2;
prevAngle = angle + (Math.PI/180*6);
var xTarget = prevX;
var yTarget = prevY;
//draw on the previous line
context.beginPath();
context.moveTo(centerX,centerY);
context.lineTo(xTarget, yTarget );
context.stroke();
}
</script>
</body>
</html>
以下是实例:http://jsfiddle.net/pyerT/1/ 有人知道答案吗?它适用于形状和文字..
答案 0 :(得分:2)
globalCompositeOperation(xor)无法像“时钟指针”那样在旋转行上运行......这就是原因:
假设您绘制一条垂直线。然后在第一条右侧绘制第二条垂直线。假设第二条垂直线将第一条线重叠一半。
Canvas.globalCompositeOperation =“xor”会导致重叠区域被删除,因此第二行会删除 half 第一行以及自身的一半。
这是代码和小提琴:http://jsfiddle.net/m1erickson/e24KU/
function drawLine(){
ctx.globalCompositeOperation="xor";
ctx.strokeStyle="red";
ctx.lineWidth=10;
ctx.beginPath();
ctx.moveTo(posX,10);
ctx.lineTo(posX,100);
ctx.stroke();
posX+=5;
}
这是一个围绕中心点的“时钟指针”的小提琴:http://jsfiddle.net/m1erickson/hW2EY/
但是,如果我们尝试在旋转线上使用“xor”,则线条会以>>覆盖,因此xor不完整。
这是一个小提琴,显示旋转时“xor”行无效:http://jsfiddle.net/m1erickson/f7hHx/
[编辑:OP提供的新代码允许扩展答案]
我查看了您的新代码,并建议进行一些更改和优化。
正如我在原始答案中所说,无法有效地删除以某个角度绘制的线条。这是由于浏览器自动执行的抗锯齿 - 无法关闭画布的antiAliasing。
以下是更改后结果的小提琴:http://jsfiddle.net/m1erickson/9QD65/
的变化:
信不信由你:通常在每个动画循环中完全擦除并完全重绘画布! Canvas真的足够快,可以处理这些重绘 - 特别是现在画布是GPU加速的。如果绝对需要优化您的性能,您可以定义必须擦除/重绘的画布的“脏”区域,并保留以前绘制的其他区域。实际上,一旦你需要这种类型的性能,你的画布就会非常复杂,以至于完全清除/重绘比尝试定义脏区更有效。
优化:
将画布,上下文,centerX,centerY移出动画循环,因为这些值可以计算一次并重复使用。
以下是我建议的代码供您查看:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Clock</title>
</head>
<body onload="spin()">
<canvas id="myCanvas" width="578" height="400"></canvas>
<script>
var firstTime = 0;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX=canvas.width/2;
var centerY=canvas.height/2;
var canvasWidth=canvas.width;
var canvasHeight=canvas.height;
function spin() {
//get the right angle for the clock hand
var date = new Date;
var seconds = date.getSeconds();
var a = seconds*6;
var angleRadian = a*Math.PI/180;
var angle = 1/2*Math.PI - angleRadian;
if(a > 360)
a = 0;
//draw line
drawLine(angle, 100, canvas, context, "black",1);
//repeat for the next second
setTimeout(spin, 500);
}
function drawLine(angle, radius, canvas, context) {
var xTarget = centerX + Math.cos(angle)*radius;
var yTarget = centerY - Math.sin(angle)*radius;
//clear the canvas
context.clearRect(0,0,canvasWidth,canvasHeight);
//draw
context.save();
context.beginPath();
context.moveTo(centerX,centerY);
context.lineTo(xTarget, yTarget);
context.stroke();
context.restore()
}
</script>
</body>
</html>