【问题标题】:how i get a coordinate of each rectangle?我如何获得每个矩形的坐标?
【发布时间】:2018-06-21 06:47:37
【问题描述】:

这个我试过了,

  public drawNumbers(ctx, x1, y1, length, count) {
      let angle = 0;
      for (let i = 0; i <= count; i++ ) {
        angle += 2 * Math.PI / (count );
      const x2 = x1 + length * Math.cos(angle),
        y2 = y1 + length * Math.sin(angle);
       ctx.beginPath();
       ctx.fillRect(x2, y2, 10, 20);
       ctx.stroke();

    }
  }

    this.canvas.drawNumbers(ctx, this.midX, this.midY, 160, 60);

输出:

预期结果:

我想计算一个四坐标(矩形)的旋转轴。

如何检测每个矩形的点击事件?

【问题讨论】:

  • 最简单的角度转换方法-初始化let angle = - Math.Pi / 2
  • 你能澄清一下想要什么吗?您似乎在标题和问题正文中提出了不同的问题。
  • @Salixalba 我已经更新了问题

标签: javascript math canvas html5-canvas geometry


【解决方案1】:

要获得旋转的矩形,您需要使用图形上下文的transform() 方法。

想象一下绘图区域左上角的一组轴。任何绘图都将相对于我们可以通过变换移动的这些轴完成。

通过xshift,yshift翻译

ctx.transform(1,0,0,1, xshift,  yshift);
ctx.fillRect(0,0,100,100);    

以弧度为单位旋转角度 ang

ctx.transform(Math.cos(ang),Math.sin(ang),
              -Math.sin(ang),Math.cos(ang),  0,0);

我们可以将事物与三个转换结合起来。第一个将原点移动到圆的中心。然后围绕这个点旋转轴, 然后将轴移动到您希望形状出现的位置。最后,绘制形状。

for(deg = 0; deg < 360; deg+=20) {
    ctx.setTransform(1,0,0,1,0,0); // reset transformation
    ang = deg * Math.PI/180;
    ctx.transform(1,0,0,1,100,100); // shift origin
    ctx.transform(Math.cos(ang),Math.sin(ang),
                 -Math.sin(ang),Math.cos(ang),  0,0);
    ctx.transform(1,0,0,1,50,0);
    ctx.fillRect(0,0,30,10);
}

您可以使用translaterotate 实现相同的目的

for(deg = 0; deg < 360; deg+=20) {
    ctx.setTransform(1,0,0,1,0,0); // reset transformation
    ang = deg * Math.PI/180;
    ctx.translate(100,100); // shift origin
    ctx.rotate(ang);
    ctx.translate(50,0);
    ctx.fillRect(0,0,30,10);
}

【讨论】:

    【解决方案2】:

    使用 setTransform

    Salix alba 答案是一个解决方案,虽然步骤太多。

    可以使用setTransform 在单个变换中完成,并在一个步骤中应用平移和旋转。此外,第二个平移是相对于其原点绘制框的位置。使用变换时,始终围绕旋转中心绘制对象。

     ctx.strokeRect(-10,-10,20,20); // rotation is always around 0,0
    

    const ctx = canvas.getContext("2d");
    const centerX = 250;
    const centerY = 250;
    const radius = 200;
    const boxWidth = 10;
    const bobLength = 20;
    
    // draw boxs around circle center at cx,cy and radius rad
    // box width bw, and box height bh
    // spacing optional is the distance between boxes
    function drawCircleOfBoxes(cx,cy,rad,bw,bh,spacing = 5){
      var steps = ((rad - bw /2) * Math.PI * 2) / (bw + spacing) | 0; // get number boxes that will fit circle
      ctx.beginPath();
      for(var i = 0; i < steps; i ++){
          const ang = (i / steps) * Math.PI * 2;
          var xAxisX = Math.cos(ang);  // get the direction of he xAxis
          var xAxisY = Math.sin(ang);
          // set the transform to circle center x Axis out towards box
          // y axis at 90 deg to x axis
          ctx.setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, cx, cy);
          // draw box offset from the center so its center is distance radius
          ctx.rect(rad - bh / 2, -bw / 2, bh, bw);
      }
      ctx.fill(); 
      ctx.stroke();
      ctx.setTransform(1,0,0,1,0,0); // reset transform
    }
    
    ctx.fillStyle = "#FCD";
    ctx.strokeStyle = "#000";
    drawCircleOfBoxes(centerX, centerY, radius, boxWidth, bobLength);
    &lt;canvas id="canvas" width="500" height="500"&gt;&lt;/canvas&gt;

    手动将变换应用到一个点

    如果您希望在代码中转换框,您可以使用上面应用的转换并将其直接应用于一组点。您不能将其应用于需要 API 转换的 ctx.rect 函数。

    要转换一个点px,py,您需要旋转x轴的方向

    const xAx = Math.cos(dirOfXAxis);
    const xAy = Math.sin(dirOfXAxis);
    

    然后您可以沿 x 轴移动点 px 距离,然后转动 90 度并沿 y 轴移动 py 距离

    var x = px * xAx;  // move px dist along x axis
    var y = px * xAy;
    
    x += py * -xAy;  // move px dist along y axis
    y += py * xAx;
    

    然后添加翻译

    x += translateX;
    y += translateY;
    

    或者一次性完成

    var x = px * xAx - py * xAy + translateX;  // move px dist along x axis
    var y = px * xAy + py * xAx + translateY;
    

    sn-p 显示它的作用

    const ctx = canvas.getContext("2d");
    const centerX = 250;
    const centerY = 250;
    const radius = 200;
    const boxWidth = 10;
    const boxLength = 20;
    
    
    // draw boxs around circle center at cx,cy and radius rad
    // box width bw, and box height bh
    // spacing optional is the distance between boxes
    function drawCircleOfBoxes(cx,cy,rad,bw,bh,spacing = 5){
      var points = [  // setout points of box with coord (0,0) as center
        {x : bh / 2, y :  -bw / 2},
        {x : bh / 2 + bh, y :  -bw / 2},
        {x : bh / 2 + bh, y :  -bw / 2 + bw},
        {x : bh / 2, y :  -bw / 2 + bw},
      ];
      var steps = (((rad - bw /2) * Math.PI * 2) / (bw + spacing) )+ 4| 0; // get number boxes that will fit circle
      ctx.beginPath();
      for(var i = 0; i < steps; i ++){
          const ang = (i / steps) * Math.PI * 2;
          const xAx = Math.cos(ang);  // get the direction of he xAxis
          const xAy = Math.sin(ang);
          var first = true
          for(const p of points){ // for each point
              // Apply the transform to the point after moving it
              // to the circle (the p.x + rad)
              const x = (p.x + rad) * xAx - p.y * xAy + cx;
              const y = (p.x + rad) * xAy + p.y * xAx + cy;
              if(first){
                 ctx.moveTo(x,y);
                 first = false;
              }else{
                 ctx.lineTo(x,y);
              }
          }
          ctx.closePath();
      }
    
      ctx.fill(); 
      ctx.stroke();
    
    }
    
    
    ctx.fillStyle = "#CFD";
    ctx.strokeStyle = "#000";
    
    for(var i = boxLength + 5; i < radius; i += boxLength + 5){
        drawCircleOfBoxes(centerX, centerY, i , boxWidth, boxLength);
    }
    &lt;canvas id="canvas" width="500" height="500"&gt;&lt;/canvas&gt;

    【讨论】:

    • 如何检测每个矩形上的点击事件?我正在与笛卡尔坐标系相反。
    • x=161, y = -5.5 点击鼠标时,我得到 x=-161, y=-5.5。
    • @DharanG 获取从圆心到鼠标vx = mx - cx; vy =my - cy; 的向量,其中 m 是鼠标,c 是圆心。然后得到轴承b = Math.atan(vy, vx) y 是第一个参数,归一化轴承b = (b + Math.PI * 2) % (Math.PI * 2). Using the steps`变量(drawCircleOfBoxes 函数的顶部)计算框的角宽度awaw = Math.PI / steps 查找从中心到鼠标的距离 dist = Math.sqrt(vx * vx + vy * vy) 使用 boxLengthradius 来查看鼠标距离是否正确 overRing = dist &gt;= radius - boxLength /2 &amp;&amp; dist &lt; radius + boxLength / 2... 继续
    • @DharanG 将角宽度添加到轴承b += aw(aw 实际上是角宽度的一半。将轴承除以角宽度和地板以获得盒子索引boxIndex = (b / (aw * 2)) | 0; 这将给出哪个盒子。但它是不完美。如果你想要完美,你需要为每个盒子创建一个逆变换并将其应用于鼠标坐标。然后只需使用这些坐标来检查鼠标是否在盒子内。
    • @DharanG 抱歉,这不是问题所在。您将不得不创建另一个问题。
    猜你喜欢
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-09
    相关资源
    最近更新 更多