Dharan Ganesan
Dharan Ganesan

Reputation: 453

how i get a coordinate of each rectangle?

enter image description here i have tried this,

  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);

output:

enter image description here

expected result:

i want to calculate a four coordinate(rectangle) of rotated axis.

How do i detect click event on each rectangle?

enter image description here

Upvotes: 0

Views: 373

Answers (2)

Blindman67
Blindman67

Reputation: 54041

Using setTransform

Salix alba answer is a solution though a few too many steps.

It can be done in a single transform using setTransform and applying the translate and rotations in one step. Also the second translation is where you draw the box relative to its origin. When using transforms always draw objects around the center of rotation.

 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);
<canvas id="canvas" width="500" height="500"></canvas>

Manually apply the transform to a point

If you wish to transform the box in code you can use the transform applied in the above and apply it directly to a set of points. You can not apply it to the ctx.rect function that needs the API transform.

To transform a point px,py you need the the direction of the rotated x axis

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

You can then move the point px distance along the xAxis and then turn 90 deg and move py distance along the y axis

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;

Then just add the translation

x += translateX;
y += translateY;

Or done in one go

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

The snippet shows it in action

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);
}
<canvas id="canvas" width="500" height="500"></canvas>

Upvotes: 1

Salix alba
Salix alba

Reputation: 7824

To get rotated rectangles you need to use the transform() method of the graphics context.

Imagine a set of axis at the top left of the drawing area. Any drawing will be done relative to these axis which we can move with transform.

To translate by xshift, yshift

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

To rotate by angle ang in radians

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

We can combine things with three transformations. The first moves the origin to the center of the circle. Then rotate the axes about this point, then shift the axes to where you want the shape to appear. Finally, draw the shape.

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);
}

You can achieve the same this using the translate and rotate

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);
}

Upvotes: 0

Related Questions