1.21 gigawatts
1.21 gigawatts

Reputation: 17878

How to rotate an SVG rectangle with a transform or with math using the rotated values?

I'm recreating a rectangle in SVG using the data I receive. I can draw a rectangle correctly as long as the rectangle is not rotated. When it is rotated it's in the incorrect location.

The rectangle values are:

left: 27
top: 30
width: 100
height: 100
localBoundsWidth: 100
localBoundsHeight: 100

Here is the unrotated rectangle (correctly positioned):

.Rectangle_1 {
  position: absolute;
  overflow: visible;
  width: 100px;
  height: 100px;
  left: 27px;
  top: 30px;
}
.Line_1 {
  overflow: visible;
  position: absolute;
  top: 30.5px;
  left: 0.5px;
  width: 225px;
  height: 1px;
}
.Line_2 {
  overflow: visible;
  position: absolute;
  top: 0.5px;
  left: 27.5px;
  width: 1px;
  height: 197px;
}
<div>
	<svg class="Rectangle_1">
		<rect fill="rgba(255,93,93,1)" id="Rectangle_1" rx="0" ry="0" x="0" y="0" width="100" height="100">
		</rect>
	</svg>
	<svg class="Line_1">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_1" d="M 0 0 L 225 0">
		</path>
	</svg>
	<svg class="Line_2">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_2" d="M 0 0 L 0 197">
		</path>
	</svg>
</div>

Here is what it should look like (desired result). I've manually adjusted the position:

#Rectangle_1 {
   transform: matrix(0.7660,0.6427,-0.6427,0.7660,64.28,0.5);
}
.Rectangle_1 {
  position: absolute;
  overflow: visible;
  width: 140.883px;
  height: 140.883px;
  left: 6.558px;
  top: 9.558px;
}
.Line_1 {
  overflow: visible;
  position: absolute;
  top: 30.5px;
  left: 0.5px;
  width: 225px;
  height: 1px;
}
.Line_2 {
  overflow: visible;
  position: absolute;
  top: 0.5px;
  left: 27.5px;
  width: 1px;
  height: 197px;
}
.Line_5 {
  overflow: visible;
  position: absolute;
  top: 0.5px;
  left: 70.5px;
  width: 1px;
  height: 9px;
}
.Line_6 {
  overflow: visible;
  position: absolute;
  top: 86.5px;
  left: 0.5px;
  width: 6px;
  height: 1px;
}
<div>
	<svg class="Rectangle_1">
		<rect fill="rgba(255,93,93,1)" id="Rectangle_1" rx="0" ry="0" x="0" y="0" width="100" height="100">
		</rect>
	</svg>
	<svg class="Line_1">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_1" d="M 0 0 L 225 0">
		</path>
	</svg>
	<svg class="Line_2">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_2" d="M 0 0 L 0 197">
		</path>
	</svg>
	<svg class="Line_5">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_5" d="M 0 9 L 0 0">
		</path>
	</svg>
	<svg class="Line_6">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_6" d="M 6 0 L 0 0">
		</path>
	</svg>
</div>

When the rectangle is rotated I can't draw it in the correct location because the values I'm receiving are the draw bounds after the rectangle has been rotated around it's center.

So the original unrotated rectangle values are:

left: 27
top: 30
width: 100
height: 100
localBoundsWidth: 100
localBoundsHeight: 100

When it's rotated 40 degrees the values are:

left: 6.56
top: 9.56
width: 140
height: 140
transform: matrix(0.766,0.6428,-0.6428,0.766,70.8372,9.5584)
rotation: 40
localBoundsWidth: 100
localBoundsHeight: 100

If it matters the top left in its parent coordinate space is:

x: 70.83
y: 9.56

When I try to create a rotated rectangle using the information above (the rotated values) the rectangle is in the incorrect location.

#Rectangle_1 {
  transform: rotate(40deg);
}
.Rectangle_1 {
  position: absolute;
  overflow: visible;
  width: 100px;
  height: 100px;
  left: 6.56px;
  top: 9.56px;
}
.Line_1 {
  overflow: visible;
  position: absolute;
  top: 30.5px;
  left: 0.5px;
  width: 225px;
  height: 1px;
}
.Line_2 {
  overflow: visible;
  position: absolute;
  top: 0.5px;
  left: 27.5px;
  width: 1px;
  height: 197px;
}
<div>
	<svg class="Rectangle_1">
		<rect fill="rgba(255,93,93,1)" id="Rectangle_1" rx="0" ry="0" x="0" y="0" width="100" height="100">
		</rect>
	</svg>
	<svg class="Line_1">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_1" d="M 0 0 L 225 0">
		</path>
	</svg>
	<svg class="Line_2">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_2" d="M 0 0 L 0 197">
		</path>
	</svg>
</div>

When I try to use the matrix value it's also in the incorrect location:

#Rectangle_1 {
  transform: matrix(0.766,0.6428,-0.6428,0.766,70.8372,9.5584);
}
.Rectangle_1 {
  position: absolute;
  overflow: visible;
  width: 100px;
  height: 100px;
  left: 6.56px;
  top: 9.56px;
}
.Line_1 {
  overflow: visible;
  position: absolute;
  top: 30.5px;
  left: 0.5px;
  width: 225px;
  height: 1px;
}
.Line_2 {
  overflow: visible;
  position: absolute;
  top: 0.5px;
  left: 27.5px;
  width: 1px;
  height: 197px;
}

.Line_5 {
  overflow: visible;
  position: absolute;
  top: 0.5px;
  left: 70.5px;
  width: 1px;
  height: 9px;
}
.Line_6 {
  overflow: visible;
  position: absolute;
  top: 86.5px;
  left: 0.5px;
  width: 6px;
  height: 1px;
}
<div>
	<svg class="Rectangle_1">
		<rect fill="rgba(255,93,93,1)" id="Rectangle_1" rx="0" ry="0" x="0" y="0" width="100" height="100">
		</rect>
	</svg>
	<svg class="Line_1">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_1" d="M 0 0 L 225 0">
		</path>
	</svg>
	<svg class="Line_2">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_2" d="M 0 0 L 0 197">
		</path>
	</svg>

	<svg class="Line_5">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_5" d="M 0 9 L 0 0">
		</path>
	</svg>
	<svg class="Line_6">
		<path stroke="rgba(112,112,112,1)" stroke-width="1px" stroke-linejoin="miter" stroke-linecap="butt" stroke-miterlimit="4" shape-rendering="auto" id="Line_6" d="M 6 0 L 0 0">
		</path>
	</svg>
</div>

I only have the following information to work with to correctly rotate the rectangle (rotated values):

left: 6.56
top: 9.56
width: 140
height: 140
transform: matrix(0.766,0.6428,-0.6428,0.766,70.8372,9.5584)
rotation: 40
localBoundsWidth: 100
localBoundsHeight: 100

The top left in it's parent coordinate space is:

x: 70.83
y: 9.56

Is it possible to place the rectangle in the correct location with only the above information (the rotated values)?

Or is it possible to un-rotate the rectangle with only the information above to get the original top and left values?

FYI The rectangle has been rotated around its center point not the top left.

Upvotes: 1

Views: 423

Answers (1)

enxaneta
enxaneta

Reputation: 33072

I hope this is what you are asking: As I've commented in your data the size is 140, however if you do the math it should be 140.88 Please let me know if this is not ok for you.

In the next demo I'm calculating the position of the rotated square's vertices on the bounding box (black stroked square), then I'm drawing the rotated square (red stroked square) by joining the calculated points for the vertices with a polygon.

// initial data

let hyp = 100;//hypotenuse
let size = 140.88;//the size of the bounding box
let rot = 40*Math.PI/180;//rotation: 40 degs
let tl = {x:6.56,y:9.56};//the top left point

let c1 = Math.sin(rot) * 100;//the length of the first cathetus

//let c2 = Math.sqrt(hyp * hyp - c1*c1)

//the points for the polygon: a rotated square
let p1 = {x:tl.x + c1,y:tl.y}
let p2 = {x:tl.x + size,y:tl.y+c1}
let p3 = {x:tl.x + size - c1,y:tl.y + size}
let p4 = {x:tl.x,y:tl.y + size - c1}

// the points attribute for the polygon
let points =`${p1.x},${p1.y} ${p2.x},${p2.y} ${p3.x},${p3.y} ${p4.x},${p4.y}`
poly.setAttributeNS(null,"points",points)
svg{border:1px solid #d9d9d9}
<svg viewBox="0 0 154 160" width="300">
  <!--the rect is drawing the bounding box for the rotated square-->
  <rect x="6.56" y="9.56" width="140.88" height="140.88" fill="none" stroke="black" />
  
  <polygon id="poly" stroke="red" fill="none" />
</svg>

Upvotes: 1

Related Questions