radians for rotation
This commit is contained in:
parent
c7a3580f9f
commit
792cf0683a
|
|
@ -23,7 +23,7 @@
|
||||||
<body>
|
<body>
|
||||||
<folk-shape x="100" y="100" width="50" height="50"></folk-shape>
|
<folk-shape x="100" y="100" width="50" height="50"></folk-shape>
|
||||||
<folk-shape x="100" y="200" width="50" height="50"></folk-shape>
|
<folk-shape x="100" y="200" width="50" height="50"></folk-shape>
|
||||||
<folk-shape x="100" y="300" width="50" height="50" rotate="45"></folk-shape>
|
<folk-shape x="100" y="300" width="50" height="50" rotation="45"></folk-shape>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { FolkShape } from '../src/folk-shape.ts';
|
import { FolkShape } from '../src/folk-shape.ts';
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const resizeObserver = new ResizeObserverManager();
|
||||||
export type Shape = 'rectangle' | 'circle' | 'triangle';
|
export type Shape = 'rectangle' | 'circle' | 'triangle';
|
||||||
|
|
||||||
type RotatedDOMRect = DOMRect & {
|
type RotatedDOMRect = DOMRect & {
|
||||||
/** in degrees */
|
/** in radians */
|
||||||
rotation: number;
|
rotation: number;
|
||||||
|
|
||||||
/** Returns the center point in worldspace coordinates */
|
/** Returns the center point in worldspace coordinates */
|
||||||
|
|
@ -134,7 +134,7 @@ styles.replaceSync(css`
|
||||||
cursor: var(--fc-nesw-resize, nesw-resize);
|
cursor: var(--fc-nesw-resize, nesw-resize);
|
||||||
}
|
}
|
||||||
|
|
||||||
[part='rotate'] {
|
[part='rotation'] {
|
||||||
z-index: calc(infinity);
|
z-index: calc(infinity);
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -154,7 +154,7 @@ styles.replaceSync(css`
|
||||||
}
|
}
|
||||||
|
|
||||||
:host(:not(:focus-within)) [part^='resize'],
|
:host(:not(:focus-within)) [part^='resize'],
|
||||||
:host(:not(:focus-within)) [part='rotate'] {
|
:host(:not(:focus-within)) [part='rotation'] {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
@ -256,8 +256,8 @@ export class FolkShape extends HTMLElement {
|
||||||
#startAngle = 0;
|
#startAngle = 0;
|
||||||
#previousRotation = 0;
|
#previousRotation = 0;
|
||||||
|
|
||||||
// TODO: consider using radians instead of degrees
|
// use degrees in the DOM, but store in radians internally
|
||||||
#rotation = Number(this.getAttribute('rotate')) || 0;
|
#rotation = (Number(this.getAttribute('rotation')) || 0) * (Math.PI / 180);
|
||||||
|
|
||||||
get rotation(): number {
|
get rotation(): number {
|
||||||
return this.#rotation;
|
return this.#rotation;
|
||||||
|
|
@ -266,7 +266,7 @@ export class FolkShape extends HTMLElement {
|
||||||
set rotation(rotation: number) {
|
set rotation(rotation: number) {
|
||||||
this.#previousRotation = this.#rotation;
|
this.#previousRotation = this.#rotation;
|
||||||
this.#rotation = rotation;
|
this.#rotation = rotation;
|
||||||
this.#requestUpdate('rotate');
|
this.#requestUpdate('rotation');
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -282,7 +282,7 @@ export class FolkShape extends HTMLElement {
|
||||||
// Ideally we would creating these lazily on first focus, but the resize handlers need to be around for delegate focus to work.
|
// Ideally we would creating these lazily on first focus, but the resize handlers need to be around for delegate focus to work.
|
||||||
// Maybe can add the first resize handler here, and lazily instantiate the rest when needed?
|
// Maybe can add the first resize handler here, and lazily instantiate the rest when needed?
|
||||||
// I can see it becoming important at scale
|
// I can see it becoming important at scale
|
||||||
shadowRoot.innerHTML = html` <button part="rotate"></button>
|
shadowRoot.innerHTML = html` <button part="rotation"></button>
|
||||||
<button part="resize-nw"></button>
|
<button part="resize-nw"></button>
|
||||||
<button part="resize-ne"></button>
|
<button part="resize-ne"></button>
|
||||||
<button part="resize-se"></button>
|
<button part="resize-se"></button>
|
||||||
|
|
@ -294,12 +294,11 @@ export class FolkShape extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.#update(new Set(['type', 'x', 'y', 'height', 'width', 'rotate']));
|
this.#update(new Set(['type', 'x', 'y', 'height', 'width', 'rotation']));
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientRect(): RotatedDOMRect {
|
getClientRect(): RotatedDOMRect {
|
||||||
const { x, y, width, height, rotation } = this;
|
const { x, y, width, height, rotation } = this;
|
||||||
const radians = (rotation * Math.PI) / 180;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x,
|
x,
|
||||||
|
|
@ -325,14 +324,13 @@ export class FolkShape extends HTMLElement {
|
||||||
|
|
||||||
corners() {
|
corners() {
|
||||||
const center = this.center();
|
const center = this.center();
|
||||||
const radians = (this.rotation * Math.PI) / 180;
|
const { x, y, width, height, rotation } = this;
|
||||||
const { x, y, width, height } = this;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Vector.rotateAround({ x, y }, center, radians),
|
Vector.rotateAround({ x, y }, center, rotation),
|
||||||
Vector.rotateAround({ x: x + width, y }, center, radians),
|
Vector.rotateAround({ x: x + width, y }, center, rotation),
|
||||||
Vector.rotateAround({ x: x + width, y: y + height }, center, radians),
|
Vector.rotateAround({ x: x + width, y: y + height }, center, rotation),
|
||||||
Vector.rotateAround({ x, y: y + height }, center, radians),
|
Vector.rotateAround({ x, y: y + height }, center, rotation),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -358,7 +356,7 @@ export class FolkShape extends HTMLElement {
|
||||||
const target = event.composedPath()[0] as HTMLElement;
|
const target = event.composedPath()[0] as HTMLElement;
|
||||||
|
|
||||||
// Store initial angle on rotation start
|
// Store initial angle on rotation start
|
||||||
if (target.getAttribute('part') === 'rotate') {
|
if (target.getAttribute('part') === 'rotation') {
|
||||||
// We need to store initial rotation/angle somewhere.
|
// We need to store initial rotation/angle somewhere.
|
||||||
// This is a little awkward as we'll want to do *quite a lot* of this kind of thing.
|
// This is a little awkward as we'll want to do *quite a lot* of this kind of thing.
|
||||||
// Might be an argument for making elements dumber (i.e. not have them manage their own state) and do this from the outside.
|
// Might be an argument for making elements dumber (i.e. not have them manage their own state) and do this from the outside.
|
||||||
|
|
@ -441,13 +439,13 @@ export class FolkShape extends HTMLElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part === 'rotate') {
|
if (part === 'rotation') {
|
||||||
const centerX = this.#x + this.width / 2;
|
const centerX = this.#x + this.width / 2;
|
||||||
const centerY = this.#y + this.height / 2;
|
const centerY = this.#y + this.height / 2;
|
||||||
const currentAngle = Math.atan2(event.clientY - centerY, event.clientX - centerX);
|
const currentAngle = Math.atan2(event.clientY - centerY, event.clientX - centerX);
|
||||||
|
|
||||||
const deltaAngle = currentAngle - this.#startAngle;
|
const deltaAngle = currentAngle - this.#startAngle;
|
||||||
this.rotation = this.#initialRotation + (deltaAngle * 180) / Math.PI;
|
this.rotation = this.#initialRotation + deltaAngle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,13 +533,13 @@ export class FolkShape extends HTMLElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatedProperties.has('rotate')) {
|
if (updatedProperties.has('rotation')) {
|
||||||
// Although the change in resize isn't useful inside this component, the outside world might find it helpful to calculate acceleration and other physics
|
// 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.#rotation - this.#previousRotation }));
|
const notCancelled = this.dispatchEvent(new RotateEvent({ rotate: this.#rotation - this.#previousRotation }));
|
||||||
|
|
||||||
if (notCancelled) {
|
if (notCancelled) {
|
||||||
if (updatedProperties.has('rotate')) {
|
if (updatedProperties.has('rotation')) {
|
||||||
this.style.rotate = `${this.#rotation}deg`;
|
this.style.rotate = `${this.#rotation}rad`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.#rotation = this.#previousRotation;
|
this.#rotation = this.#previousRotation;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue