Очистить холст Rect (но сохранить фон)

Я пытаюсь оживить круг и просто перемещать его по горизонтали, что отлично работает. Однако, пока круг движется, я должен сделать clearRect над этим кругом, чтобы он перерисовывал его в горизонтальном направлении. Когда я делаю clearRect, он также делает фон белым ящиком так эффективно, что он будет одной белой горизонтальной линией в направлении движения круга.

  • Есть ли способ очистить круг без clearRect?
  • Если мне нужно продолжить перерисовку фона после clearRect, холст будет мерцать, если в этой области будут отображаться 10 кругов.

Любые другие подходы к решению этого вопроса?

    function drawcircle() {
        clear();    

        context.beginPath();
        context.arc(X, Y, R, 0, 2*Math.PI, false);                  
        context.moveTo(X,Y);            
        context.lineWidth = 0.3;
        context.strokeStyle = "#999999"; 
        context.stroke();

        if (X > 200)
        {
            clearTimeout(t); //stop
        }
        else
        {
            //move in x dir
            X += dX;
            t = setTimeout(drawcircle, 50);
        }
    }

    function clear() {
        context.clearRect(X-R, Y-R, 2*R, 2*R);
    }

Ответ 1

Основы: холст HTML5 как нестрочный графический интерфейс Графика API

Во-первых, давайте обсудим, как работает холст HTML5. Как настоящий холст с быстросохнущими масляными красками, когда вы на stroke() или fill() или drawImage() на ваш холст, краска становится частью холста. Хотя вы нарисовали "круг" и рассматривали его как таковой, пиксели круга полностью заменяли фон (или в случае сглаживания по краям круга, смешивались и навсегда меняли их). Что Моне сказал бы, если бы вы попросили его "переместить" одного из людей на картине немного вправо? Вы не можете перемещать круг, вы не можете стереть круг, вы не можете обнаружить наводку круга... потому что нет круга, существует только один 2D-массив пикселей.

Некоторые параметры

  • Если ваш фон полностью статичен, установите его как фоновое изображение в элемент canvas с помощью CSS. Это будет отображаться и накладываться на контент, который вы рисуете, но не очищается, когда вы очищаете свой холст.

  • Если вы не можете сделать выше, то вы можете просто очистить весь холст и перекрасить его в каждый кадр. В моих тестах работа, необходимая для очистки и перерисовки только части холста, не стоит усилий, если перерисовать холст очень дорого.

    Например, см. этот тест: http://phrogz.net/tmp/image_move_sprites_canvas.html
    В Safari v5.0.4 я вижу 59.4fps, если я очищаю и повторно рисую весь холст один раз за кадр и 56.8fps, если я использую 20 clearRect() вызовов и 20 drawImage() вызовов для повторного рисования только загрязненной части фон каждого кадра. В этом случае медленнее быть умным и отслеживать небольшие грязные области.

  • В качестве другой альтернативы используйте графическую систему с сохраненным рисунком, такую ​​как SVG или HTML. При этом каждый элемент поддерживается независимо. Вы можете изменить положение предмета, и он будет волшебно двигаться; браузер должен разумно сделать обновление наиболее эффективным способом.

    Вы можете сделать это, сохранив при этом силу пользовательского холста, создав и разместив несколько холстов на одной и той же странице HTML (используя абсолютное позиционирование CSS и z-index). Как показано в этот тест производительности, переместите 20 спрайтов через CSS значительно быстрее, чем пытаться сделать все это самостоятельно на одном холсте.

Мерцание?

Вы писали:

Если мне нужно продолжить перерисовку фона после clearRect, холст будет мерцать, если в этой области будут отображаться 10 кругов.

Это никогда не было моим опытом. Можете ли вы представить небольшой пример, показывающий эту проблему "мерцания", которую вы заявляете (пожалуйста, укажите ОС, браузер и версию, которые вы испытываете)? Вот два комментария известных разработчиков браузеров, отметив, что ни Firefox, ни Safari не должны когда-либо показывать мерцание.

Ответ 2

На самом деле это очень просто сделать, просто позиционируя более одного холста друг на друга. Вы можете нарисовать свой фон на холсте, который (дождитесь его...), в фоновом режиме, и нарисуйте круги на втором холсте, который находится на переднем плане. (т.е. уложены перед фоновым холстом)

Несколько холстов на самом деле являются одним из лучших способов повысить производительность любой анимации, когда элементы конечного изображения перемещаются независимо и не обязательно перемещаются в каждом кадре. Это позволяет избежать перерисовки элементов, которые не были перемещены в каждом кадре. Однако следует иметь в виду, что изменение относительной глубины (думаю, z-индекс) элементов, нарисованных на разных полотнах, теперь требует, чтобы фактические элементы <canvas> были переупорядочены в dom. На практике это редко бывает проблемой для 2D-игр и анимаций.

Ответ 3

Есть два способа сделать это, чтобы уменьшить мерцание, esp, если у вас много кругов.

Один из них - двойная буферизация, и для краткого вопроса об этом вы можете посмотреть: Поддерживает ли поддержка HTML5/Canvas двойную буферизацию?

В принципе, вы рисуете на двух холстах и ​​меняете их по мере необходимости.

Это был бы предпочтительный вариант, esp со многими изменениями на кадр, но, наоборот, я сделал это, чтобы просто нарисовать круг, который я хочу стереть, используя цвет фона, затем нарисуйте с правильным цветом новый круг.

Единственная проблема заключается в том, что есть небольшая вероятность того, что вы можете оставить некоторые доказательства попытки стирания, так как кажется, что для некоторых фигур трудно заставить ее рисовать точно сверху.

UPDATE:

На основе комментария вы можете посмотреть на эту дискуссию о двойной буферизации на холсте:

Проблемы с частотой кадров с двойной буферизацией HTML

Основная идея состоит в том, чтобы отслеживать все, что вы нарисовали, с текущей позицией, затем на отдельном холсте, вы перерисовываете все, а затем отбрасываете их, а затем я просто буду снова рисовать на новых позициях, чтобы изображение выглядело так, как должно. Включение и выключение их в операционную систему - это быстрая операция, единственная проблема заключается в том, что если вы помещаете обработчики событий на холст, в этом случае имейте это в div или span, окружающем холст, так что эта информация не потеряется.