马黑黑 发表于 2025-9-8 20:26

夏花

<style>
        @import 'https://638183.freep.cn/638183/web/css/tz01.css';
        #pa { --offsetX: 81px; --bg: url('https://638183.freep.cn/638183/t24/w6/xxhx.webp') no-repeat center/cover; --ma-size: 15%; }
        #ma { animation: unset; cursor: unset; left: 10px; bottom: 65px; }
        #btnFs { right: 20px; top: 20px; color: #eee; border-color: currentColor!important; }
        #player { stroke-width: 2; cursor: pointer; animation: rotate 8s linear infinite var(--state); }
        #lrc { left: 30px; bottom: 20px; }
        #lrc::before { background: green; background-clip: text; -webkit-background-clip: text; }
        .prog { stroke-width: 10; transition: 0.25s; }
</style>

<div id="pa">
        <audio id="aud" src="https://music.163.com/song/media/outer/url?id=2717576053" autoplay loop></audio>
        <video class="pd-vid" src="https://img.tukuppt.com/video_show/2402760/00/01/32/5b3f53c677460.mp4" autoplay loop muted></video>
        <div id="ma" class="brightness">
                <svg id="msvg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="-200 -200 400 400">
                        <path class="prog" d="M0 190 C-200 20,-300 -320,0 -100 C300 -320,200 20,0 190" fill="lightyellow" stroke="red" stroke-dasharray="1227" stroke-dashoffset="1227"></path>
                        <path class="prog" d="M0 190 C-200 20,-300 -320,0 -100 C300 -320,200 20,0 190" fill="none" stroke="rgba(100,0,0,.35)" stroke-dasharray="1227" stroke-dashoffset="0" style="cursor: pointer;">
                                <title>调节进度</title>
                        </path>
                        <path id="player" d="M0 0 C-160 100 100 100 0 0 C-6.603 -188.564 -136.603 36.603 0 0 C166.603 88.564 36.603 -136.603 0 0Z" fill="darkred" stroke="yellow">
                                <title>Alt+X</title>
                        </path>
                </svg>
        </div>
</div>


<script type="module">
        import lrc from 'https://638183.freep.cn/638183/web/lrc/hclrc_only.js';
        import { FS } from 'https://638183.freep.cn/638183/web/js/svglz_fs.js';

        const progs = document.querySelectorAll('.prog'); // 进度条(path标签)标识
        const pathLength = progs.getTotalLength(); // 路径长度

        // 音频播放时 : 进度变更+跳动
        aud.ontimeupdate = () => {
                progs.setAttribute('stroke-dashoffset', pathLength - pathLength * aud.currentTime / aud.duration);
                progs.setAttribute('opacity', Math.random() * 0.5 + 0.5);
        };

        // 点击track路径 : 调节播放进度
        progs.onclick = (e) => {
                const point = msvg.createSVGPoint(); // 创建坐标对象
                point.x = e.clientX;
                point.y = e.clientY;
                // 转换点坐标为svg坐标对象
                const svgPoint = point.matrixTransform(msvg.getScreenCTM().inverse());
                if (progs.isPointInStroke(svgPoint)) {
                        aud.currentTime = aud.duration * getDistanceFromStart(progs, svgPoint) / pathLength;
                }
        };

const geci = [
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
        ,
       
];

        FS(pa, player);
        lrc(pa, geci);

        // 获取路径点击点长度
        function getDistanceFromStart(pathElement, point) {
                const samples = Math.ceil(pathLength); // 按像素采样
                let bestPos = 0;
                let bestDist = Infinity;
                // 路径起点
                const startPoint = pathElement.getPointAtLength(0);
                let minDist = Math.hypot(point.x - startPoint.x, point.y - startPoint.y);
                // 采样路径上的点
                for (let i = 0; i <= samples; i++) {
                        const pos = (i / samples) * pathLength;
                        const pathPoint = pathElement.getPointAtLength(pos);
                        const dist = Math.hypot(point.x - pathPoint.x, point.y - pathPoint.y);
                        if (dist < minDist) {
                                minDist = dist;
                                bestPos = pos;
                        }
                }
                // 处理封闭路径
                if (bestPos > pathLength - 1 && minDist > Math.hypot(point.x - startPoint.x, point.y - startPoint.y)) {
                        return 0;
                }
                return bestPos;
        }
</script>

马黑黑 发表于 2025-9-8 20:26

帖子代码

<style>
    @import 'https://638183.freep.cn/638183/web/css/tz01.css';
    #pa { --offsetX: 81px; --bg: url('https://638183.freep.cn/638183/t24/w6/xxhx.webp') no-repeat center/cover; --ma-size: 15%; }
    #ma { animation: unset; cursor: unset; left: 10px; bottom: 65px; }
    #btnFs { right: 20px; top: 20px; color: #eee; border-color: currentColor!important; }
    #player { stroke-width: 2; cursor: pointer; animation: rotate 8s linear infinite var(--state); }
    #lrc { left: 30px; bottom: 20px; }
    #lrc::before { background: green; background-clip: text; -webkit-background-clip: text; }
    .prog { stroke-width: 10; transition: 0.25s; }
</style>

<div id="pa">
    <audio id="aud" src="https://music.163.com/song/media/outer/url?id=2717576053" autoplay loop></audio>
    <video class="pd-vid" src="https://img.tukuppt.com/video_show/2402760/00/01/32/5b3f53c677460.mp4" autoplay loop muted></video>
    <div id="ma" class="brightness">
      <svg id="msvg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="-200 -200 400 400">
            <path class="prog" d="M0 190 C-200 20,-300 -320,0 -100 C300 -320,200 20,0 190" fill="lightyellow" stroke="red" stroke-dasharray="1227" stroke-dashoffset="1227"></path>
            <path class="prog" d="M0 190 C-200 20,-300 -320,0 -100 C300 -320,200 20,0 190" fill="none" stroke="rgba(100,0,0,.35)" stroke-dasharray="1227" stroke-dashoffset="0" style="cursor: pointer;">
                <title>调节进度</title>
            </path>
            <path id="player" d="M0 0 C-160 100 100 100 0 0 C-6.603 -188.564 -136.603 36.603 0 0 C166.603 88.564 36.603 -136.603 0 0Z" fill="darkred" stroke="yellow">
                <title>Alt+X</title>
            </path>
      </svg>
    </div>
</div>


<script type="module">
    import lrc from 'https://638183.freep.cn/638183/web/lrc/hclrc_only.js';
    import { FS } from 'https://638183.freep.cn/638183/web/js/svglz_fs.js';

    const progs = document.querySelectorAll('.prog'); // 进度条(path标签)标识
    const pathLength = progs.getTotalLength(); // 路径长度

    // 音频播放时 : 进度变更+跳动
    aud.ontimeupdate = () => {
      progs.setAttribute('stroke-dashoffset', pathLength - pathLength * aud.currentTime / aud.duration);
      progs.setAttribute('opacity', Math.random() * 0.5 + 0.5);
    };

    // 点击track路径 : 调节播放进度
    progs.onclick = (e) => {
      const point = msvg.createSVGPoint(); // 创建坐标对象
      point.x = e.clientX;
      point.y = e.clientY;
      // 转换点坐标为svg坐标对象
      const svgPoint = point.matrixTransform(msvg.getScreenCTM().inverse());
      if (progs.isPointInStroke(svgPoint)) {
            aud.currentTime = aud.duration * getDistanceFromStart(progs, svgPoint) / pathLength;
      }
    };

const geci = [
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
    ,
   
];

    FS(pa, player);
    lrc(pa, geci);

    // 获取路径点击点长度
    function getDistanceFromStart(pathElement, point) {
      const samples = Math.ceil(pathLength); // 按像素采样
      let bestPos = 0;
      let bestDist = Infinity;
      // 路径起点
      const startPoint = pathElement.getPointAtLength(0);
      let minDist = Math.hypot(point.x - startPoint.x, point.y - startPoint.y);
      // 采样路径上的点
      for (let i = 0; i <= samples; i++) {
            const pos = (i / samples) * pathLength;
            const pathPoint = pathElement.getPointAtLength(pos);
            const dist = Math.hypot(point.x - pathPoint.x, point.y - pathPoint.y);
            if (dist < minDist) {
                minDist = dist;
                bestPos = pos;
            }
      }
      // 处理封闭路径
      if (bestPos > pathLength - 1 && minDist > Math.hypot(point.x - startPoint.x, point.y - startPoint.y)) {
            return 0;
      }
      return bestPos;
    }
</script>

马黑黑 发表于 2025-9-8 20:28

主要演示:

实现路径上的点击控制音频播放进度

马黑黑 发表于 2025-9-8 20:29

歌词粗略转换,没有时间进行详细微调

马黑黑 发表于 2025-9-8 20:33

获取路径点击点离路径开头的距离与 svg 的 viewBox 的设置没有任何要求,怎么设置 viewBox 都可以

杨帆 发表于 2025-9-8 21:03

完美实现路径上的点击控制音频播放进度,谢谢马老师经典分享{:4_191:}

花飞飞 发表于 2025-9-8 21:14

这个是静谧夜晚的萤火,看了下是视频效果,搭这样的小花园太漂亮了~~{:4_173:}
粒子和视频傻傻分不表。。开贴还以为是粒子。。

花飞飞 发表于 2025-9-8 21:21

心形路径做成小播这么漂亮。。。
17行和18行写了两遍,头一遍是心形加了填充色,
第二遍是纯红色外框。。。这个可以点击调节歌曲进度。。。
这个可比刚才看的教程更先进了。。{:4_199:}想听哪里就点哪里了。。

花飞飞 发表于 2025-9-8 21:24

21行填充了深红色,用了黄色边缘,那么中间那个风扇叶片形状是画出来的?{:4_170:}
这也太厉害了。。
这三个元素全部都在id="ma" class="brightness,之内,给了滤镜,触碰之后全体点亮,好看。。

花飞飞 发表于 2025-9-8 21:31

感觉从42行开始不是我这小白能看懂理解的,还是等封包直接用吧。。{:4_173:}
这么复杂的计算,哎,到底是电脑还是人脑。。白老师是真厉害

红影 发表于 2025-9-8 22:15

马黑黑 发表于 2025-9-8 20:28
主要演示:

实现路径上的点击控制音频播放进度

前面那个帖子里还说,控制路径需要增加很多代码,还以为不准备弄了,这里就已经实现了{:4_199:}

红影 发表于 2025-9-8 22:18

这园子太美了,好想有个这样是小花园,晚上去喝喝茶,享受一下它的安宁和轻松{:4_187:}

红影 发表于 2025-9-8 22:22

这心形加别的颜色,也挺漂亮,中间还画了个图形当小播。这构思真棒{:4_187:}

马黑黑 发表于 2025-9-9 08:18

红影 发表于 2025-9-8 22:22
这心形加别的颜色,也挺漂亮,中间还画了个图形当小播。这构思真棒

还好

马黑黑 发表于 2025-9-9 08:18

红影 发表于 2025-9-8 22:18
这园子太美了,好想有个这样是小花园,晚上去喝喝茶,享受一下它的安宁和轻松

想得美

马黑黑 发表于 2025-9-9 08:19

红影 发表于 2025-9-8 22:15
前面那个帖子里还说,控制路径需要增加很多代码,还以为不准备弄了,这里就已经实现了

以前的插件做过的。当然,当时的处理细节与现在这个有所不同但道理差不多

马黑黑 发表于 2025-9-9 08:19

花飞飞 发表于 2025-9-8 21:31
感觉从42行开始不是我这小白能看懂理解的,还是等封包直接用吧。。
这么复杂的计算,哎,到底是 ...

涉及到的知识点已经严重超过大班水平了

马黑黑 发表于 2025-9-9 08:20

花飞飞 发表于 2025-9-8 21:24
21行填充了深红色,用了黄色边缘,那么中间那个风扇叶片形状是画出来的?
这也太厉害了。。
这 ...

啥呀?这是夏花,夏天长得猛烈像扇叶那么夸张了

马黑黑 发表于 2025-9-9 08:21

花飞飞 发表于 2025-9-8 21:21
心形路径做成小播这么漂亮。。。
17行和18行写了两遍,头一遍是心形加了填充色,
第二遍是纯红色外框。 ...

其实啥形都可以哈

马黑黑 发表于 2025-9-9 08:21

花飞飞 发表于 2025-9-8 21:14
这个是静谧夜晚的萤火,看了下是视频效果,搭这样的小花园太漂亮了~~
粒子和视频傻傻分不表。。 ...

据说这个视频是实拍的效果
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 夏花