这种css复杂(且动态)的UI的效果该如何实现?
图一:1、动态时间轴的长短根据起止时间来定的,就是说如果时间更长,结束点有可能继续往下(拐弯)走;2、灰色表示整个轴的长度,渐变(彩)色表示实际进度;3、时间轴上的小圆点也是动态的,表示某一天对应的位置;4、点击时间轴上的白色小圆点,会弹出对应的下拉卡片,卡片有堆叠效果,表示可以继续展开,点击卡片上的蓝色小圆点,则继续展开内容;
图二:1、点击卡片上蓝色小圆点,展示详细内容,时间轴及其他卡片处于高斯模糊状态,以突出当前选中的卡片及其详细内容。
实现要求:图一、图二里面的说明就是UI需要实现的效果,另外就是整个时间轴内容需要可以方法、缩小、拖拽;
思路及想法:昨天研究了一天,发现用常规的 css 技术连 “图一” 的时间轴都无法做到,所以来请教下大家有什么要建议,我的想法有两种:1、通过canvas
技术来实现时间轴(灰色轨迹和渐变色的实际进度)图
,把canvas
图当作背景图片,然后通过绝对定位,把开始
、结束
、每天一天对应的点都打上去,然后放到缩小、拖拽等所有其他逻辑通过css
、js
技术实现;2、整个效果
、交互
都通过canvas
来实现,但是对于canvas美什么经验,不敢轻易使用;
请教下大家有什么好的意见或建议,或者好的canvas操作库等,谢谢!
回复
1个回答

test
2024-06-29
https://jsrun.net/3YJKp/editSVG画起来感觉还好,难到不难,就是比较繁琐。。。 最好找下看有什么第三方库,简化操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.47/vue.global.js"></script>
</head>
<body>
<div id="app">
<svg class="test" width="500" height="300" style="background-color: rgb(232, 234, 238);">
<!-- 渐变色 -->
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style="stop-color:#5897ee;"></stop>
<stop offset="100%" style="stop-color:#eda378;"></stop>
</linearGradient>
</defs>
<!-- 轨道 -->
<path v-for="p in paths" :key="p.index" id="path" d=" M 20 20 L 430 20 C 480 20 480 120 430 120 L 430 120 L 20 120" :stroke="p.hex" :stroke-width="p.index" stroke-linecap="round" stroke-linejoin="round" fill="transparent"></path>
<!-- 进度 -->
<path d=" M 20 20 L 430 20 C 480 20 480 120 430 120 L 430 120 L 200 120" stroke="url(#gradient)" stroke-width="21" stroke-linecap="round" stroke-linejoin="round" fill="transparent"></path>
<!-- 圈 -->
<circle cx="20" cy="170" r="10" fill="#2274fa" />
<circle cx="50" cy="170" r="10" fill="#e78d48" />
<circle cx="80" cy="170" r="6" fill="#fff" />
<path d="M 76 170 H 84" stroke="#2274fa" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" fill="transparent"></path>
<circle cx="100" cy="170" r="6" fill="#fff" />
<path d="M 96 170 H 104" stroke="#2274fa" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" fill="transparent"></path>
<path d="M 100 166 V 174" stroke="#2274fa" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" fill="transparent"></path>
<!-- 文本 -->
<path d="M 120 140 H 250 V 200 H 120 Z" stroke="transparent" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" fill="#fff"></path>
<text x="140" y="160" font-family="Verdana" font-size="12">
<tspan x="140" y="160" fill="red">不支持自动换行</tspan>
<tspan x="140" y="180">这是第二行</tspan>
</text>
</svg>
</div>
<script>
const { createApp } = Vue
var paths = getPaths('#eeeeee', '#aaaaaa', 23)
createApp({
data() {
return {
paths: paths,
message: 'Hello Vue!'
}
}
}).mount('#app')
function getPaths(color1, color2, height) {
var paths = []
var color = {
start: hexToRGB(color1),
end: hexToRGB(color2),
height: height
}
var h = color.height - 1
for (let i = h; i >= 0; i--) {
var c = {
r: color.start.r + (color.end.r - color.start.r) / h * i,
g: color.start.g + (color.end.g - color.start.g) / h * i,
b: color.start.b + (color.end.b - color.start.b) / h * i,
}
paths.push({
index: i,
rgb: `rgb(${c.r}, ${c.g}, ${c.b})`,
hex: rgbToHex(c.r, c.g, c.b)
})
}
console.log(JSON.stringify(paths, null, 2))
return paths
}
function hexToRGB(hex) {
var r = parseInt(hex.slice(1, 3), 16);
var g = parseInt(hex.slice(3, 5), 16);
var b = parseInt(hex.slice(5, 7), 16);
return { r: r, g: g, b: b };
}
function rgbToHex(_r, _g, _b) {
var [r, g, b] = [Math.round(_r), Math.round(_g), Math.round(_b)]
var rHex = r.toString(16);
rHex = rHex.length == 1 ? "0" + rHex : rHex;
var gHex = g.toString(16);
gHex = gHex.length == 1 ? "0" + gHex : gHex;
var bHex = b.toString(16);
bHex = bHex.length == 1 ? "0" + bHex : bHex;
return "#" + rHex + gHex + bHex;
}
</script>
</body>
</html>
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容