rotation in RotatedDOMRect
This commit is contained in:
parent
9b22f838af
commit
14d94f83e7
|
|
@ -38,12 +38,13 @@ export class DistanceField extends HTMLElement {
|
|||
this.initWebGL();
|
||||
this.initShaders();
|
||||
this.initPingPongTextures();
|
||||
this.initSeedPointRendering();
|
||||
this.populateSeedPoints();
|
||||
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
this.shapes.forEach((geometry) => {
|
||||
geometry.addEventListener('move', this.handleGeometryUpdate);
|
||||
geometry.addEventListener('resize', this.handleGeometryUpdate);
|
||||
geometry.addEventListener('rotate', this.handleGeometryUpdate);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +53,7 @@ export class DistanceField extends HTMLElement {
|
|||
this.shapes.forEach((geometry) => {
|
||||
geometry.removeEventListener('move', this.handleGeometryUpdate);
|
||||
geometry.removeEventListener('resize', this.handleGeometryUpdate);
|
||||
geometry.removeEventListener('rotate', this.handleGeometryUpdate);
|
||||
});
|
||||
this.cleanupWebGLResources();
|
||||
}
|
||||
|
|
@ -71,7 +73,8 @@ export class DistanceField extends HTMLElement {
|
|||
* Handles updates to geometry elements by re-initializing seed points and rerunning the JFA.
|
||||
*/
|
||||
private handleGeometryUpdate = () => {
|
||||
this.initSeedPointRendering();
|
||||
console.log('handleGeometryUpdate');
|
||||
this.populateSeedPoints();
|
||||
this.runJumpFloodingAlgorithm();
|
||||
};
|
||||
|
||||
|
|
@ -140,7 +143,7 @@ export class DistanceField extends HTMLElement {
|
|||
* Initializes rendering of seed points (shapes) into a texture.
|
||||
* Seed points are the starting locations for distance calculations.
|
||||
*/
|
||||
private initSeedPointRendering() {
|
||||
private populateSeedPoints() {
|
||||
const gl = this.glContext;
|
||||
const positions: number[] = [];
|
||||
|
||||
|
|
@ -150,12 +153,39 @@ export class DistanceField extends HTMLElement {
|
|||
// Collect positions and assign unique IDs to all shapes
|
||||
this.shapes.forEach((geometry, index) => {
|
||||
const rect = geometry.getClientRect();
|
||||
const rotation = (geometry.rotation * Math.PI) / 180; // Convert to radians
|
||||
|
||||
// Convert DOM coordinates to Normalized Device Coordinates (NDC)
|
||||
const x1 = (rect.left / windowWidth) * 2 - 1;
|
||||
const y1 = -((rect.top / windowHeight) * 2 - 1);
|
||||
const x2 = (rect.right / windowWidth) * 2 - 1;
|
||||
const y2 = -((rect.bottom / windowHeight) * 2 - 1);
|
||||
// Calculate the center of the rectangle
|
||||
const centerX = (rect.left + rect.right) / 2;
|
||||
const centerY = (rect.top + rect.bottom) / 2;
|
||||
|
||||
// Function to rotate a point around the center
|
||||
const rotatePoint = (x: number, y: number) => {
|
||||
const dx = x - centerX;
|
||||
const dy = y - centerY;
|
||||
const cos = Math.cos(rotation);
|
||||
const sin = Math.sin(rotation);
|
||||
return {
|
||||
x: centerX + dx * cos - dy * sin,
|
||||
y: centerY + dx * sin + dy * cos,
|
||||
};
|
||||
};
|
||||
|
||||
// Rotate each corner of the rectangle
|
||||
const topLeft = rotatePoint(rect.left, rect.top);
|
||||
const topRight = rotatePoint(rect.right, rect.top);
|
||||
const bottomLeft = rotatePoint(rect.left, rect.bottom);
|
||||
const bottomRight = rotatePoint(rect.right, rect.bottom);
|
||||
|
||||
// Convert rotated coordinates to NDC
|
||||
const x1 = (topLeft.x / windowWidth) * 2 - 1;
|
||||
const y1 = -((topLeft.y / windowHeight) * 2 - 1);
|
||||
const x2 = (topRight.x / windowWidth) * 2 - 1;
|
||||
const y2 = -((topRight.y / windowHeight) * 2 - 1);
|
||||
const x3 = (bottomLeft.x / windowWidth) * 2 - 1;
|
||||
const y3 = -((bottomLeft.y / windowHeight) * 2 - 1);
|
||||
const x4 = (bottomRight.x / windowWidth) * 2 - 1;
|
||||
const y4 = -((bottomRight.y / windowHeight) * 2 - 1);
|
||||
|
||||
const shapeID = index + 1; // Avoid zero to prevent hash function issues
|
||||
|
||||
|
|
@ -165,20 +195,20 @@ export class DistanceField extends HTMLElement {
|
|||
y1,
|
||||
shapeID,
|
||||
x2,
|
||||
y1,
|
||||
shapeID,
|
||||
x1,
|
||||
y2,
|
||||
shapeID,
|
||||
x3,
|
||||
y3,
|
||||
shapeID,
|
||||
|
||||
x1,
|
||||
y2,
|
||||
shapeID,
|
||||
x2,
|
||||
y1,
|
||||
x3,
|
||||
y3,
|
||||
shapeID,
|
||||
x2,
|
||||
y2,
|
||||
shapeID,
|
||||
x4,
|
||||
y4,
|
||||
shapeID
|
||||
);
|
||||
});
|
||||
|
|
@ -376,7 +406,7 @@ export class DistanceField extends HTMLElement {
|
|||
this.initPingPongTextures();
|
||||
|
||||
// Re-initialize seed point rendering to update positions
|
||||
this.initSeedPointRendering();
|
||||
this.populateSeedPoints();
|
||||
|
||||
// Rerun the Jump Flooding Algorithm with the new sizes
|
||||
this.runJumpFloodingAlgorithm();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ const resizeObserver = new ResizeObserverManager();
|
|||
|
||||
export type Shape = 'rectangle' | 'circle' | 'triangle';
|
||||
|
||||
type RotatedDOMRect = DOMRect & { rotation: number };
|
||||
|
||||
export type MoveEventDetail = { movementX: number; movementY: number };
|
||||
|
||||
export class MoveEvent extends CustomEvent<MoveEventDetail> {
|
||||
|
|
@ -239,15 +241,18 @@ export class FolkShape extends HTMLElement {
|
|||
|
||||
#initialRotation = 0;
|
||||
#startAngle = 0;
|
||||
#previousRotate = 0;
|
||||
#rotate = Number(this.getAttribute('rotate')) || 0;
|
||||
get rotate(): number {
|
||||
return this.#rotate;
|
||||
#previousRotation = 0;
|
||||
|
||||
// TODO: consider using radians instead of degrees
|
||||
#rotation = Number(this.getAttribute('rotate')) || 0;
|
||||
|
||||
get rotation(): number {
|
||||
return this.#rotation;
|
||||
}
|
||||
|
||||
set rotate(rotate: number) {
|
||||
this.#previousRotate = this.#rotate;
|
||||
this.#rotate = rotate;
|
||||
set rotation(rotation: number) {
|
||||
this.#previousRotation = this.#rotation;
|
||||
this.#rotation = rotation;
|
||||
this.#requestUpdate('rotate');
|
||||
}
|
||||
|
||||
|
|
@ -279,8 +284,8 @@ export class FolkShape extends HTMLElement {
|
|||
this.#update(new Set(['type', 'x', 'y', 'height', 'width', 'rotate']));
|
||||
}
|
||||
|
||||
getClientRect(): DOMRect {
|
||||
const { x, y, width, height } = this;
|
||||
getClientRect(): RotatedDOMRect {
|
||||
const { x, y, width, height, rotation } = this;
|
||||
|
||||
return {
|
||||
x,
|
||||
|
|
@ -291,6 +296,7 @@ export class FolkShape extends HTMLElement {
|
|||
top: y,
|
||||
right: x + width,
|
||||
bottom: y + height,
|
||||
rotation,
|
||||
toJSON: undefined as any,
|
||||
};
|
||||
// return DOMRectReadOnly.fromRect({ x: this.x, y: this.y, width: this.width, height: this.height });
|
||||
|
|
@ -320,7 +326,7 @@ export class FolkShape extends HTMLElement {
|
|||
// Might be an argument for making elements dumber (i.e. not have them manage their own state) and do this from the outside.
|
||||
// But we also want to preserve the self-sufficient nature of elements' behaviour...
|
||||
// Maybe some kind of shared utility, used by both the element and the outside environment?
|
||||
this.#initialRotation = this.#rotate;
|
||||
this.#initialRotation = this.#rotation;
|
||||
const centerX = this.#x + this.width / 2;
|
||||
const centerY = this.#y + this.height / 2;
|
||||
this.#startAngle = Math.atan2(event.clientY - centerY, event.clientX - centerX);
|
||||
|
|
@ -383,7 +389,7 @@ export class FolkShape extends HTMLElement {
|
|||
const currentAngle = Math.atan2(event.clientY - centerY, event.clientX - centerX);
|
||||
|
||||
const deltaAngle = currentAngle - this.#startAngle;
|
||||
this.rotate = this.#initialRotation + (deltaAngle * 180) / Math.PI;
|
||||
this.rotation = this.#initialRotation + (deltaAngle * 180) / Math.PI;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -473,14 +479,14 @@ export class FolkShape extends HTMLElement {
|
|||
|
||||
if (updatedProperties.has('rotate')) {
|
||||
// Although the change in resize isn't useful inside this component, the outside world might find it helpful to calculate acceleration and other physics
|
||||
const notCancelled = this.dispatchEvent(new RotateEvent({ rotate: this.#rotate - this.#previousRotate }));
|
||||
const notCancelled = this.dispatchEvent(new RotateEvent({ rotate: this.#rotation - this.#previousRotation }));
|
||||
|
||||
if (notCancelled) {
|
||||
if (updatedProperties.has('rotate')) {
|
||||
this.style.rotate = `${this.#rotate}deg`;
|
||||
this.style.rotate = `${this.#rotation}deg`;
|
||||
}
|
||||
} else {
|
||||
this.#rotate = this.#previousRotate;
|
||||
this.#rotation = this.#previousRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue