You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

关键逻辑说明

  1. 反向映射计算:通过公式 ((maxDistance - dist) / maxDistance) * (maxLineWidth - minLineWidth) + minLineWidth 将距离值转换为线条宽度。当dist=0时,线条宽度为maxLineWidth;当dist=maxDistance时,宽度为minLineWidth,中间值线性过渡。
  2. 优化绘制逻辑:将线条绘制从Agent.draw方法中提取出来,避免每个Agent都重复绘制所有线条对,提升性能。
  3. 参数可调整:你可以根据需求修改maxDistance、maxLineWidth、minLineWidth这三个参数,调整线条的显示效果。

内容的提问来源于stack exchange,提问作者J.A.C.K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 09:25:41