hookehuyr

feat(animation): 添加SVG图像到动画路径组件

在动画路径组件中新增了SVG图像显示功能,支持根据激活节点动态切换图像。引入了多个SVG资源文件,并更新了动画路径的逻辑以支持图像显示。
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
<!--
* @Date: 2025-03-28 09:23:04
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-03-28 14:41:28
* @LastEditTime: 2025-03-28 21:28:07
* @FilePath: /mlaj/src/views/animation.vue
* @Description: 贝塞尔曲线动画路径组件
*
......@@ -13,8 +13,14 @@
-->
<template>
<div class="animation-container">
<div style="position: fixed; top: 0; right: 0;">
<button class="next-button" @click="nextStep" :disabled="activeNodeIndex >= points.length - 1">下一步</button>
<div style="position: fixed; top: 0; right: 0">
<button
class="next-button"
@click="nextStep"
:disabled="activeNodeIndex >= points.length - 1"
>
下一步
</button>
</div>
<svg width="100%" height="100%" viewBox="0 0 1000 1200" class="animation-svg">
<!-- 定义箭头标记 -->
......@@ -79,12 +85,29 @@
:class="['node', { 'node-active': activeNodeIndex >= index - 1 }]"
/>
</template>
<!-- Image In Svg -->
<template v-for="(obj, index) in svgObj" :key="obj.name">
<image
:id="obj.name"
:href="index <= activeNodeIndex ? obj.light_up : obj.not_light"
width="100"
height="100"
:x="points[0].x + obj.offset.x"
:y="points[0].y + obj.offset.y"
/>
</template>
</svg>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { ref, computed } from "vue";
import img_svg1 from "@/assets/1.svg";
import img_svg2 from "@/assets/2.svg";
import img_svg3 from "@/assets/3.svg";
import img_svg4 from "@/assets/4.svg";
import img_svg5 from "@/assets/5.svg";
// 定义节点坐标数组,每个节点包含x和y坐标
// 这些点将用于生成贝塞尔曲线的路径
......@@ -93,7 +116,7 @@ const points = ref([
{ x: 300, y: 300 },
{ x: 700, y: 600 },
{ x: 300, y: 800 },
{ x: 700, y: 1000 }
{ x: 700, y: 1000 },
]);
// 当前激活的节点索引,初始值为-1表示没有节点被激活
......@@ -114,10 +137,10 @@ const pathData = computed(() => {
} else {
const prevPoint = points.value[index - 1];
const segment = calculatePathSegment(prevPoint, point);
path.push(segment.substring(segment.indexOf('C')));
path.push(segment.substring(segment.indexOf("C")));
}
});
return path.join(' ');
return path.join(" ");
});
// 计算两点之间的贝塞尔曲线路径段
......@@ -141,11 +164,11 @@ const calculatePathSegment = (startPoint, endPoint) => {
// 计算偏移后的起点和终点,根据路径方向调整垂直偏移
const adjustedStart = {
x: startPoint.x + unitX * offset,
y: startPoint.y + (dy > 0 ? -verticalOffset : verticalOffset)
y: startPoint.y + (dy > 0 ? -verticalOffset : verticalOffset),
};
const adjustedEnd = {
x: endPoint.x - unitX * offset,
y: endPoint.y + (dy > 0 ? verticalOffset : -verticalOffset)
y: endPoint.y + (dy > 0 ? verticalOffset : -verticalOffset),
};
// 计算控制点
......@@ -160,10 +183,9 @@ const calculatePathSegment = (startPoint, endPoint) => {
// 未激活路径的颜色
// 使用浅灰色(#ccc)表示未激活状态
const pathColor = computed(() => {
return '#ccc';
return "#ccc";
});
// 处理节点点击事件,激活指定节点并更新路径
// @param index - 被点击节点的索引
// 点击节点时会激活该节点及其之前的所有节点和路径
......@@ -197,11 +219,60 @@ const nextStep = () => {
activePathSegments.value.push(newSegment);
}
// 如果是最后一个节点,直接将其设置为激活状态
if (activeNodeIndex.value === points.value.length - 2) {
if (activeNodeIndex.value === points.value.length - 1) {
activeNodeIndex.value = points.value.length - 1;
}
}
};
// 图片对象数组
const svgObj = [
{
name: "node1",
not_light: img_svg1,
light_up: img_svg5,
offset: {
x: -350,
y: -25,
},
},
{
name: "node2",
not_light: img_svg2,
light_up: img_svg4,
offset: {
x: -150,
y: 200,
},
},
{
name: "node3",
not_light: img_svg3,
light_up: img_svg3,
offset: {
x: -450,
y: 480,
},
},
{
name: "node4",
not_light: img_svg4,
light_up: img_svg2,
offset: {
x: -150,
y: 700,
},
},
{
name: "node5",
not_light: img_svg5,
light_up: img_svg1,
offset: {
x: -450,
y: 950,
},
},
];
</script>
<style scoped>
......@@ -247,7 +318,7 @@ const nextStep = () => {
.node-active {
fill: white;
stroke: #4CAF50;
stroke: #4caf50;
}
.path-animation {
......@@ -269,7 +340,7 @@ const nextStep = () => {
top: 1.25rem;
right: 1.25rem;
padding: 0.5rem 1rem;
background-color: #4CAF50;
background-color: #4caf50;
color: white;
border: none;
border-radius: 0.25rem;
......