Какова цель сохранения и восстановления Canvas.Context в этом примере? - программирование
Подтвердить что ты не робот

Какова цель сохранения и восстановления Canvas.Context в этом примере?

Эта страница показывает некоторые анимации в холсте HTML5. Если вы посмотрите на источник скроллера, появится инструкция для сохранения контекста после очистки прямоугольника и восстановления его после анимации. Если я заменю инструкцию restore другим оператором ctx.clearRect(0, 0, can.width, can.height, ничего не работает. Я думал, что восстановление восстанавливает очищенный прямоугольник, но кажется, что он восстанавливает больше информации. Какую дополнительную информацию необходимо для следующего кадра?

Я не ищу определения HTML5 для учебников Save and Restore, но я хочу понять, почему они необходимы в этом конкретном примере.

UPDATE

Нехорошо получить ответ, в котором я конкретно упоминал в вопросе, я не хочу получать определения save() и restore(). Я уже знаю, что Save() сохраняет состояние контекста и Restor() e восстанавливает его. Мой вопрос очень конкретный. Почему restore() используется в примере, когда все сохраненные сохранены пустым холстом. Почему восстанавливает пустой холст не так же, как его очистка?

4b9b3361

Ответ 1

Состояние холста не нарисовано на нем. Это стек свойств, которые определяют текущее состояние инструментов, которые используются для создания следующей вещи.

Canvas - это растровое изображение немедленного режима. Как MS Paint. После этого он там, поэтому нет смысла "сохранять" текущие данные изображения, потому что это будет похоже на сохранение всего JPEG, каждый раз, когда вы вносите изменения, каждый кадр...

... нет, состояние, которое вы сохраняете, - это состояние, которое будет определять, какую координатную ориентацию, размерность, цвет и т.д. вы используете для рисования СЛЕДУЮЩЕЙ вещи (и все после этого, пока вы не измените эти значения на рука).

var canvas = document.createElement("canvas"),
    easel  = canvas.getContext("2d");

easel.fillStyle = "rgb(80, 80, 120)";
easel.strokeStyle = "rgb(120, 120, 200)";

easel.fillRect(x, y, width, height);
easel.strokeRect(x, y, width, height);

easel.save();  // stores ALL current status properties in the stack

easel.rotate(degrees * Math.PI / 180); // radians
easel.scale(scale_X, scale_Y); // any new coordinates/dimensions will now be multiplied by these
easel.translate(new_X, new_Y); // new origin coordinates, based on rotated orientation, multiplied by the scale-factor

easel.fillStyle = "gold";
easel.fillRect(x, y, width, height); // completely new rectangle
// origin is different, and the rotation is different, because you're in a new coordinate space

easel.clearRect(0, 0, width, height); // not even guaranteed to clear the actual canvas, anymore
easel.strokeRect(width/2, height/2, width, height); // still in the new coordinate space, still with the new colour


easel.restore(); // reassign all of the previous status properties
easel.clearRect(0, 0, width, height);

Предполагая, что вы были только одним изменением состояния в стеке, эта последняя строка, теперь, когда ваше предыдущее состояние вашего холста было восстановлено, должно было успешно очиститься (несмотря на субпиксельные shenanigans).

Итак, как вы можете видеть, у него очень, очень мало общего с стиранием холста.
Фактически, это не имеет никакого отношения к его стиранию.

Это связано с желанием нарисовать что-то и делать основные выделения и подметание цветов/стилей, а затем вручную писать в цветах для небольших деталей сверху, а затем вручную записывать все стили обратно так, как они были раньше, чтобы вернуться к широким ударам для следующего объекта, и дальше и дальше...

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

В вашем точном примере, если вы обратили внимание, вы увидите, что единственное, что меняется, - это значение step.

Они установили состояние кучки значений для холста (цвет/шрифт/etc).
А потом они спасут. Ну, что они спасли?
Ты не выглядишь достаточно глубоко. Они фактически сохранили перевод по умолчанию (т.е.: origin = 0,0 в исходном мировом пространстве).
Но вы не видели, чтобы они определяли это?
Это потому, что оно определено как значение по умолчанию.

Затем они увеличивают шаг 1 пикселя (фактически, они делают это сначала, но это не имеет значения после первого цикла - оставайтесь со мной здесь).
Затем они устанавливают новую точку начала 0,0 (т.е. Теперь, когда они набирают 0,0, что новое происхождение указывает на совершенно другое место на холсте).

Эта точка происхождения равна x, являющейся точной серединой холста, и y равно текущему шагу (то есть: пиксель 1 или пиксель 2 и т.д.) и почему разница между начальным значением 0 и началом с 1 действительно не имеет значения).

Тогда что они делают?
Они восстанавливаются.

Ну, что они восстановили?
... ну, что они изменили?

Они восстанавливают точку начала до 0,0
Почему?

Хорошо, что произойдет, если они этого не сделают?
Если холст 500px x 200px, и он начинается с 0,0 в нашем текущем пространстве экрана...... это замечательно...
Затем они переводят его на ширину /2, 1
Хорошо, так что теперь, когда они попросят нарисовать текст в 0,0, они на самом деле будут рисовать 250, 1

Замечательно. Но что будет в следующий раз?

Теперь они переводятся по ширине /2, 2
Вы думаете, хорошо, что хорошо...... призыв на ничью для 0,0 будет происходить на 250, 2, потому что они установили его для очистки чисел: canvas.width/2, 2

Неа. Потому что ток 0,0 фактически равен 250,1 по нашему экрану. И один перевод относится к его предыдущему переводу...

... так что теперь вы говорите холсту, чтобы начать с него текущие координаты '0,0 и идите влево 250 и вниз 2.
Согласно экрану (который похож на окно, глядя на карту, а не на карту), мы теперь на расстоянии 500 пикселей справа и на 3 пикселя вниз от того места, где мы начали... И только один кадр прошел мимо.

Таким образом, они восстанавливают координаты карты в том же месте, что и координаты экрана (и вращение должно быть одинаковым, а масштаб, и перекос и т.д.) перед установкой нового.

И как вы могли догадаться, посмотрев на это, теперь вы можете видеть, что текст должен перемещаться сверху вниз. Не справа налево, как говорится на странице...

Зачем это?
Зачем переходить к проблеме изменения координатной системы контекста рисования, когда команды рисования дают вам x и y прямо там в функции?

Если вы хотите нарисовать изображение на холсте, и знаете, насколько он высок и широк, и где вам нужен верхний левый угол, почему бы вам просто не сделать это:

easel.drawImage(myImg, x, y, myImg.width, myImg.height);

Ну, вы можете.
Вы можете это сделать полностью. Там вас никто не останавливает.

Фактически, если вы хотите сделать его масштабируемым по экрану, вы можете просто обновить x и y по таймеру и называть его днем.

Но как насчет рисования персонажа? Что, если у персонажа была шляпа, были руки в перчатках и большие сапоги, и все эти вещи были оттянуты отдельно от персонажа?

Итак, сначала вы сказали бы "хорошо, что он стоит на x и y в мире, поэтому x плюс, когда его рука по отношению к его телу будет x + body.x - hand.x... или была что плюс..."

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

Вместо этого вы можете сказать: "Он здесь. Установите мои координаты, чтобы 0,0 был прямо посреди моего парня". Теперь ваши призывы рисования так же просты, как "Моя правая рука - 6 пикселей справа от тела, левая рука - 3 пикселя влево".

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

Ответ 2

Контекст save() сохраняет материал, такой как цвет преобразования, среди других вещей. Затем вы можете изменить контекст и восстановить его так же, как при его сохранении. Он работает как стек, поэтому вы можете вставлять несколько стеков в стек и восстанавливать их. http://html5.litten.com/understanding-save-and-restore-for-the-canvas-context/