返回一个特殊对象(并不是原来的sprite对象),当我们调用.attr
方法对它进行属性设置时,它创建一个属性动画。当我们再次对它进行属性设置时,它会结束上一次的动画进入下一段动画,这样我们就可以平滑地进行状态切换。此外我们可以通过调用.reverse
方法来让当前transition状态回滚。
试试将鼠标移动到左右两个方块上:
const scene = new Scene('#transition-toggle', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
const layer = scene.layer('fglayer');
const left = new Sprite();
left.attr({
anchor: 0.5,
pos: [400, 300],
size: [200, 200],
bgcolor: 'red',
});
layer.append(left);
const right = left.cloneNode();
right.attr({
pos: [900, 300],
bgcolor: 'green',
});
layer.append(right);
let leftTrans = null;
left.on('mouseenter', (evt) => {
leftTrans = left.transition(1.0);
leftTrans.attr({
rotate: 180,
bgcolor: 'green',
});
});
left.on('mouseleave', (evt) => {
leftTrans.attr({
rotate: 0,
bgcolor: 'red',
});
});
let rightTrans = null;
right.on('mouseenter', (evt) => {
rightTrans = right.transition(3.0);
rightTrans.attr({
rotate: 720,
bgcolor: 'red',
});
});
right.on('mouseleave', (evt) => {
rightTrans.reverse();
});
在前面的例子里我们已经看过很多动画的用法。事实上,spritejs支持,因此可以让精灵使用.animate方法做出各种复杂的组合动画。
我们既可以使用spritejs提供的animate动画,也可以使用其他方式,比如原生的setInterval或requestAnimationFrame。此外一些动画库提供的Tween动画,也可以很容易地结合spritejs使用。
比起使用原生timer或者第三方库,直接使用spritejs提供的animate动画有一个额外的好处,就是它默认基于layer的timeline。也就是说我们可以通过控制layer的timeline来控制动画播放的速度,方便地加速、减速、暂停甚至回放动画。
playbackRate: 1.0
通过控制playbackRate可以控制layer上的所有动画的播放速度,该属性也会影响到layer的draw方法中的时间参数,对自定义绘图中依赖于时间轴的也可以产生影响。
;(async function () {
const birdsJsonUrl = 'https://s5.ssl.qhres.com/static/5f6911b7b91c88da.json';
const birdsRes = 'https://p.ssl.qhimg.com/d/inn/c886d09f/birds.png';
const scene = new Scene('#animations-playback', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
const layer = scene.layer('fglayer');
const timeline = layer.timeline;
const playbackRate = document.getElementById('playbackRate');
const speedUp = document.getElementById('speedUp');
const slowDown = document.getElementById('slowDown');
const resume = document.getElementById('resume');
function updateSpeed() {
playbackRate.innerHTML = `playbackRate: ${timeline.playbackRate.toFixed(1)}`;
}
speedUp.addEventListener('click', () => {
timeline.playbackRate += 0.5;
updateSpeed();
});
slowDown.addEventListener('click', () => {
timeline.playbackRate -= 0.5;
updateSpeed();
});
pause.addEventListener('click', () => {
timeline.playbackRate = 0;
updateSpeed();
});
resume.addEventListener('click', () => {
timeline.playbackRate = 1.0;
updateSpeed();
});
await scene.preload([birdsRes, birdsJsonUrl]);
for(let i = 0; i < 10; i++) {
if(i !== 5 && i !== 9) {
const bird = new Sprite('bird1.png');
bird.attr({
anchor: [0.5, 0.5],
pos: [-50, 100 + (i % 5) * 100],
});
layer.append(bird);
bird.animate([
{textures: 'bird1.png'},
{textures: 'bird2.png'},
{textures: 'bird3.png'},
{textures: 'bird1.png'},
], {
duration: 500,
iterations: Infinity,
easing: 'step-end',
});
const delay = i < 5 ? Math.abs(2 - i) * 300 : (4 - Math.abs(7 - i)) * 300;
bird.animate([
{x: -50},
{x: 1600},
{x: -50},
], {
delay,
duration: 6000,
// direction: 'alternate',
iterations: Infinity,
});
bird.animate([
{scale: [1, 1]},
{scale: [-1, 1]},
{scale: [1, 1]},
delay,
iterations: Infinity,
easing: 'step-end',
});
}
}
}())
spritejs动画功能非常丰富,关于动画的其他内容,可参考高级用法:动画。
spritejs可以通过shadow
属性给元素设置阴影:
除了设置shadow外,spritejs支持,能够方便地给元素添加各种滤镜。
;(async function () {
const images = [
{id: 'girl1', src: 'https://p5.ssl.qhimg.com/t01feb7d2e05533ca2f.jpg'},
{id: 'girl2', src: 'https://p5.ssl.qhimg.com/t01deebfb5b3ac6884e.jpg'},
];
const scene = new Scene('#filters', {viewport: ['auto', 'auto'], resolution: [1540, 600]});
const layer = scene.layer('fglayer');
const y1 = 50,
y2 = 320;
function applyFilters(id, filters, y, scale = 1) {
filters.forEach((f, i) => {
const s = new Sprite();
const textures = {id},
filter = {};
if(f.length === 2) {
filter[f[0]] = f[1];
}
s.attr({
textures,
pos: [50 + i * 250, y],
scale,
filter,
});
layer.append(s);
});
}
await scene.preload(...images);
const filters1 = [
[],
['brightness', '150%'],
['grayscale', '50%'],
['blur', '12px'],
['dropShadow', [15, 15, 5, '#033']],
['hueRotate', 45],
];
applyFilters('girl1', filters1, y1, 0.5);
const filters2 = [
[],
['invert', '100%'],
['opacity', '70%'],
['saturate', '20%'],
['sepia', '100%'],
['hueRotate', 135],
];
applyFilters('girl2', filters2, y2);