Javascript 如何在画布上画六条半径对称的线?

Javascript 如何在画布上画六条半径对称的线?,javascript,math,html5-canvas,Javascript,Math,Html5 Canvas,我正在尝试在画布上构建一个雪花绘图应用程序,非常类似于此: 基本上,如果你画一个点,它应该在画布上以对称的圆形图案重复5次以上。下面是一个例子: 我知道如何告诉画布多次绘制一些东西,但我的数学技能有限,我想知道如何计算复制的5个点相对于原始点的位置 我在想,我必须找到画布的中间,并计算从中间到原始点的x和y位置的距离。在那之后,我假设如果我要从那个点画一个圆,可能我必须找到它的半径,然后。。。这是我的头开始冒烟的时候 我想知道我是否可以做一些类似于他们在这里所做的事情: 仅作为背景,我最初是

我正在尝试在画布上构建一个雪花绘图应用程序,非常类似于此:

基本上,如果你画一个点,它应该在画布上以对称的圆形图案重复5次以上。下面是一个例子:

我知道如何告诉画布多次绘制一些东西,但我的数学技能有限,我想知道如何计算复制的5个点相对于原始点的位置

我在想,我必须找到画布的中间,并计算从中间到原始点的x和y位置的距离。在那之后,我假设如果我要从那个点画一个圆,可能我必须找到它的半径,然后。。。这是我的头开始冒烟的时候

我想知道我是否可以做一些类似于他们在这里所做的事情:

仅作为背景,我最初是从6张剪下来的画布开始的,其中5张是旋转的,并将复制第一张画布,但我意识到这种方法并没有真正起作用,部分原因是画布会稍微重叠(但也存在其他问题)

以下是我目前掌握的代码:

drawing = false;
startX = 0;
startY = 0;
imageData = null;

const canvas = document.getElementById("canvas");

canvas.addEventListener("mousedown", startPosition());
canvas.addEventListener("mouseup", endPosition());
canvas.addEventListener("mousemove", draw());

function startPosition(e) {
  const canvas = this;
  const ctx = canvas.getContext("2d");

  startX = e.clientX;
  startY = e.clientY;
  imageData = ctx.getImageData(0,0,canvas.width,canvas.height);
  drawing = true;
}

function endPosition(e) {
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");

  ctx.lineWidth = 4;
  ctx.lineCap = "round";
  ctx.moveTo(startX, startY);
  ctx.lineTo(e.clientX, e.clientY);
  ctx.strokeStyle = '#ffffff';
  ctx.stroke();
  ctx.beginPath();

  drawing = false;
}
function draw(e) {
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");

  if(!drawing) {
    return;
  }

  ctx.putImageData(imageData, 0, 0);
  ctx.lineWidth = 4;
  ctx.lineCap = "round";
  ctx.moveTo(startX, startY);
  ctx.lineTo(e.clientX, e.clientY);    
  ctx.strokeStyle = '#ffffff';
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(e.clientX, e.clientY);

  //draw line 2
  ctx.moveTo(startX - 50, startY - 50);
  ctx.lineTo(e.clientX - 50, e.clientY - 50);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(e.clientX - 50, e.clientY - 50);

  //draw line 3
  ctx.moveTo(startX - 100, startY - 100);
  ctx.lineTo(e.clientX - 100, e.clientY - 100);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(e.clientX - 100, e.clientY - 100);
}

围绕另一点旋转点的步骤

const center = {x: 100, y: 100};   // Point to rotate around
const point = {x: ?, y: ?};        // Point to rotate
const rotate = (Math.PI * 2) / 5;  // Rotate 1/5th of 360


// Get the vector from center to point
const vx = point.x - center.x;
const vy = point.y - center.y;

// Get the transformation (2D uniform rotate)
const xAx = Math.cos(rotate);
const xAy = Math.sin(rotate); 

// Transform the vector (rotates) and translate back to center
const tx = vx * xAx - vy * xAy + center.x;
const ty = vx * xAy + vy * xAx + center.y;
作为一项功能

function rotate(point, center, rotate, result = {}) {
    const vx = point.x - center.x;
    const vy = point.y - center.y;
    const xAx = Math.cos(rotate);
    const xAy = Math.sin(rotate); 
    result.x = vx * xAx - vy * xAy + center.x;
    result.y = vx * xAy + vy * xAx + center.y;
    return result;
}
使用上述功能从1创建5个点

const slices = 5; // number of rotations
const center = {x: 100, y: 100}; // center point

// Rotates point steps times around center
// Returns array of points
function rotateAll(point, steps, result = []) {
    const ang = Math.PI * 2 / steps;
    result.push(point);                      // Add first point
    for (let rot = 1; rot < steps; rot++) {  // Add remaining points
        result.push(rotate(point, center, rot * ang));
    }
    return result;
}

// Usage
const points = rotateAll({x: 10, y: 20}, slices);
const slices=5;//旋转次数
常数中心={x:100,y:100};//中心点
//围绕中心旋转点步数次
//返回点的数组
函数rotateAll(点、步数、结果=[])){
常数ang=Math.PI*2/步;
result.push(point);//添加第一个点
对于(让rot=1;rot
关于数学:我想你想要12分,而不是6分。看看上面的“尖头”:每个端点有12个“副本”:每个分支的右侧6个,左侧6个。从数学上讲,需要围绕中心旋转60度生成5个点,并使用反射(在链接的雪花中,想象相对于垂直轴的反射,对应于
(x,y)(-x,y))生成其他6个点
transformation。如果你只使用6个旋转版本,你会得到这样的结果。你不希望脚只放在每条腿的一侧。谢谢Andreas!是的,我明白你的意思。我的灵感来自Jaquie Lawson降临节日历中的雪花发生器,其中一个有6个部分,但每个部分在你绘制时都会反射自己,所以你以12结尾。你需要5次旋转,旋转六分之一个圆(
PI/3
),因为有六个副本(但你已经有了原始点)。@AndrasDeak常量
slices
定义了点数。底部片段。顶部片段有
(Math.PI*2)/5;//旋转360度的1/5
这不可能是正确的。我不知道JS(?)但在我看来,
切片
被作为
步骤
传递到
rotateAll
,所以你再次传递
5
,进入
const ang=Math.PI*2/步骤;
。这仍然意味着72度旋转,而不是60度旋转。你需要
步骤
循环的迭代,但
Math.PI*2/(步骤+1)
作为旋转角度。@AndrasDeak第一个值是任意的,可以是任何值。函数
rotateAll
返回一个带有参数
步数
点的数组。如果值
步数
为5,则在圆周围有5个点等距分布,只有最后4个点是旋转的。太棒了,非常感谢@Blindman67!这个真漂亮!