Rotate a point about an origin by a specified angle. Read more on Wikipedia and StackExchange.
The red point represents the rotation of the blue point around the black point by 45 degrees. By dragging, you can adjust the position of the blue point and the black point, and the angle of rotation of the red point.
This block uses Geometric.js for all geometric functions, specifically lineAngle
, lineLength
, lineMidpoint
, pointRotate
and pointTranslate
.
xxxxxxxxxx
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
body {
margin: 0;
}
circle {
cursor: move;
}
.point {
fill: steelblue;
}
.point-line {
stroke: steelblue;
}
.rotated-point {
fill: tomato;
}
.rotated-point-line {
stroke: tomato;
}
text {
fill: #fff;
font-family: "Helvetica Neue", sans-serif;
pointer-events: none;
text-anchor: middle;
text-shadow: -3px -3px 1px rgba(195,136,192, 0.4), -3px -2px 1px rgba(195,136,192, 0.4), -3px -1px 1px rgba(195,136,192, 0.4), -3px 0px 1px rgba(195,136,192, 0.4), -3px 1px 1px rgba(195,136,192, 0.4), -3px 2px 1px rgba(195,136,192, 0.4), -3px 3px 1px rgba(195,136,192, 0.4), -2px -3px 1px rgba(195,136,192, 0.4), -2px -2px 1px rgba(195,136,192, 0.4), -2px -1px 1px rgba(195,136,192, 0.4), -2px 0px 1px rgba(195,136,192, 0.4), -2px 1px 1px rgba(195,136,192, 0.4), -2px 2px 1px rgba(195,136,192, 0.4), -2px 3px 1px rgba(195,136,192, 0.4), -1px -3px 1px rgba(195,136,192, 0.4), -1px -2px 1px rgba(195,136,192, 0.4), -1px -1px 1px rgba(195,136,192, 0.4), -1px 0px 1px rgba(195,136,192, 0.4), -1px 1px 1px rgba(195,136,192, 0.4), -1px 2px 1px rgba(195,136,192, 0.4), -1px 3px 1px rgba(195,136,192, 0.4), 0px -3px 1px rgba(195,136,192, 0.4), 0px -2px 1px rgba(195,136,192, 0.4), 0px -1px 1px rgba(195,136,192, 0.4), 0px 1px 1px rgba(195,136,192, 0.4), 0px 2px 1px rgba(195,136,192, 0.4), 0px 3px 1px rgba(195,136,192, 0.4), 1px -3px 1px rgba(195,136,192, 0.4), 1px -2px 1px rgba(195,136,192, 0.4), 1px -1px 1px rgba(195,136,192, 0.4), 1px 0px 1px rgba(195,136,192, 0.4), 1px 1px 1px rgba(195,136,192, 0.4), 1px 2px 1px rgba(195,136,192, 0.4), 1px 3px 1px rgba(195,136,192, 0.4), 2px -3px 1px rgba(195,136,192, 0.4), 2px -2px 1px rgba(195,136,192, 0.4), 2px -1px 1px rgba(195,136,192, 0.4), 2px 0px 1px rgba(195,136,192, 0.4), 2px 1px 1px rgba(195,136,192, 0.4), 2px 2px 1px rgba(195,136,192, 0.4), 2px 3px 1px rgba(195,136,192, 0.4), 3px -3px 1px rgba(195,136,192, 0.4), 3px -2px 1px rgba(195,136,192, 0.4), 3px -1px 1px rgba(195,136,192, 0.4), 3px 0px 1px rgba(195,136,192, 0.4), 3px 1px 1px rgba(195,136,192, 0.4), 3px 2px 1px rgba(195,136,192, 0.4), 3px 3px 1px rgba(195,136,192, 0.4);
}
path {
fill: purple;
fill-opacity: .5;
stroke: purple;
stroke-dasharray: 5, 5;
pointer-events: none;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/geometric@1.0.0/build/geometric.js"></script>
<script>
var width = window.innerWidth, height = window.innerHeight;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var anglePath = svg.append("path");
var origin_position = [width / 2, height / 2];
var point_position = origin_position.map((d, i) => d -= (i === 0 ? 45 : 100));
var rotation = 45;
var rotated_point_position = geometric.pointRotate(point_position, rotation, origin_position);
var point_line = svg.append("line").attr("class", "point-line");
var point = svg.append("circle")
.attr("r", 5)
.attr("class", "point")
.call(d3.drag().on("drag", _ => {
point_position[0] = event.pageX;
point_position[1] = event.pageY;
rotated_point_position = geometric.pointRotate(point_position, rotation, origin_position);
drawAngle();
drawPoint();
drawPointLine();
drawRotatedPoint();
drawRotatedPointLine();
}));
var rotated_point_line = svg.append("line").attr("class", "rotated-point-line");
var rotated_point = svg.append("circle")
.attr("r", 5)
.attr("class", "rotated-point")
.call(d3.drag().on("drag", _ => {
rotation = geometric.lineAngle([origin_position, [event.pageX, event.pageY]]) - geometric.lineAngle([origin_position, point_position]);
rotated_point_position = geometric.pointRotate(point_position, rotation, origin_position);
drawAngle();
drawRotatedPoint();
drawRotatedPointLine();
}));
var origin = svg.append("circle")
.attr("r", 5)
.attr("class", "origin")
.call(d3.drag().on("drag", _ => {
var point_distance = geometric.lineLength([origin_position, point_position]);
var point_angle = geometric.lineAngle([origin_position, point_position]);
origin_position[0] = event.pageX;
origin_position[1] = event.pageY;
point_position = geometric.pointTranslate(origin_position, point_angle, point_distance);
rotated_point_position = geometric.pointRotate(point_position, rotation, origin_position);
drawAngle();
drawOrigin();
drawPoint();
drawPointLine();
drawRotatedPoint();
drawRotatedPointLine();
}));
var angleText = svg.append("text").attr("dx", 3.5);
drawOrigin();
drawPointLine();
drawPoint();
drawRotatedPoint();
drawRotatedPointLine();
drawAngle();
function drawAngle(){
angleText
.attr("transform", "translate(" + geometric.lineMidpoint([point_position, rotated_point_position]) + ")")
.text(Math.round(rotation > 180 ? 360 - rotation : rotation < -180 ? 360 + rotation : Math.abs(rotation)) + "°");
var d = geometric.lineLength([point_position, rotated_point_position]);
anglePath
.attr("d", "M" + ((rotation < 0 && rotation > -180) || rotation > 180 ? rotated_point_position : point_position) + "A" + d + "," + d + " 0 0,1 " + ((rotation < 0 && rotation > -180) || rotation > 180 ? point_position : rotated_point_position) + " L" + origin_position + " Z")
}
function drawOrigin(){
origin.attr("transform", "translate(" + origin_position + ")");
}
function drawPoint(){
point.attr("transform", "translate(" + point_position + ")");
}
function drawPointLine(){
point_line
.attr("x1", point_position[0])
.attr("y1", point_position[1])
.attr("x2", origin_position[0])
.attr("y2", origin_position[1]);
}
function drawRotatedPoint(){
rotated_point.attr("transform", "translate(" + rotated_point_position + ")");
}
function drawRotatedPointLine(){
rotated_point_line
.attr("x1", rotated_point_position[0])
.attr("y1", rotated_point_position[1])
.attr("x2", origin_position[0])
.attr("y2", origin_position[1]);
}
</script>
</body>
</html>
https://d3js.org/d3.v5.min.js
https://unpkg.com/geometric@1.0.0/build/geometric.js