@paperbits/common
Version:
Paperbits common components.
78 lines (67 loc) • 3.27 kB
text/typescript
import { BehaviorHandle } from "./behavior";
import { Events } from "../events";
export interface AngleBehaviorOptions {
/**
* Callback function invoked when the angle changes.
* @param angle The new angle in degrees (0-359).
*/
onChange: (angle: number) => void;
}
export class AngleBehavior {
public static attach(element: HTMLElement, options: AngleBehaviorOptions): BehaviorHandle {
const rect = element.getBoundingClientRect();
const centerX = Math.floor(rect.width / 2);
const centerY = Math.floor(rect.height / 2);
let tracking = false;
const determineAngle = (x: number, y: number) => {
const dx = centerX - x;
const dy = centerY - y;
let theta = Math.atan2(dy, dx) * 180 / Math.PI;
theta += -90; // Adjusting to make 0 degrees at the top
if (theta < 0) {
theta += 360;
}
options.onChange(Math.floor(theta));
};
const onMouseDown = (event: MouseEvent) => {
tracking = true;
determineAngle(event.offsetX, event.offsetY);
};
const onMouseUp = (event: MouseEvent) => {
if (tracking) { // Only determine angle if tracking was active
determineAngle(event.offsetX, event.offsetY);
}
tracking = false;
};
const onMouseMove = (event: MouseEvent) => {
if (!tracking) {
return;
}
determineAngle(event.offsetX, event.offsetY);
};
const onMouseLeave = (event: MouseEvent) => {
// Optional: if you want tracking to stop if mouse leaves the element
// if (tracking) {
// determineAngle(event.offsetX, event.offsetY); // Update one last time
// }
// tracking = false;
};
element.addEventListener(Events.MouseDown, onMouseDown);
// Listen to mouseup and mousemove on the document or a specific capturing parent
// to handle cases where the mouse is released outside the element.
// However, the original code listened on the element itself for mouseup and mousemove with capture=true.
// For now, sticking to element listeners as per original, but document-level listeners are often more robust for dragging.
document.addEventListener(Events.MouseUp, onMouseUp, true); // Changed to document to ensure mouseup is caught
document.addEventListener(Events.MouseMove, onMouseMove, true); // Changed to document for better tracking experience
// element.addEventListener(Events.MouseLeave, onMouseLeave); // Optional: see comment above
return {
detach: () => {
element.removeEventListener(Events.MouseDown, onMouseDown);
document.removeEventListener(Events.MouseUp, onMouseUp, true);
document.removeEventListener(Events.MouseMove, onMouseMove, true);
// element.removeEventListener(Events.MouseLeave, onMouseLeave);
tracking = false; // Ensure tracking is reset
}
};
}
}