JavaScript中Canvas线条粗细随点距离缩放的函数实现需求
实现Canvas中基于点距离的线条粗细动态调整(纯JavaScript)
要实现「两点距离越近线条越粗,越远线条越细」的效果,只需在计算两点距离后,将距离值反向映射到设定的线条宽度范围内即可。以下是修改后的完整代码,核心改动已标注说明:
修改后的完整代码
CSS部分(无改动)
body { background-color: #000000; } canvas { padding: 0; margin: auto; display: block; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background-color: #111416; border: 10px solid #37c7f7; border-style: double; box-shadow: 0 0 20px 5px #37c7f7; }
HTML&JavaScript部分(核心改动已标注)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <link rel="stylesheet" href="canvas.css"> <canvas id="myCanvas" width="700" height="700"></canvas> <script> var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); var canvW = document.getElementById("myCanvas").width; var canvH = document.getElementById("myCanvas").height; const randomRange = (min, max) => { return Math.random () * (max - min) + min; } const agents = []; class Point { constructor(x, y){ this.x = x; this.y = y; } getDistance(v){ const dx = this.x - v.x; const dy = this.y - v.y; return Math.sqrt(dx*dx + dy*dy); } } class Agent { constructor(x, y){ this.pos = new Point(x, y); this.vel = new Point(randomRange(-0.75, 0.75), randomRange(-0.75, 0.75)); this.radius = randomRange(4, 12); } bounce(canvW, canvH) { if (this.pos.x <= 0 || this.pos.x >= canvW) this.vel.x *= -1; if (this.pos.y <= 0 || this.pos.y >= canvH) this.vel.y *= -1; } update() { this.pos.x += this.vel.x; this.pos.y += this.vel.y; } draw (context) { context.save(); context.translate(this.pos.x, this.pos.y); context.beginPath(); context.arc(0, 0, this.radius, 0, Math.PI * 2); context.lineWidth = 2; context.fillStyle = "#37c7f7"; context.fill(); context.stroke(); context.restore(); } } // 新增:单独提取线条绘制逻辑,避免重复绘制 const drawConnections = (context, agents) => { const maxDistance = 200; // 原代码中不绘制线条的阈值 const maxLineWidth = 5; // 线条最大宽度(两点重合时) const minLineWidth = 0.5; // 线条最小宽度(距离为maxDistance时) for (let i = 0; i < agents.length; i++){ const agent = agents[i]; for(let j = i +1; j < agents.length; j++){ const other = agents[j]; const dist = agent.pos.getDistance(other.pos); if (dist > maxDistance) continue; // 核心计算:反向映射距离到线条宽度 const lineWidth = ((maxDistance - dist) / maxDistance) * (maxLineWidth - minLineWidth) + minLineWidth; context.beginPath(); context.moveTo(agent.pos.x, agent.pos.y); context.lineTo(other.pos.x, other.pos.y); context.strokeStyle = "#37c7f7"; context.lineWidth = lineWidth; // 设置动态线条宽度 context.stroke(); } } } for (let i =0; i<40; i++){ const x = randomRange(0, canvW); const y = randomRange(0, canvH); agents.push(new Agent (x, y)); } const animate = () => { context.save(); context.fillStyle = "#111416"; context.fillRect(0, 0, canvW, canvH); context.restore(); // 先绘制所有点,再绘制连接线条 agents.forEach(agent => { agent.draw(context); agent.update(); agent.bounce(canvW, canvH); }); drawConnections(context, agents); requestAnimationFrame(animate); } animate(); </script> </body> </html>
关键逻辑说明
- 反向映射计算:通过公式
((maxDistance - dist) / maxDistance) * (maxLineWidth - minLineWidth) + minLineWidth将距离值转换为线条宽度。当dist=0时,线条宽度为maxLineWidth;当dist=maxDistance时,宽度为minLineWidth,中间值线性过渡。 - 优化绘制逻辑:将线条绘制从
Agent.draw方法中提取出来,避免每个Agent都重复绘制所有线条对,提升性能。 - 参数可调整:你可以根据需求修改
maxDistance、maxLineWidth、minLineWidth这三个参数,调整线条的显示效果。
内容的提问来源于stack exchange,提问作者J.A.C.K.
相关产品推荐
相关产品推荐

