HTML5 画布绘制点之间的线条距离
HTML5 Canvas draw line distance between points
我正在尝试学习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,这样您就可以更好地看到结果
你有一个坐标系 - 使用勾股定理。
- 铯JS-两点之间的距离
- cloudSearch:范围从0到某个值之间的距离
- 查找图像上两点之间的距离,即使缩放图像也是如此
- 如何使用谷歌地图几何库查找两点之间的距离
- HTML5 画布绘制点之间的线条距离
- javascript中两个位置之间的距离
- 如何使用JavaScript设置内容和页脚之间的距离
- 使用javascript计算两个邮政编码之间的距离
- 只需显示两点之间的距离(KM)
- 计算标记之间的距离
- d3.js中条形图之间的相关距离
- 在强制布局 D3.js 中保持节点之间的动态链接距离
- 如何计算两个纬度和经度之间的距离
- X 轴标签与高图表中的图表之间的距离
- DOM 中两个元素之间的距离(以 px 为单位)
- 删除云中点之间的间隙 - 随着距离的靠近,使它们变大
- 搜索的地址与谷歌地图 api v3 上最近的现有地标之间的距离
- D3 力布局:如何保持节点之间的给定最小距离
- 坐标之间的音差地理位置距离
- 计算两个邮编之间距离的最佳方法(英国)