马黑黑 发表于 2024-10-29 19:43

svgdr : 元素沿路径排列+可控闪烁CSS动画

<p style="text-align:center;">
        <svg id="mysvg" width="700" height="400"></svg>
</p>

<script>
var sc = document.createElement('script');
sc.src = 'https://638183.freep.cn/638183/web/js/svgdr.js';
document.body.appendChild(sc);

sc.onload = () => {
        var dr = _dr(mysvg)

        var balls = [], playing = true;
        dr.path('M0 400 Q350 -280,700 400', 'none','none').id('path');
        var len = path.getTotalLength();
        for(var i = 1, tt = 20; i < tt; i ++) {
                var point = path.getPointAtLength(len / tt * i);
                var color = '#' + Math.random().toString(16).substring(2,8),
                        delay = Math.random() * i * -0.1;
                var cx = point.x, cy = point.y;
                dr.circle(cx,cy,20,color).set('class','ball').style(`--delay: ${delay}s`);
                balls.push(dr.elm);
        }
        dr.css(`
                #mysvg { --state: running; }
                .ball { running; cursor: pointer; animation: flash .1s var(--delay) linear infinite alternate var(--state); }
                @keyframes flash { to { opacity: .2; } }
        `);

        balls.forEach(b => b.onclick = () => {
                playing = !playing;
                dr.svg.style.setProperty('--state', ['paused','running'][+playing]);
        });
};
</script>

马黑黑 发表于 2024-10-29 19:44

代码:

<p style="text-align:center;">
    <svg id="mysvg" width="700" height="400"></svg>
</p>

<script>
var sc = document.createElement('script');
sc.src = 'https://638183.freep.cn/638183/web/js2024/svgdr_trial.js';
document.body.appendChild(sc);

sc.onload = () => {
    var dr = _dr(mysvg)

    var balls = [], playing = true;
    dr.path('M0 400 Q350 -280,700 400', 'none','none').id('path');
    var len = path.getTotalLength();
    for(var i = 1, tt = 20; i < tt; i ++) {
      var point = path.getPointAtLength(len / tt * i);
      var color = '#' + Math.random().toString(16).substring(2,8),
            delay = Math.random() * i * -0.1;
      var cx = point.x, cy = point.y;
      dr.circle(cx,cy,20,color).set('class','ball').style(`--delay: ${delay}s`);
      balls.push(dr.elm);
    }
    dr.css(`
      #mysvg { --state: running; }
      .ball { running; cursor: pointer; animation: flash .1s var(--delay) linear infinite alternate var(--state); }
      @keyframes flash { to { opacity: .2; } }
    `);

    balls.forEach(b => b.onclick = () => {
      playing = !playing;
      dr.svg.style.setProperty('--state', ['paused','running'][+playing]);
    });
};
</script>

马黑黑 发表于 2024-10-29 19:56

JS代码解释:

(一)06-08行:加载插件
(二)11行:声明画笔;
(三)13行:声明两个变量,balls 数组变量用于装载小球对象,playing 布尔变量是动画运行标识;
(四)14行:画一条无痕路径,添加 id 是为了获得路径长度等信息;
(五)15行:获取路径长度 len;
(六)16*23行:用一个for循环绘制 19 个小圆,小圆的cx、cy依据路径长度百分比获得(path.getPointAtLength),从而达到在路径上均匀布置小球的目的。小球颜色随机。小球加入class属性。同时将小球记入balls数组;
(七)24-28行:写一个svg内部CSS样式表,给svg定义 --state 变量,给小球设置一个基本CSS样式(比如手型图标响应、动画),设计一个 flash 动画等;
(八)30-33行:小球点击交互。

马黑黑 发表于 2024-10-29 20:03

svg有文本路径,可以将文本按路径排列。但是,其他元素按路径布排则需要另辟蹊径,本例的实现思路是,利用路径的两个方法,一是 pathElement.getTotalLength() 获的路径总长度,二是 pathElement.getPointsAt() 方法后的路径上某个长度的点坐标,来确定小圆的中心坐标点,从而达到目的。

for语句中,变量 i 从 1 开始,步进变化到小于上限 tt,酱紫,tt 为 20 时实际上只画了 19 个园。这是为了节省计算,我们的目标之一是小球左右位置齐整,根据路径的设计这么做就不必去计算第一个球和最后一个球的具体位置。

起个网名好难 发表于 2024-10-29 20:30

马黑黑 发表于 2024-10-29 19:44
代码:

tt = 20 没变化没必要放在循环里吧;
15行之后, len / tt 也是不变的,在循环外计算好,每次循环就免得计算了。

醉美水芙蓉 发表于 2024-10-29 20:50

红影 发表于 2024-10-29 20:57

getTotalLength()用于获取SVG路径的总长度,而getPointAtLength(len)则返回路径上特定距离处的点的坐标。

这个功能真好,不用计算就能得到路径上的点的坐标了。黑黑还做在了封装里,用起来更方便了{:4_199:}

马黑黑 发表于 2024-10-29 21:09

红影 发表于 2024-10-29 20:57
getTotalLength()用于获取SVG路径的总长度,而getPointAtLength(len)则返回路径上特定距离处的点的坐标。
...

这两个是JS的方法,在svgdr中可以使用

马黑黑 发表于 2024-10-29 21:11

起个网名好难 发表于 2024-10-29 20:30
tt = 20 没变化没必要放在循环里吧;
15行之后, len / tt 也是不变的,在循环外计算好,每次循环就免得 ...

这 tt 同在for循环中便于修改总数,声明在外部也是一种做法。这个无关紧要,很多人都这么做

红影 发表于 2024-10-29 21:11

我去试了个直线的,也挺好看呢{:4_173:}

马黑黑 发表于 2024-10-29 21:11

醉美水芙蓉 发表于 2024-10-29 20:50
欣赏学习老师新教程!

这是测试

马黑黑 发表于 2024-10-29 21:12

红影 发表于 2024-10-29 21:11
我去试了个直线的,也挺好看呢

可以设计各类路径

红影 发表于 2024-10-29 21:19

马黑黑 发表于 2024-10-29 21:09
这两个是JS的方法,在svgdr中可以使用

还是头一次知道这方法,这个太好了{:4_187:}

马黑黑 发表于 2024-10-29 21:19

红影 发表于 2024-10-29 21:19
还是头一次知道这方法,这个太好了

方法都有的,而且还不断地有新方法,只是大家不去留意

红影 发表于 2024-10-29 21:19

马黑黑 发表于 2024-10-29 21:12
可以设计各类路径

这个用明暗变化来形成闪烁,很漂亮{:4_187:}

马黑黑 发表于 2024-10-29 21:21

红影 发表于 2024-10-29 21:19
这个用明暗变化来形成闪烁,很漂亮

这里用的是透明度,还可以考虑用亮度,或二者相结合

红影 发表于 2024-10-29 21:21

马黑黑 发表于 2024-10-29 21:19
方法都有的,而且还不断地有新方法,只是大家不去留意

不需要去计算的,都是好方法{:4_173:}

马黑黑 发表于 2024-10-29 21:22

红影 发表于 2024-10-29 21:21
不需要去计算的,都是好方法

如果自己去计算路径的长度、路径某一点的坐标值,那是相当复杂的

起个网名好难 发表于 2024-10-29 21:27

马黑黑 发表于 2024-10-29 21:11
这 tt 同在for循环中便于修改总数,声明在外部也是一种做法。这个无关紧要,很多人都这么做

确实无关紧要,但至少在这个例子它是没必要这么做的。

马黑黑 发表于 2024-10-29 21:29

起个网名好难 发表于 2024-10-29 21:27
确实无关紧要,但至少在这个例子它是没必要这么做的。

tt在for循环里参与计算 point 值,这个tt得有,至于放在for之前还是for内,这都没问题的,C语言也有这么写的,JS和c很相似
页: [1] 2 3 4 5
查看完整版本: svgdr : 元素沿路径排列+可控闪烁CSS动画