2013-02-25 8 views
0

Я пытаюсь создать часы с элементом холста HTML 5.с использованием 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" вызывает удаление перекрывающихся областей, поэтому вторая строка удаляет половину первая строка, а также половина из них.

Вот код и Fiddle: 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; 
    } 

Это Fiddle из «часовой стрелки» радикальные вокруг центральной точки: http://jsfiddle.net/m1erickson/hW2EY/

Однако, если мы будем пытаться использовать «XOR» на вращающаяся линия, линии наложения под углом и, следовательно, xor является неполным.

Вот Скрипки, показывающая линия «XOR» быть неэффективными при вращении: http://jsfiddle.net/m1erickson/f7hHx/

[Отредактировано: новый код был поставлен О.П., позволяющим для расширенного ответа]

я смотрел на вашем новом кода и предлагаю некоторые изменения и оптимизации.

Как я сказал в своем первоначальном ответе, вы не можете не удалить, чтобы удалить линию, которая была нарисована под углом. Это связано с сглаживанием, которое браузер делает автоматически - antiAliasing для холста нельзя отключить.

Вот Fiddle результатов после изменения: http://jsfiddle.net/m1erickson/9QD65/

Изменения:

Верьте или нет: Это обычно полностью стереть и полностью перекроить холст во время каждого цикла анимации! Холст действительно достаточно быстр, чтобы обрабатывать эти перерисовки, особенно сейчас, когда холст ускоряется. Если вы абсолютно необходимо оптимизировать свою производительность, вы можете определить «грязные» области холста, которые необходимо стереть/перерисовать, и оставить остальные области, как было ранее нарисовано.На практике, когда вам нужен этот тип производительности, ваш холст настолько сложный, что более эффективно полностью очистить/перерисовать, чем пытаться определить грязные области.

Оптимизация:

перемещена холст, контекст, 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

Больше замечательного материала! Гм, но не можете ли вы перерисовать с помощью XOR оригинальной часовой стрелки, а затем увеличить позицию? То есть всегда повторяйте одну и ту же строку дважды: один раз, чтобы отобразить ее и один раз удалить. –

Смежные вопросы