vector gizmo
This commit is contained in:
parent
2dc21997cf
commit
1ec960527a
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue