动态加载svg,根据path路径移动动画,配置关键帧实现动画效果(移动和透明度)最后附上gitee地址

关键帧动画效果

一、先上依赖包

基本的vue3项目配置,需要安装d3和animejs的包。

二、准备一个路径文件path.svg

<svg width="500px" height="300px" viewBox="0 0 500 300" xmlns="http://www.w3.org/2000/svg">
    <path d="M45.716904,269.5 C250,269.5 250,30.5 454.283096,30.5" id="Path-3"/>
</svg>

注意svg文件中的 xmlns="http://www.w3.org/2000/svg" 是必须存在的

三、动态加载svg

三、加载path路径给path设置样式,并且添加移动图片

 四、配置关键帧数据,处理关键帧数据

export const keyframesList = [
    {
        anim:[
            {
                style: 'opacity',
                from: "0",
                to: "50",
                start: "0",
                end: "30",
            },
            {
                style: 'opacity',
                from: "50",
                to: "100",
                start: "30",
                end: "40",
            },
            {
                style: 'opacity',
                from: "100",
                to: "0",
                start: "40",
                end: "80",
            },
            {
                style: 'opacity',
                from: "0",
                to: "100",
                start: "80",
                end: "100",
            },
            {
                style: 'translate',
                from: "0",
                to: "50",
                start: "0",
                end: "30",
            },
            {
                style: 'translate',
                from: "50",
                to: "100",
                start: "30",
                end: "40",
            },
            {
                style: 'translate',
                from: "100",
                to: "0",
                start: "40",
                end: "80",
            },
            {
                style: 'translate',
                from: "0",
                to: "100",
                start: "80",
                end: "100",
            }
        ]
    }
]
export function initData(obj){
    // eslint-disable-next-line no-useless-escape
    let reg = /[-\d\.]+/g;
    let numArrFrom = obj.from.match(reg);
    let numArrTo = obj.to.match(reg);
    if (!numArrFrom || !numArrTo || numArrFrom.length == 0 || numArrTo.length == 0 || numArrFrom.length != numArrTo.length) {
        console.warn('数据输入错误');
    }
    for (let i = 0; i < numArrFrom.length; i++) {
        numArrFrom[i] = parseFloat(numArrFrom[i]);
        numArrTo[i] = parseFloat(numArrTo[i]);
    }
    let strArr = obj.from.split(reg);
    if (numArrFrom.length <= 0) {
        return;
    }
    return {
        strArr: strArr,
        numArrFrom: numArrFrom,
        numArrTo: numArrTo,
        totalLength: strArr.length + numArrFrom.length,
        isEnd: false,
    }
}

五、渲染关键帧动画

keyframesAnime脚本
export function keyframesAnime({pathDom,keyframesList, duration = 5000}){
    const pathLength = pathDom.getTotalLength();
    let keyframes = [];
    let list = []
    const frameLength = 1;
    // 计算全部路线
    for(let i = 0; i<= pathLength; i++){
        const framePosition = frameLength * i;
        const framePoint = pathDom.getPointAtLength(framePosition);
        const angle = getRotationAtPoint(pathDom, framePosition)
        // let keyframe;
        let keyframe = {
            duration: duration / pathLength,
            easing: 'linear',
            translateY:`${framePoint.y}`,
            translateX:`${framePoint.x}`,
            rotate:`${angle}`,
        };
        keyframes.push(keyframe)
    }
    // 计算关键帧路线及透明度
    for(let i = 0; i < keyframesList[0].anim.length; i++){
        let target = keyframesList[0].anim[i]

        if((Number(target.end) > Number(target.start) ) && !target.initData.isEnd){
            let percent = (target.end - target.start) / 100
            if(percent >= 1){
                target.initData.isEnd = true
            }
            if(target.style === "translate"){
                let index = i - keyframesList[0].anim.length/2
                if(target.initData.numArrFrom[0] > target.initData.numArrTo[0]){
                    let num = ((keyframesList[0].anim[index].initData.numArrFrom[0] - keyframesList[0].anim[index].initData.numArrTo[0]) / 100) /(Math.round(keyframes.length * (target.initData.numArrFrom[0]/100)) - Math.round(keyframes.length * (target.initData.numArrTo[0]/100)))
                    let opacityNum = 0
                    for(let j = Math.round(keyframes.length * (target.initData.numArrFrom[0]/100))-1; j > Math.round(keyframes.length * (target.initData.numArrTo[0]/100)); j--){
                        list.push({
                            ...keyframes[j],
                            duration:(duration * percent )/ (Math.round(keyframes.length * (target.initData.numArrFrom[0]/100)) - Math.round(keyframes.length * (target.initData.numArrTo[0]/100))),
                            opacity: opacityNum
                        })
                        opacityNum += num
                    }
                }else{
                    let num = ((keyframesList[0].anim[index].initData.numArrTo[0] - keyframesList[0].anim[index].initData.numArrFrom[0]) / 100) /(Math.round(keyframes.length * (target.initData.numArrTo[0]/100)) - Math.round(keyframes.length * (target.initData.numArrFrom[0]/100)))
                    let opacityNum = 0
                    for(let j= Math.round(keyframes.length * (target.initData.numArrFrom[0]/100)); j< Math.round(keyframes.length * (target.initData.numArrTo[0]/100)); j++){
                        list.push({
                            ...keyframes[j],
                            duration:(duration * percent )/ (Math.round(keyframes.length * (target.initData.numArrTo[0]/100)) - Math.round(keyframes.length * (target.initData.numArrFrom[0]/100))),
                            opacity:opacityNum
                        })
                        opacityNum += num
                    }
                }
            }
        }
    }
    return list;
}
function getRotationAtPoint(pathEl, length) {
    const startPoint = pathEl.getPointAtLength(length - 0.01);
    const endPoint = pathEl.getPointAtLength(length + 0.01);
    const angle = Math.atan2(endPoint.y - startPoint.y, endPoint.x - startPoint.x) * 180 / Math.PI;
    return angle;
}

 git地址vue-keyframes: js关键帧动画

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值