У меня есть веб-компонент, который использует attributeChangedCallback
attributeChangedCallback(name, oldValue, newValue) {
// TODO: use something like rxjs debounce time?
this.expensiveRenderer()
}
И я устанавливаю новые значения для двух атрибутов в каждом кадре анимации:
Кроме того, это может увеличить до установки 4 атрибутов.
component.setAttribute("att1", r);
component.setAttribute("att2", p);
Это вызовет attributeChangedCallback
дважды, и дорогой рендерер также будет запущен дважды.
Есть ли эффективный способ объединить два атрибута или сделать эффект изменения единым событием, похожим на время отката или около того?
Я немного скептически отношусь к использованию setTimeout
/ clearTimeout
, так как это вызывается на каждом анимационном кадре 60 кадров в секунду.
Для лучшего обзора мой компонент выглядит примерно так:
<mm-spirograph
fixed-circle-radius="100"
moving-circle-radius="10"
moving-circle-locus-length="30"
repeat-count="100"
></mm-spirograph>
И он делает спирограф с webGL и планирует использовать его для генеративного искусства.
Мне нравится простота этого и немного неохота использовать атрибут JSON.
Кроме того, анимация спирографа хранится отдельно от компонента, идея состоит в том, чтобы использовать спирограф в качестве статического рендеринга, или изменение атрибутов может легко привести к анимации. Здесь он только оживляет два атрибута, но может варьироваться для разных случаев.
Также планируется добавить подобные компоненты, которые можно анимировать, если необходимо, путем установки атрибутов.
function animateSpirograph(spirograph, r, p, rIncrement, pIncrement) {
let v = r;
if (v + rIncrement > 100) rIncrement = -Math.abs(rIncrement);
if (v + rIncrement <= 0) rIncrement = Math.abs(rIncrement);
v = v + rIncrement;
r = v;
let w = p;
if (w + pIncrement > 200) pIncrement = -Math.abs(pIncrement);
if (w + pIncrement <= 0) pIncrement = Math.abs(pIncrement);
w = w + pIncrement;
p = w;
spirograph.setAttribute("moving-circle-radius", r);
spirograph.setAttribute("moving-circle-locus-length", p);
window.requestAnimationFrame(() =>
animateSpirograph(spirograph, r, p, rIncrement, pIncrement)
);
}
То, что предложил Дэнни, интересно, у меня может быть третий атрибут, который может принимать значение, может быть отметкой времени из requestAnimationFrame и помечать ее как необязательный атрибут, используемый только для анимации. Таким образом, каждый раз, когда атрибуты меняются, нам нужно установить этот дополнительный атрибут для фактического запуска рендера. Но это звучит немного хаки / патч.