数据可视化大屏项目开发中,设计师提供了下面的底座装饰图,习惯了动态效果,如果只是放一张静态图片的话,总觉得少点意思。
实现动态效果
我们首先将图片拆解,我们将图片拆分成4部分,刻度部分不要,
图片拆解
最底部的线
中间的线条
带流光的线条
顶部的遮罩
线条添加流光
我们使用saber给线条添加流光效果。
刻度动画
刻度分为两部分,第一部分是浅色部分,第二部分是发光部分
浅色部分
我们使用椭圆工具绘制描边10 颜色浅黄色,虚线8.5
开启3d,配置x轴68°,这样一个倾斜的齿轮就出现了。
发光层
我们再复制一层,使用Deep Glow来发光,我们的发光齿轮就出现了
添加修剪路径添加动画,这样一个刻度逐渐变亮的效果就实现了,接下来
动态效果
旋转动画
逐渐变亮以后,我们还需要让其转起来,我们跟z轴打一个关键帧,从第3s 0度到第6s
最终ae效果
我们最终的ae效果就出来了
接下来,我们再做其他3个颜色的底座效果,组成四个底座。
导出图片资源
我们制作出来的图片大小是530408,导出来后一共150张图片,大小有20多M,文件有点大,我们需要压缩一下,这里我们使用的是图压这种工具,我们将图片缩小一点改为265204,使用工具 图压 对图片进行压缩处理,
压缩后就有6M左右了。
页面加载
这里的动画,我们需要对动画分开处理,分为前三秒和后三秒,前三秒只需要第一次加载执行,后三秒是旋转动画,可以一直循环,我们通过js来对图片进行处理。
<template>
<canvas ref="animationCanvas" class="animation_canvas" id="animation_canvas"></canvas>
</template>
<script>
export default {
props: {
// 文件数量
fileLength: {
type: Number,
default: 149
},
// 动画间隔
IntervalTime: {
type: Number,
default: 50
},
// 图片路径
imgPath: {
type: String,
default: 'lan'
}
},
data() {
return {
animationCanvas: null
};
},
methods: {
async loadImages2(sources) {
for (let i = 1; i <= this.fileLength; i++) {
const image = await import(`./``{this.imgPath}/``{i}.png`);
sources.push(image.default);
}
},
loadImages(sources, callback) {
let loadedImages = 0;
const numImages = sources.length;
const images = [];
for (let i = 0; i < numImages; i++) {
images[i] = new Image();
images[i].onload = () => {
if (++loadedImages >= numImages) {
callback(images);
}
};
images[i].src = sources[i];
}
},
playImages(images, ctx, width, height, intervalTime) {
let imageNow = 0;
let isFirstLoop = true; // 添加标志判断是否是第一次循环
setInterval(() => {
ctx.clearRect(0, 0, width, height);
ctx.drawImage(images[imageNow], 0, 0, width, height);
imageNow++;
if (imageNow >= images.length) {
if (isFirstLoop) {
imageNow = 74; // 第二次循环从第74张开始(索引从0开始,所以是73)
isFirstLoop = false;
} else {
imageNow = 74; // 之后的循环都从第74张开始
}
}
}, intervalTime);
}
},
async mounted() {
this.$nextTick(async () => {
const canvas = this.$refs.animationCanvas;
if (canvas) {
const ctx = canvas.getContext('2d');
if (!ctx) {
console.error('Failed to get canvas context');
return;
}
const sources = [];
// 先加载第一张图片并展示
const firstImage = await import(`./${this.imgPath}/0.png`);
sources.push(firstImage.default);
const width = canvas.offsetWidth;
const height = canvas.offsetHeight;
canvas.width = width;
canvas.height = height;
const firstImgElement = new Image();
firstImgElement.src = sources[0];
firstImgElement.onload = () => {
ctx.drawImage(firstImgElement, 0, 0, width, height);
};
// 加载剩余的图片
await this.loadImages2(sources);
// 执行图片预加载,加载完成后执行动画
this.loadImages(sources, (images) => {
this.playImages(images, ctx, width, height, this.IntervalTime);
});
}
});
}
};
</script>
<style scoped>
.animation_canvas {
width: 133PX;
height: 102PX;
position: absolute;
z-index: 1;
}
</style>
最终效果
实例代码下载
ae源文件 和 vue3项目实例代码