夏花
<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> 帖子代码
<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>
主要演示:
实现路径上的点击控制音频播放进度 歌词粗略转换,没有时间进行详细微调 获取路径点击点离路径开头的距离与 svg 的 viewBox 的设置没有任何要求,怎么设置 viewBox 都可以 完美实现路径上的点击控制音频播放进度,谢谢马老师经典分享{:4_191:} 这个是静谧夜晚的萤火,看了下是视频效果,搭这样的小花园太漂亮了~~{:4_173:}
粒子和视频傻傻分不表。。开贴还以为是粒子。。 心形路径做成小播这么漂亮。。。
17行和18行写了两遍,头一遍是心形加了填充色,
第二遍是纯红色外框。。。这个可以点击调节歌曲进度。。。
这个可比刚才看的教程更先进了。。{:4_199:}想听哪里就点哪里了。。 21行填充了深红色,用了黄色边缘,那么中间那个风扇叶片形状是画出来的?{:4_170:}
这也太厉害了。。
这三个元素全部都在id="ma" class="brightness,之内,给了滤镜,触碰之后全体点亮,好看。。 感觉从42行开始不是我这小白能看懂理解的,还是等封包直接用吧。。{:4_173:}
这么复杂的计算,哎,到底是电脑还是人脑。。白老师是真厉害 马黑黑 发表于 2025-9-8 20:28
主要演示:
实现路径上的点击控制音频播放进度
前面那个帖子里还说,控制路径需要增加很多代码,还以为不准备弄了,这里就已经实现了{:4_199:} 这园子太美了,好想有个这样是小花园,晚上去喝喝茶,享受一下它的安宁和轻松{:4_187:} 这心形加别的颜色,也挺漂亮,中间还画了个图形当小播。这构思真棒{:4_187:} 红影 发表于 2025-9-8 22:22
这心形加别的颜色,也挺漂亮,中间还画了个图形当小播。这构思真棒
还好 红影 发表于 2025-9-8 22:18
这园子太美了,好想有个这样是小花园,晚上去喝喝茶,享受一下它的安宁和轻松
想得美 红影 发表于 2025-9-8 22:15
前面那个帖子里还说,控制路径需要增加很多代码,还以为不准备弄了,这里就已经实现了
以前的插件做过的。当然,当时的处理细节与现在这个有所不同但道理差不多 花飞飞 发表于 2025-9-8 21:31
感觉从42行开始不是我这小白能看懂理解的,还是等封包直接用吧。。
这么复杂的计算,哎,到底是 ...
涉及到的知识点已经严重超过大班水平了 花飞飞 发表于 2025-9-8 21:24
21行填充了深红色,用了黄色边缘,那么中间那个风扇叶片形状是画出来的?
这也太厉害了。。
这 ...
啥呀?这是夏花,夏天长得猛烈像扇叶那么夸张了 花飞飞 发表于 2025-9-8 21:21
心形路径做成小播这么漂亮。。。
17行和18行写了两遍,头一遍是心形加了填充色,
第二遍是纯红色外框。 ...
其实啥形都可以哈 花飞飞 发表于 2025-9-8 21:14
这个是静谧夜晚的萤火,看了下是视频效果,搭这样的小花园太漂亮了~~
粒子和视频傻傻分不表。。 ...
据说这个视频是实拍的效果