vector gizmo

This commit is contained in:
Orion Reed 2024-12-20 18:48:21 -05:00
parent 2dc21997cf
commit 1ec960527a
2 changed files with 73 additions and 1 deletions

View File

@ -19,6 +19,10 @@ interface RectOptions extends LineOptions {
fill?: string;
}
interface VectorOptions extends LineOptions {
size?: number;
}
/**
* Visual debugging system that renders canvas overlays in DOM containers.
*
@ -35,6 +39,7 @@ interface RectOptions extends LineOptions {
* Gizmos.point({x, y});
* Gizmos.line(start, end, { color: 'red' });
* Gizmos.rect(domRect, { fill: 'blue' });
* Gizmos.vector(origin, vector, { color: 'blue', width: 2, size: 10 });
* ```
*/
export class Gizmos extends FolkElement {
@ -150,6 +155,41 @@ export class Gizmos extends FolkElement {
ctx.stroke();
}
/** Draws a vector with an arrow head */
static vector(
origin: Point,
vector: Point,
{ color = 'blue', width = 2, size = 10, layer = Gizmos.#defaultLayer }: VectorOptions = {},
) {
const ctx = Gizmos.#getContext(layer);
if (!ctx) return;
// Calculate angle and length
const angle = Math.atan2(vector.y - origin.y, vector.x - origin.x);
const arrowAngle = Math.PI / 6; // 30 degrees
// Calculate where the line should end (where arrow head begins)
const lineEndX = vector.x - size * Math.cos(angle);
const lineEndY = vector.y - size * Math.sin(angle);
// Draw the main line
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.moveTo(origin.x, origin.y);
ctx.lineTo(lineEndX, lineEndY);
ctx.stroke();
// Draw arrow head as a connected triangle
ctx.beginPath();
ctx.moveTo(vector.x, vector.y); // Tip of the arrow
ctx.lineTo(vector.x - size * Math.cos(angle - arrowAngle), vector.y - size * Math.sin(angle - arrowAngle));
ctx.lineTo(vector.x - size * Math.cos(angle + arrowAngle), vector.y - size * Math.sin(angle + arrowAngle));
ctx.lineTo(vector.x, vector.y); // Back to the tip
ctx.fillStyle = color;
ctx.fill();
}
/** Clears drawings from a specific layer or all layers if no layer specified */
static clear(layer?: string) {
if (layer) {

View File

@ -34,6 +34,11 @@
</head>
<body>
<button onclick="enableGravity()">Enable Gravity</button>
<div>
<label for="gravityScale">Gravity Scale:</label>
<input type="range" id="gravityScale" min="0" max="6000" value="3000" step="100" />
<span id="gravityScaleValue">3000</span>
</div>
<p>Alpha: <span id="alpha">0</span></p>
<p>Beta: <span id="beta">0</span></p>
<p>Gamma: <span id="gamma">0</span></p>
@ -58,11 +63,14 @@
rotation: from.x"
></folk-event-propagator> -->
<folk-gizmos></folk-gizmos>
<script type="module">
import { requestAnimationFrame } from '@lib';
import { Vector } from '@lib/Vector';
import '@labs/standalone/folk-shape.ts';
import '@labs/standalone/folk-event-propagator.ts';
import { Gizmos } from '@lib/folk-gizmos';
document.addEventListener(
'touchmove',
@ -75,6 +83,15 @@ rotation: from.x"
const ropes = Array.from(document.querySelectorAll('folk-event-propagator'));
let orientationEvent;
let gravityScale = 3000;
const gravitySlider = document.getElementById('gravityScale');
const gravityScaleValue = document.getElementById('gravityScaleValue');
gravitySlider.addEventListener('input', (e) => {
gravityScale = parseInt(e.target.value);
gravityScaleValue.textContent = gravityScale;
});
function tick() {
requestAnimationFrame(tick);
if (orientationEvent === undefined) return;
@ -95,10 +112,25 @@ rotation: from.x"
const direction = Vector.normalized(downwardVector);
// Scale the vector by gravity constant
const gravityScale = 3000;
const gravity = Vector.scale(direction, magnitude * gravityScale);
window.gravity.textContent = `${Math.round(gravity.x)}, ${Math.round(gravity.y)}`;
// Draw the gravity vector
const center = {
x: window.innerWidth / 2,
y: window.innerHeight / 2,
};
Gizmos.vector(
center,
{
x: center.x + gravity.x / 100 + 50,
y: center.y + gravity.y / 100 + 50,
},
{ color: 'grey', width: 3, size: 15 },
);
ropes.forEach((rope) => {
rope.gravity = gravity;
});