Created
November 24, 2016 00:42
-
-
Save redgeoff/911cdeac0ffbb7325194a6642ea35619 to your computer and use it in GitHub Desktop.
Rotated Rectangles
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
<script> | |
var Point = function (x, y) { | |
this.x = x; | |
this.y = y; | |
}; | |
var rotatePoint = function (p, rads) { | |
return new Point(p.x*Math.cos(rads) - p.y*Math.sin(rads), | |
p.x*Math.sin(rads) + p.y*Math.cos(rads)); | |
}; | |
var rotatePointAround = function (p, rads, ctr) { | |
var p2 = rotatePoint(new Point(p.x - ctr.x, p.y - ctr.y), rads); | |
return new Point(p2.x + ctr.x, p2.y + ctr.y); | |
}; | |
var rotatePointsAround = function (points, rads, ctr) { | |
var rotatedPoints = []; | |
points.forEach(function (point) { | |
rotatedPoints.push(rotatePointAround(point, rads, ctr)); | |
}); | |
return rotatedPoints; | |
}; | |
var boundingRect = function (vertices) { | |
var left = vertices[0].x, | |
right = vertices[0].x, | |
top = vertices[0].y, | |
bottom = vertices[0].y; | |
vertices.forEach(function (vertex) { | |
if (vertex.x < left) { | |
left = vertex.x; | |
} | |
if (vertex.x > right) { | |
right = vertex.x; | |
} | |
if (vertex.y < top) { | |
top = vertex.y; | |
} | |
if (vertex.y > bottom) { | |
bottom = vertex.y; | |
} | |
}); | |
return { left: left, right: right, top: top, bottom: bottom }; | |
}; | |
var toVertices = function (x, y, width, height) { | |
return [ | |
new Point(x, y), | |
new Point(width, y), | |
new Point(width, height), | |
new Point(x, height) | |
]; | |
}; | |
var rotateAndGetBoundingRect = function (width, height, rads) { | |
var vertices = toVertices(0, 0, width, height); | |
var center = new Point(width/2, height/2); | |
var rotatedVertices = rotatePointsAround(vertices, rads, center); | |
return boundingRect(rotatedVertices); | |
}; | |
// Allow for 1 extra pixel as the canvas's implementation of round may differ from ours by up to 1 | |
// pixel and we don't want to clip any pixels | |
var EXTRA_PIXEL = 1; | |
var getOffsets = function (left, top) { | |
// Use floor so that we don't clip any pixels as we are rounding to the nearest pixel | |
var x = -Math.floor(left) + EXTRA_PIXEL; | |
var y = -Math.floor(top) + EXTRA_PIXEL; | |
return { x: x, y: y }; | |
}; | |
var drawRotatedRect = function (canvas, width, height, rads) { | |
// Get the bounding rect after rotation and use this to position our rectangle and size our canvas. | |
var rect = rotateAndGetBoundingRect(width, height, rads); | |
var offsets = getOffsets(rect.left, rect.top); | |
// Use ceil so that we don't clip any pixels | |
var canvasWidth = Math.ceil(rect.right) + offsets.x + EXTRA_PIXEL; | |
var canvasHeight = Math.ceil(rect.bottom) + offsets.y + EXTRA_PIXEL; | |
canvas.width = canvasWidth; | |
canvas.height = canvasWidth; | |
var ctx = canvas.getContext('2d'); | |
ctx.translate(offsets.x + width/2, offsets.y + height/2); | |
ctx.rotate(rads); | |
ctx.rect(-width/2, -height/2, width, height); | |
ctx.stroke(); | |
return offsets; | |
}; | |
var createAndDrawRotatedRect = function (x, y, width, height, rads) { | |
var canvas = document.createElement('canvas'); | |
var offsets = drawRotatedRect(canvas, width, height, rads); | |
canvas.style.position = 'absolute'; | |
canvas.style.left = (x - offsets.x) + 'px'; | |
canvas.style.top = (y - offsets.y) + 'px'; | |
document.body.appendChild(canvas); | |
}; | |
var degs2Rads = function (degs) { | |
return degs*Math.PI/180; | |
}; | |
// ----- | |
// Starting point for 1st rectangle | |
var x = 100, y = 100; | |
var width = 100, height = 100, rads = degs2Rads(45); | |
var rect = rotateAndGetBoundingRect(width, height, rads); | |
var center = new Point(x + width/2, y + height/2); | |
var rotatedVertices = rotatePointsAround(toVertices(x, y, width, height), rads, center); | |
var offsets = getOffsets(rect.left, rect.top); | |
createAndDrawRotatedRect(x, y, width, height, rads); | |
var dX = Math.cos(Math.PI/2 - rads)*height; | |
var dY = Math.sin(Math.PI/2 - rads)*height; | |
createAndDrawRotatedRect(x + dX, y - dY, width, height, rads); | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment