HTML Canvas可拖拽圆形容器滚动条无法实时同步的解决方法
解决Canvas圆形容器滚动条实时同步问题
问题原因
你当前代码中计算圆弧滚动进度的逻辑错误,直接使用container.scrollTop来计算弧度,没有基于滚动比例(已滚动距离/总可滚动距离),导致圆弧无法准确反映实际滚动进度。
修复方案
- 利用已计算好的
scrollPer(范围01)映射圆弧的弧度(02π) - 调整圆弧起始角度为
-Math.PI/2(对应圆形顶部),让滚动条视觉表现更符合用户直觉 - 确保每次滚动时,圆弧绘制完全基于当前滚动比例,而非原始
scrollTop值
修改后的完整代码
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>圆形滚动容器</title> </head> <body> <h1>Hi</h1> <section class="scrollbar" id="container"> <main> <div class="item"> <p>hola</p> </div> <div class="item"> <p>hola</p> </div> <div class="item"> <p>hola</p> </div> <div class="item"> <p>hola</p> </div> <div class="item"> <p>hola</p> </div> </main> <canvas width="100" height="100" class="canvas" id="canvas"></canvas> </section> </body> </html>
CSS
:root{ --item-size: 40dvw; } *{ box-sizing: content-box; } html { scrollbar-width:none; -ms-overflow-style:none; overflow-y:-moz-scrollbars-none } .hide-scrollbar::-webkit-scrollbar { width:0; display: none } body{ display: flex; flex-wrap: wrap; flex-direction: column; align-content: center; justify-content: center; align-items: center; height: 100vh; margin: 0; background-color: rgba(185, 212, 235, 0.698); } section{ border-radius: 50%; width: calc(var(--item-size) + 5.9px); height: calc(var(--item-size) + 5.9px); gap: 2px; position: relative; overflow: hidden; } main{ display: grid; grid-auto-flow: row; width: 100%; height: 100%; gap: 2px; overflow: scroll; scrollbar-width: none; scroll-snap-type: y mandatory; scroll-behavior: smooth; position: relative; box-sizing: border-box; } main>.item{ background-color: aliceblue; border: 3px dashed black; border-radius: 50%; aspect-ratio: 1; width: 100%; box-sizing: border-box; display: flex; align-content: center; justify-content: center; scroll-snap-align: start; } .canvas{ position: absolute; right: 0px; top: 0px; border-radius: 50%; pointer-events: none; }
JavaScript
const canvas = document.getElementById('canvas'); const container = document.getElementById('container'); const ctx = canvas.getContext('2d'); const resizeCanvas = () => { canvas.height = container.clientHeight; canvas.width = container.clientHeight; } let containerHeight, containerScrollHeight, scrolled, scrollPer; const render = () => { containerHeight = container.offsetHeight; containerScrollHeight = container.scrollHeight; scrolled = container.scrollTop; // 计算滚动比例:0(顶部)到1(底部) scrollPer = scrolled / (containerScrollHeight - containerHeight); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.lineWidth = 5; // 绘制灰色背景圆弧 makeArc('#666666', canvas.width / 2, canvas.height / 2, canvas.height / 2.05, 0, 2 * Math.PI); // 绘制黑色进度圆弧:从顶部(-π/2)开始,根据滚动比例计算结束角度 const startAngle = -Math.PI / 2; const endAngle = startAngle + scrollPer * 2 * Math.PI; makeArc('#000000', canvas.width / 2, canvas.height / 2, canvas.height / 2.05, startAngle, endAngle); }; const makeArc = (color, x, y, radius, startAngle, endAngle) => { ctx.beginPath(); ctx.strokeStyle = color; ctx.arc(x, y, radius, startAngle, endAngle); ctx.stroke(); }; resizeCanvas(); render(); window.addEventListener('resize', () => { resizeCanvas(); render(); }); container.addEventListener('scroll', render);
关键修改点
- 用
scrollPer * 2 * Math.PI计算进度圆弧的结束角度,确保滚动比例与圆弧进度完全同步 - 将圆弧起始角度设为
-Math.PI/2,对应圆形顶部,符合用户对滚动条的视觉预期 - 优化
makeArc函数参数命名,提升代码可读性 - 调整CSS中
scroll-behavior为smooth,优化滚动体验
内容的提问来源于stack exchange,提问作者polluelo_js
相关产品推荐
相关产品推荐

