gif
でも Lottie
でもなく、 apng
で実装。
1つ目を再生→数秒終了したままの1つ目を表示→1つ目を非表示&2つ目を再生
のような動きを繰り返し行うようにしたい…。
まず最初に「再生タイミング」と「終了タイミング」ってどうするのか、というところから考えて、 js
で制御はできないのか、と試すことに。
apng-canvas.js
以前使用していた apng-canvas.js
、APNG非対応ブラウザ
1で表示する際に使用していました。
それもあって、一度こちらで対応してみようとしたのですが、再生→停止→再度再生できるようにはならず。
APNG.parseBuffer
の項目にあった rewind()
を使って、APNG
のアニメーション終了に合わせて再度再生を行おうと思ったのですが、止まる位置にズレが多く、また終了タイミングもうまく取れなかったため、別の方法はないかと探すことになりました。
※一度だけアニメーションを動かすだけの場合であればこちらで大丈夫かと思います。
確かnpmパッケージ
登録がされていないプラグインになるので、cdn
で読み込む必要があります。
apng-js
上で記述した apng-canvas
を作成された方が、別のプラグインも作成されていました。
こちらだと再生・一時停止・停止など、apng
をコントロールできるイベントが多く、思った通りの動きはできそうでした。
README に記述してある通りにまずは書いてみました。
import parseAPNG from 'apng-js';
const img = 'xxx.png'
const apng = parseAPNG(img);
エラーが出てしまい、動きません。
README を見ると、 parseAPNG
の引数は画像のURLなどではなく、画像のバイナリデータを入れる、とのことです。バイナリデータ…?
いろいろな記事を参考にしつつ、以下のように書いてみました。
import apngJs from 'apng-js/lib/index.js'
const parseAPNG = apngJs.default;
const getImgBuffer = (url) =>
new Promise(async (resolve) => {
const blob = await fetch(url).then((res) => res.blob());
const reader = new FileReader();
reader.readAsArrayBuffer(blob);
reader.onload = () => {
resolve(reader.result);
};
}
);
async function createAPNGPlayer(_target, _options = {}) {
const imgBuffer = await getImgBuffer(_target.src);
const apng = parseAPNG(imgBuffer);
Object.keys(_options).forEach((key) => {
apng[key] = _options[key];
});
await apng.createImages();
// 画像のバイナリデータを利用し、canvas に反映させるため、canvas は必須
// JS で作成しなくても、html に書いてあるものを使っても良い
const ctx = document.createElement('canvas');
ctx.width = apng.width
ctx.height = apng.height
_target.appendChild(ctx);
const player = await apng.getPlayer(ctx.getContext('2d'));
return player;
}
(async () => {
// 1つ目
const img = document.querySelector('.img');
const apng = await createAPNGPlayer(img);
// 2つ目
const img2 = document.querySelector('.img2');
const apng2 = await createAPNGPlayer(img2);
// apng の再生
apng.play();
apng.on('end', () => {
apng.stop();
apng2.play();
});
apng2.on('end', () => {
apng2.stop();
apng.play();
});
})();
これで最初に希望していた動きを実装することができました。
あとは再生してみて適宜 settimeout
などを挟んで調節して終わります。
apng
をこうやって扱うこと自体、そこまでなさそうではあります。
ですが、条件が色々と重なった結果使うこともあるかなと思い、記事に残しておきます。もしかしたら自分もすっきり忘れたころに見ながら対応するかもしれない。
参考にさせていただいた記事
-
2024年3月15日現在、主要なブラウザは apng に対応しています。
https://caniuse.com/?search=apng ↩