Public
Edited
Sep 10, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof radius = Inputs.range([0, 320], { label: "radius", step: 1, value: 80 })
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function normalToDegrees(x, z) {
return (Math.atan2(x, z) / Math.PI) * 180;
}
Insert cell
{
const canvas = document.createElement("canvas");
canvas.width = radius * 2;
canvas.height = radius * 2;
canvas.style.width = `${radius * 2}px`;
canvas.style.height = `${radius * 2}px`;
const ctx = canvas.getContext("2d");

ctx.fillStyle = "black";
ctx.fillRect(0, 0, radius * 2, radius * 2);

ctx.fillStyle = "red";
const range = 360;
const stepSize = 180;
for (let degrees = 0; degrees <= range; degrees += stepSize) {
ctx.fillStyle = `rgb(${(degrees / range) * 128 + 128},0,0)`;

let p = rotate(radius, degrees);
let degreeRecovered = normalToDegrees(p.x, p.y);

console.log("degrees", degrees, degreeRecovered);

p = rotate(radius, 45);
console.log("p", p.x, p.y);
circle(p.x + radius + degrees * 10, p.y + radius, radius / 10, ctx);
}

return canvas;
}
Insert cell
Insert cell
Insert cell
function calculateRotationAngle(x, y) {
const angleInRadians = Math.atan2(-y, -x);
// Convert radians to degrees
const angleInDegrees = angleInRadians * (180 / Math.PI);

// Normalize the angle to be between 0 and 360
const normalizedAngle = (angleInDegrees + 360) % 360;

return normalizedAngle;
}
Insert cell
Insert cell
function calculateCycleAngle(x, z) {
const degrees = (calculateRotationAngle(x, -z) + 90) % 360;
return degrees;
}
Insert cell
{
const width = 200;
const height = 200;
const canvas = getCanvas(width, height);
const ctx = canvas.getContext("2d");

ctx.fillStyle = "white";
circle(width / 2, height / 2, 5, ctx);

ctx.textAlign = "center";

function drawDirectionalLightAngleNormal(x, z, color) {
ctx.font = "bold 14px serif";

const distance = Math.sqrt(x * x + z * z);

const degrees = calculateCycleAngle(x / distance, z / distance); //90;

console.log(x / distance, z / distance, x, z, distance, degrees);

x = (-x * width) / 4;
z = (-z * height) / 4;

ctx.fillStyle = "rgb(200,200,200)";
circle(width / 2 + x, height / 2 + z, 3, ctx);

ctx.fillText(`${degrees}°`, width / 2 + x + 2, height / 2 + z - 5);
}

// Visuals are top down
// z is down towards bottom and x increases to the right

// x,z pairs
const lightDirections = [
[0, -1],
[-1, -1],
[-1, 0],
[-1, 1],
[0, 1],
[1, 1],
[1, 0],
[1, -1]
];
lightDirections.forEach((lightDirection) => {
drawDirectionalLightAngleNormal(lightDirection[0], lightDirection[1]);
});

return canvas;
}
Insert cell
Insert cell
Insert cell
function getCanvas(width, height) {
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
const ctx = canvas.getContext("2d");

ctx.fillStyle = "black";
ctx.fillRect(0, 0, width, height);

return canvas;
}
Insert cell
offsetX = (Math.cos(((cycleAngle + 180) / 180) * Math.PI) + 1) * radius
Insert cell
function circle(x, y, Radius, ctx, stroke = false) {
ctx.beginPath();
ctx.arc(x, y, Radius, 0, 2 * Math.PI);
if (stroke) {
ctx.stroke();
} else {
ctx.fill();
}
}
Insert cell
function ellipse(x, y, RadiusX, RadiusY, ctx, stroke = false) {
ctx.beginPath();
ctx.ellipse(x, y, RadiusX, RadiusY, 0, 0, 2 * Math.PI);
if (stroke) {
ctx.stroke();
} else {
ctx.fill();
}
}
Insert cell
function calculateVerticalRadius(horizontalRadius, x, y) {
let factor = 1 - (x * x) / (horizontalRadius * horizontalRadius);
if (factor === 0) {
factor = 0.0001;
}
return Math.sqrt((y * y) / factor);
}
Insert cell
function dotProductToDegrees(dotProduct) {
const angleInRadians = Math.acos(dotProduct);
const angleInDegrees = angleInRadians * (180 / Math.PI);
return angleInDegrees;
}
Insert cell
dotProductToDegrees(0)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more