2013-02-25 2 views
0

HTML5의 캔버스 요소로 시계를 만들려고합니다.globalCompositeOperation을 행과 함께 사용 하시겠습니까?

내가하려는 것은 매초마다 줄을 만들고 이전 줄을 지우는 것입니다.

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

의지가 코드를 : 여기에

당신이 보는 내 제안 코드? – markE

답변

2

globalCompositeOperation (XOR)는 "시계 손"처럼 회전 라인에서 작동하지 않습니다 ... 왜 문서라도 :

당신이 수직선을 그릴 가정합니다. 그런 다음 첫 번째 오른쪽의 두 번째 세로선을 그립니다. 두 번째 세로선 이 첫 번째 줄의 절반 인과 겹친다 고 가정합니다.

Canvas.globalCompositeOperation = "xor"는 중복 영역을 제거하므로 두 번째 줄은 첫 번째 줄과 그 반의 부분을 제거합니다. 우리가 "XOR"를 사용하려고하면, http://jsfiddle.net/m1erickson/hW2EY/

그러나 : 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; 
    } 

이는 중심점 주위 청소에 "시계 손"의 바이올린입니다 : 여기

는 코드와 바이올린입니다 회전 선인 경우, 선들은의 각도로 을 오버레이하므로 xor가 불완전합니다. 여기

회전 할 때 비효율적 인 줄 "XOR"을 보여주는 바이올린입니다 : http://jsfiddle.net/m1erickson/f7hHx/

[편집 : 새로운 코드가 확장 응답을 허용 OP에 의해 제공된] 나는 당신의 새로운 보았다

코드를 수정하고 일부 변경 및 최적화를 제안합니다.

원래 대답에서 말한 것처럼 은 각도로 그려진 선을 효과적으로 지울 수 없습니다. 이는 브라우저가 자동으로 수행하는 앤티 앨리어싱으로 인해 캔버스에 대한 앤티 앨리어싱을 끌 수 없기 때문입니다. http://jsfiddle.net/m1erickson/9QD65/

변경 : 여기

은 변경 후 결과의 바이올린입니다

그것을 여부를 믿으 :를 완전히 지우고 완전히 각 애니메이션 루프 동안 캔버스를 다시 그려야하는 것이 일반적입니다! 캔버스는 실제로 이러한 재 드래그를 처리 할만큼 충분히 빠릅니다. 특히 캔버스가 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> 
+0

답변 해 주셔서 감사합니다. 하지만 내 문제는'globalCompositeOperation'이 두 줄을 'xor'할 수 없다는 것입니다. 여러분이 한 번 보지 않으려 고하면, 간단한 코드를 추가했습니다. – aIKid

+0

와우, 정말 고마워! 정말 도움이됩니다. 고맙습니다! 전에 완전히 새로운 캔버스를 그리는 것에 대해 생각해 본 적이 없습니다 :) – aIKid

+0

더 멋진 것들! Ahem,하지만 원래 시계 손 XOR을 사용하여 다시 그려서 위치를 증가시킬 수는 없습니까? 즉, 항상 같은 선을 두 번 그립니다. 한 번만 나타나고 한 번 제거하면됩니다. –

관련 문제