HTML5 画布绘制点之间的线条距离

HTML5 Canvas draw line distance between points

本文关键字:之间 距离 布绘制 绘制 HTML5      更新时间:2023-09-26

我正在尝试学习HTML5,并找到了一个非常简单的粒子系统,我稍微修改了一下。我想在粒子之间创建一条线,如果粒子之间的距离在 0-20 范围内。

我目前拥有的在每个粒子之间画一条线,无论距离多远。

这是我尝试检查距离的地方,但我不知道该怎么做。将不胜感激任何帮助和解释。提前谢谢。

           // This particle
            var p = particles[t];
            // Check position distance to other particles
            for (var q = 0; q < particles.length; q++) {
                if (particles[q].x - p.x < line_distance || p.x - particles[q].x < line_distance) {
                    ctx.beginPath();
                    ctx.lineWidth = .1;
                    ctx.strokeStyle = '#fff';
                    ctx.moveTo(p.x, p.y);
                    ctx.lineTo(particles[q].x, particles[q].y);
                    ctx.stroke();
                }
            }

// Request animation frame
var requestAnimationFrame = window.requestAnimationFrame || 
    window.mozRequestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.msRequestAnimationFrame;
// Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Set fullscreen
canvas.width = document.documentElement.clientWidth;
canvas.height = document.documentElement.clientHeight;
// Options
var num =30;            // Number of particles to draw
var size = 3;           // Particle size
var color = '#fff';     // Particle color
var min_speed = 1;      // Particle min speed
var max_speed = 3;      // Particle max speed
var line_distance = 20; // This is the max distance between two particles
// if we want to draw a line between them
// Particles array
var particles = [];
for (var i = 0; i < num; i++) {
  particles.push(
    new create_particle()
  );
}
// Lets animate the particle
function draw() {
  // Background
  ctx.fillStyle = "#000";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  // Lets draw particles from the array now
  for (var t = 0; t < particles.length; t++) {
    // This particle
    var p = particles[t];
    for (var q = 0; q < particles.length; q++) {
      // Check position distance
      if (particles[q].x - p.x < line_distance || p.x - particles[q].x < line_distance) {
        ctx.beginPath();
        ctx.lineWidth = .1;
        ctx.strokeStyle = '#fff';
        ctx.moveTo(p.x, p.y);
        ctx.lineTo(particles[q].x, particles[q].y);
        ctx.stroke();
      }
    }
    // Color
    ctx.fillStyle = color;
    // Circle path
    ctx.beginPath();
    ctx.arc(p.x, p.y, p.radius, Math.PI * 2, false);
    ctx.fill();
    // Lets use the velocity now
    p.x += p.vx;
    p.y += p.vy;
    // If there is only 1 particle
    // show X, Y, and velocity
    if (num === 1) {
      ctx.fillText('Y:'+ p.y, 20, 20);
      ctx.fillText('X:'+ p.x, 20, 40);
      ctx.fillText('YV:'+ p.vy, 20, 60);
      ctx.fillText('XV:'+ p.vx, 20, 80);
    }
    // To prevent the balls from moving out of the canvas
    if (p.x < size) p.vx*= (p.vx / -p.vx);
    if (p.y < size) p.vy*= (p.vy / -p.vy);
    if (p.x > canvas.width - size) p.vx*= (-p.vx / p.vx);
    if (p.y > canvas.height - size) p.vy*= (-p.vy / p.vy);
  }
  // Loop
  requestAnimationFrame(draw);
}
// Function for particle creation
function create_particle() {
  // Random position
  this.x = Math.random() * canvas.width;
  this.y = Math.random() * canvas.height;
  // Velocity
  this.vx = random_int_between(min_speed, max_speed);
  this.vy = random_int_between(min_speed, max_speed);
  // Color & Size
  this.color = color;
  this.radius = size;
}
// Random number between (used for speed)
function random_int_between(min, max) {
  return Math.floor(Math.random() * max) + min;
}
draw();
<canvas id="canvas"></canvas>

N 体 粒子系统

由于这是一个 N 体案例,没有人谈论 CPU 负载。

中央处理器负载

粒子系统可能会在处理过载中迅速使CPU陷入困境。当您针对每个粒子测试另一个粒子时尤其如此。由于粒子系统几乎总是用于实时图形,无效的编码会破坏整个动画。

不做任何不需要的事情

首先,由于您只是在寻找阈值距离,因此您可以通过在知道测试失败后立即不继续计算来优化计算。

所以设置阈值距离

var dist = 20;
var distSq = dist * dist; // No need to square this inside loops

然后在循环中计算测试并继续。假设 p1 和 p2 是粒子

x = p2.x-p1.x;  // do x first
if((x *= x) < distSq){ // does it pass?? if not you have saved calculating y
    y = p2.y-p1.y; // now do y as you know x is within distance
    if(x + (y * y) < distSq){ // now you know you are within 20
         // draw the line

假设只有 1/6 会通过,1/3 接近,您可以节省一半以上的 CPU 负载。您还会注意到,我不使用 CPU 繁重的 sqrt 的距离。没有必要,因为数字和数字的平方之间存在一对一的匹配。如果一个数字的平方根小于距离,那么数字的平方也会小于距离的平方。

N 体平方

永远不要像这样做一个带有两个 for 循环的 N 体模拟游戏。

for(i = 0; i < particles.length; i ++){
    for(j = 0; j < particles.length; j ++){
       // you will test all i for j and all j for i but half of them are identical
       // and the square root of the number are self to self

光是看着就让我很伤心,因为解决方案是如此简单。

假设您有 100 个粒子,每秒 60

帧,您每秒对 100 个粒子进行 60 * 100 * 100 次比较 (600,000(。这完全是浪费 CPU 时间。

永远不要做两次,或者你知道答案。

改进for循环并避免测试您已经知道的距离并测试每个粒子与自身的距离

var len =  particles.length;  // move the length out as it can be expensive
                              // and pointless as the value does not change;
for(i = 0; i < len; i ++){
    for(j = i + 1; j < len; j ++){
       // Now you only test each particle against each other once rather than twice

因此,只需几个简单的字符(for(j = 0变得for(j = i + 1(,您的CPU负载就会减少一半以上,从600,000次比较减少到不到300,000

人眼容易上当

愚弄眼睛是从动画中获得额外性能的最佳方式。

这是一种视觉效果,人眼看不到像素,也不会以每秒 1/60 的速度看到单个帧,但它确实看到了帧速率的下降。创建一个复杂的粒子系统可以带来出色的效果,但如果它降低了帧速率,好处就会丧失。利用像素很小的事实,1/20秒远远超出了人类发现错误的能力,这是优化FX和为每个CPU时钟周期添加更多爆炸的最佳方法。

下面的演示有两个粒子模拟。 每个100分。任何在 49 像素范围内的点之间都会画一条线。一个人做我上面展示的所有东西,牺牲了一点记忆和很多敏锐度,每帧只计算点的 1/3 之间的距离。由于最大速度可能接近一帧线长度的一半,跳过 2 帧会使一条线长两倍或两点在没有线的情况下太近。这样做可以节省大量的CPU,但您无法选择哪个是哪个。

单击您认为跳过点的SIM卡,找出哪个是哪个。

var canvas = document.createElement("canvas"); 
canvas.width= 540;
canvas.height = 270; 
var ctx = canvas.getContext("2d"); 
document.body.appendChild(canvas);
mouseX = 0;
mouseB = false;
function clickedFun(event){
  mouseX = event.clientX
  mouseB = true;
}
  
canvas.addEventListener("click",clickedFun);
var w = 250;
var h = 250;
var wh = w/2;
var hh = h/2;
var speedMax = 5;
var partSize = 2;
var count = 100
var grav = 1;
var pA1 = [];  // particle arrays
var pA2 = [];
var PI2 = Math.PI * 2;
// populate particle arrays
for(var i = 0; i < count; i += 1){
    // dumb list
    pA1.push({
       x : Math.random() * w,
       y : Math.random() * h,
       dx : (Math.random() -0.5)*speedMax,
       dy : (Math.random() -0.5)*speedMax,
       
    })      
    // smart list
    pA2.push({
       x : Math.random() * w,
       y : Math.random() * h,
       dx : (Math.random() -0.5)*speedMax,
       dy : (Math.random() -0.5)*speedMax,
       links : [], // add some memory
    })  
    for(var j = 0; j < count; j += 1){
        pA2[i].links[i] = false; // set memory to no links
    }
}
// move and draw the dots. Just a simple gravity sim
function drawAll(parts){
    var x,y,d;
    var i = 0;
    var len = parts.length;
    var p;
    ctx.beginPath();
    for(;i < len; i++){
        p = parts[i];
        x = wh-p.x;
        y = hh-p.y;
        d = x*x + y*y;
        x *= grav / d;
        y *= grav / d;
        p.dx += x;
        p.dy += y;
        p.x += p.dx;
        p.y += p.dy;
        if(p.x <= 0){
            p.dx -= p.dx/2;
            p.x = 1;
        }else
        if(p.x >= w){
            p.dx -= p.dx/2;
            p.x = w-1;
        }
        if(p.y <= 0){
            p.dy -= p.dy/2;
            p.y = 1;
        }else
        if(p.y >= h){
            p.dy -= p.dy/2;
            p.y = w-1;
        }
        ctx.moveTo(p.x+partSize,p.y)
        ctx.arc(p.x,p.y,partSize,0,PI2)
    }
    ctx.fill();
}
//Old style line test. If two particles are less than dist apart
// draw a line between them
function linesBetween(parts,dist){
    var distSq = dist*dist;
    var x,y,d,j;
    var i = 0;
    var len = parts.length;
    var p,p1;
    ctx.beginPath();
    for(; i < len; i ++){
        p = parts[i];
        for(j = i + 1; j < len; j ++){
            p1 = parts[j];
            x = p1.x-p.x;
            if((x *= x) < distSq){
                y = p1.y-p.y;
                if(x + (y*y) < distSq){
                    ctx.moveTo(p.x,p.y);
                    ctx.lineTo(p1.x,p1.y)
                }
            }
        }
        
    }
    ctx.stroke();
}
var counter = 0;// counter for multyplexing
// Fast version. As the eye can not posible see the differance of 
// of 4 pixels over 1/30th of a second only caculate evey third
// particls
function linesBetweenFast(parts,dist){
    var distSq = dist*dist;
    var x,y,d,j,l;
    var i = 0;
    counter += 1;
    var cc = counter % 3;
    var wr,re;
    var len = parts.length;
    var p,p1;
    var lineSet
    ctx.beginPath();
    for(; i < len; i ++){
        p = parts[i];
        l = p.links;
        for(j = i + 1; j < len; j += 1){
            p1 = parts[j];
            if((j + cc)%3 === 0){ // only every third particle
                lineSet = false;  // test for diferance default to fail
                x = p1.x-p.x;     
                if((x *= x) < distSq){
                    y = p1.y-p.y;
                    if(x + (y*y) < distSq){
                        lineSet = true;  // yes this needs a line
                    }
                }
                l[j] = lineSet; // flag it as needing a line
            }
            if(l[j]){ // draw the line if needed
                ctx.moveTo(p.x,p.y);
                ctx.lineTo(p1.x,p1.y);
            }
        }
    }
    ctx.stroke();
}
var drawLines; // to hold the function that draws lines
// set where the screens are drawn
var left = 10;
var right = 10 * 2 + w;
// Now to not cheat swap half the time
if(Math.random() < 0.5){
    right = 10;
    left = 10 * 2 + w;
}
  
// draws a screem
var doScreen = function(parts){
    ctx.fillStyle = "red"
    drawAll(parts);
    ctx.strokeStyle = "black";
    ctx.lineWidth = 1;
    drawLines(parts,49);
}
var guess = ""
var guessPos;
var gueesCol;
ctx.font = "40px Arial Black";
ctx.textAlign = "center";
ctx.textBasline = "middle"
var timer = 0;
function update(){
    ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0,0,canvas.width,canvas.height);
    ctx.setTransform(1,0,0,1,left,10);
    ctx.strokeStyle = "red";
    ctx.lineWidth = 4;
    ctx.strokeRect(0,0,w,h);
    drawLines = linesBetween;
    doScreen(pA1)
    ctx.setTransform(1,0,0,1,right,10);
    ctx.strokeStyle = "red";
    ctx.lineWidth = 4;
    ctx.strokeRect(0,0,w,h);
    drawLines = linesBetweenFast
    doScreen(pA2)  
  
  
  
  
    if(mouseB){
      if((mouseX > 270 && right >250) ||
          (mouseX < 250 && right < 250)){
        guess = "CORRECT!"
        guessPos = right;
        guessCol = "Green";
      }else{
        guess = "WRONG"
        guessPos = left
        guessCol = "Red";
      }
      timer = 120;
      mouseB = false;
    }else
    if(timer > 0){
      timer -= 1;
      if(timer > 30){
        ctx.setTransform(1,0,0,1,guessPos,10);
        ctx.font = "40px Arial Black";
        ctx.fillStyle = guessCol;
        ctx.fillText(guess,w/2,h/2);
      }else{
        if(Math.random() < 0.5){
          right = 10;
          left = 10 * 2 + w;
        }else{
          left = 10;
          right = 10 * 2 + w;
        }          
      }
      
    }else{
      ctx.setTransform(1,0,0,1,0,0);
      ctx.font = "16px Arial Black";
      var tw = ctx.measureText("Click which sim skips 2/3rd of").width +30;
      
      ctx.beginPath();
      ctx.fillStyle = "#DDD";
      ctx.strokeStyle = "Red";
      ctx.rect(270-tw/2,-5,tw,40);
      ctx.stroke();
      ctx.fill();
      ctx.fillStyle = "blue";
      ctx.fillText("Click which sim skips 2/3rd of",270,15) ;
      ctx.fillText("particle tests every frame",270,30) ;
    }
    requestAnimationFrame(update);
}
update();

这只是你的测试是错误的。

A-B

// Request animation frame
		var requestAnimationFrame = window.requestAnimationFrame || 
		window.mozRequestAnimationFrame || 
		window.webkitRequestAnimationFrame || 
		window.msRequestAnimationFrame;
    
		// Canvas
		var canvas = document.getElementById('canvas');
		var ctx = canvas.getContext('2d');
		
		// Set fullscreen
		canvas.width = document.documentElement.clientWidth;
		canvas.height = document.documentElement.clientHeight;
		// Options
		var num =30;            // Number of particles to draw
		var size = 3;           // Particle size
		var color = '#fff';     // Particle color
		var min_speed = 1;      // Particle min speed
		var max_speed = 3;      // Particle max speed
		var line_distance = 20; // This is the max distance between two particles
		                        // if we want to draw a line between them
		// Particles array
		var particles = [];
		for (var i = 0; i < num; i++) {
			particles.push(
				new create_particle()
			);
		}
		// Lets animate the particle
		function draw() {
			// Background
			ctx.fillStyle = "#000";
			ctx.fillRect(0, 0, canvas.width, canvas.height);
			
			// Lets draw particles from the array now
			for (var t = 0; t < particles.length; t++) {
		  
				// This particle
				var p = particles[t];
				
				for (var q = 0; q < particles.length; q++) {
					// Check position distance
					if (Math.abs(particles[q].x - p.x) < line_distance) {
						ctx.beginPath();
						ctx.lineWidth = .1;
						ctx.strokeStyle = '#fff';
						ctx.moveTo(p.x, p.y);
						ctx.lineTo(particles[q].x, particles[q].y);
						ctx.stroke();
					}
				
				}
				
				// Color
				ctx.fillStyle = color;
				// Circle path
				ctx.beginPath();
				ctx.arc(p.x, p.y, p.radius, Math.PI * 2, false);
				ctx.fill();
				
				// Lets use the velocity now
				p.x += p.vx;
				p.y += p.vy;
				// If there is only 1 particle
				// show X, Y, and velocity
				if (num === 1) {
					ctx.fillText('Y:'+ p.y, 20, 20);
					ctx.fillText('X:'+ p.x, 20, 40);
					ctx.fillText('YV:'+ p.vy, 20, 60);
					ctx.fillText('XV:'+ p.vx, 20, 80);
				}
				// To prevent the balls from moving out of the canvas
				if (p.x < size) p.vx*= (p.vx / -p.vx);
				if (p.y < size) p.vy*= (p.vy / -p.vy);
				if (p.x > canvas.width - size) p.vx*= (-p.vx / p.vx);
				if (p.y > canvas.height - size) p.vy*= (-p.vy / p.vy);
			}
		  
		  // Loop
		  requestAnimationFrame(draw);
		  
		}
		
		// Function for particle creation
		function create_particle() {
			// Random position
			this.x = Math.random() * canvas.width;
			this.y = Math.random() * canvas.height;
			
			// Velocity
			this.vx = random_int_between(min_speed, max_speed);
			this.vy = random_int_between(min_speed, max_speed);
			
			// Color & Size
			this.color = color;
			this.radius = size;
		  
		}
		// Random number between (used for speed)
		function random_int_between(min, max) {
			return Math.floor(Math.random() * (max-min)) + min;
		}
		draw();
<canvas id="canvas" width="300" height="300"></canvas>

// Request animation frame
		var requestAnimationFrame = window.requestAnimationFrame || 
		window.mozRequestAnimationFrame || 
		window.webkitRequestAnimationFrame || 
		window.msRequestAnimationFrame;
    
		// Canvas
		var canvas = document.getElementById('canvas');
		var ctx = canvas.getContext('2d');
		
		// Set fullscreen
		canvas.width = document.documentElement.clientWidth;
		canvas.height = document.documentElement.clientHeight;
		// Options
		var num =30;            // Number of particles to draw
		var size = 3;           // Particle size
		var color = '#fff';     // Particle color
		var min_speed = 1;      // Particle min speed
		var max_speed = 3;      // Particle max speed
		var line_distance = 20; // This is the max distance between two particles
		                        // if we want to draw a line between them
		// Particles array
		var particles = [];
		for (var i = 0; i < num; i++) {
			particles.push(
				new create_particle()
			);
		}
		// Lets animate the particle
		function draw() {
			// Background
			ctx.fillStyle = "#000";
			ctx.fillRect(0, 0, canvas.width, canvas.height);
			
			// Lets draw particles from the array now
			for (var t = 0; t < particles.length; t++) {
		  
				// This particle
				var p = particles[t];
				
				for (var q = 0; q < particles.length; q++) {
					// Check position distance
					if (particles[q].x - p.x < line_distance || p.x - particles[q].x < line_distance) {
						ctx.beginPath();
						ctx.lineWidth = .1;
						ctx.strokeStyle = '#fff';
						ctx.moveTo(p.x, p.y);
						ctx.lineTo(particles[q].x, particles[q].y);
						ctx.stroke();
					}
				
				}
				
				// Color
				ctx.fillStyle = color;
				// Circle path
				ctx.beginPath();
				ctx.arc(p.x, p.y, p.radius, Math.PI * 2, false);
				ctx.fill();
				
				// Lets use the velocity now
				p.x += p.vx;
				p.y += p.vy;
				// If there is only 1 particle
				// show X, Y, and velocity
				if (num === 1) {
					ctx.fillText('Y:'+ p.y, 20, 20);
					ctx.fillText('X:'+ p.x, 20, 40);
					ctx.fillText('YV:'+ p.vy, 20, 60);
					ctx.fillText('XV:'+ p.vx, 20, 80);
				}
				// To prevent the balls from moving out of the canvas
				if (p.x < size) p.vx*= (p.vx / -p.vx);
				if (p.y < size) p.vy*= (p.vy / -p.vy);
				if (p.x > canvas.width - size) p.vx*= (-p.vx / p.vx);
				if (p.y > canvas.height - size) p.vy*= (-p.vy / p.vy);
			}
		  
		  // Loop
		  requestAnimationFrame(draw);
		  
		}
		
		// Function for particle creation
		function create_particle() {
			// Random position
			this.x = Math.random() * canvas.width;
			this.y = Math.random() * canvas.height;
			
			// Velocity
			this.vx = random_int_between(min_speed, max_speed);
			this.vy = random_int_between(min_speed, max_speed);
			
			// Color & Size
			this.color = color;
			this.radius = size;
		  
		}
		// Random number between (used for speed)
		function random_int_between(min, max) {
			return Math.floor(Math.random() * max) + min;
		}
		draw();
<canvas id="canvas"></canvas>

要计算两点之间的距离,应该使用勾股定理:

length = sqrt(a² + b²)

其中 a 是一侧的长度,b 是另一侧的长度。

var a = (x2 - x1);
var b = (y2 - y1);
var sum = (a * a) + (b * b);
var length = Math.sqrt(sum);

这可以变成一个函数,因为你知道你会有有x和y的粒子。

function calcLength(particle1, particle2) {
  var xDiff = particle2.x - particle1.x;
  var yDiff = particle2.y - particle1.y;
  var sum = (xDiff * xDiff) + (yDiff * yDiff);
  return Math.sqrt(sum);
}

然后,您可以在代码中使用该函数:

for (var t = 0; t < particles.length; t++) {
  var p = particles[t];
    for (var q = 0; q < particles.length; q++) {
      var p2 = particles[q];
      if (calcLength(p, p2) < 20) {
        // draw a line between the particles
      }
    }
 }

要计算两点之间的距离,请使用勾股定理。 http://www.purplemath.com/modules/distform.htm

// Request animation frame
		var requestAnimationFrame = window.requestAnimationFrame || 
		window.mozRequestAnimationFrame || 
		window.webkitRequestAnimationFrame || 
		window.msRequestAnimationFrame;
    
		// Canvas
		var canvas = document.getElementById('canvas');
		var ctx = canvas.getContext('2d');
		
		// Set fullscreen
		canvas.width = document.documentElement.clientWidth;
		canvas.height = document.documentElement.clientHeight;
		// Options
		var num =30;            // Number of particles to draw
		var size = 3;           // Particle size
		var color = '#fff';     // Particle color
		var min_speed = 1;      // Particle min speed
		var max_speed = 3;      // Particle max speed
		var line_distance = 20; // This is the max distance between two particles
		                        // if we want to draw a line between them
		// Particles array
		var particles = [];
		for (var i = 0; i < num; i++) {
			particles.push(
				new create_particle()
			);
		}
		// Lets animate the particle
		function draw() {
			// Background
			ctx.fillStyle = "#000";
			ctx.fillRect(0, 0, canvas.width, canvas.height);
			
			// Lets draw particles from the array now
			for (var t = 0; t < particles.length; t++) {
		  
				// This particle
				var p = particles[t];
				
				for (var q = 0; q < particles.length; q++) {
					// Check position distance
					if (distance(particles[q], p) < line_distance) {
						ctx.beginPath();
						ctx.lineWidth = 1;
						ctx.strokeStyle = '#fff';
						ctx.moveTo(p.x, p.y);
						ctx.lineTo(particles[q].x, particles[q].y);
						ctx.stroke();
					}
				
				}
				
				// Color
				ctx.fillStyle = color;
				// Circle path
				ctx.beginPath();
				ctx.arc(p.x, p.y, p.radius, Math.PI * 2, false);
				ctx.fill();
				
				// Lets use the velocity now
				p.x += p.vx;
				p.y += p.vy;
				// If there is only 1 particle
				// show X, Y, and velocity
				if (num === 1) {
					ctx.fillText('Y:'+ p.y, 20, 20);
					ctx.fillText('X:'+ p.x, 20, 40);
					ctx.fillText('YV:'+ p.vy, 20, 60);
					ctx.fillText('XV:'+ p.vx, 20, 80);
				}
				// To prevent the balls from moving out of the canvas
				if (p.x < size) p.vx*= (p.vx / -p.vx);
				if (p.y < size) p.vy*= (p.vy / -p.vy);
				if (p.x > canvas.width - size) p.vx*= (-p.vx / p.vx);
				if (p.y > canvas.height - size) p.vy*= (-p.vy / p.vy);
			}
		  
		  // Loop
		  requestAnimationFrame(draw);
		  
		}
		
		// Function for particle creation
		function create_particle() {
			// Random position
			this.x = Math.random() * canvas.width;
			this.y = Math.random() * canvas.height;
			
			// Velocity
			this.vx = random_int_between(min_speed, max_speed);
			this.vy = random_int_between(min_speed, max_speed);
			
			// Color & Size
			this.color = color;
			this.radius = size;
		  
		}
		// Random number between (used for speed)
		function random_int_between(min, max) {
			return Math.floor(Math.random() * max) + min;
		}
		draw();
function distance(pointA, pointB){
  var dx = pointB.x - pointA.x;
  var dy = pointB.y - pointA.y;
  return Math.sqrt(dx*dx + dy*dy);
}
<canvas id="canvas"></canvas>

请注意,我将 lineWidth 增加到 1,这样您就可以更好地看到结果

你有一个坐标系 - 使用勾股定理。