add imperative radial space (working on composition of coordinate spaces)

This commit is contained in:
Orion Reed 2024-12-07 15:49:50 -05:00
parent a141d05e87
commit 7535245702
3 changed files with 141 additions and 0 deletions

45
demo/radial-space.html Normal file
View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Shapes</title>
<style>
html {
width: 100%;
height: 100%;
position: fixed;
overflow: hidden;
}
body {
min-height: 100%;
position: relative;
margin: 0;
}
folk-shape {
background: rgb(187, 178, 178);
}
folk-space-radial {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<folk-space-radial>
<folk-shape x="0" y="100" width="50" height="50"></folk-shape>
<folk-shape x="0" y="200" width="50" height="50"></folk-shape>
<folk-shape x="20" y="300" width="50" height="50" rotation="45"></folk-shape>
<folk-shape x="20" y="400" width="50" height="50" rotation="45"></folk-shape>
<folk-shape x="20" y="500" width="50" height="50" rotation="45"></folk-shape>
</folk-space-radial>
<script type="module">
import '../src/standalone/folk-shape.ts';
import '../src/standalone/folk-space-radial.ts';
</script>
</body>
</html>

91
src/folk-space-radial.ts Normal file
View File

@ -0,0 +1,91 @@
import { css, html } from './common/tags';
import { FolkShape } from './folk-shape';
import { DOMRectTransform } from './common/DOMRectTransform';
const styles = css`
:host {
display: block;
position: relative;
border: 2px dashed hsl(214, 84%, 56%);
border-radius: 50%;
}
::slotted(*) {
position: absolute;
transform-origin: 50% 0%;
}
.center-point {
position: absolute;
width: 8px;
height: 8px;
background: hsl(214, 84%, 56%);
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
`;
export class FolkSpaceRadial extends HTMLElement {
static tagName = 'folk-space-radial';
static define() {
if (!customElements.get(this.tagName)) {
customElements.define(this.tagName, this);
}
}
#shadow = this.attachShadow({ mode: 'open' });
#centerPoint: HTMLDivElement;
constructor() {
super();
this.#shadow.adoptedStyleSheets = [styles];
// Create center point marker
this.#centerPoint = document.createElement('div');
this.#centerPoint.className = 'center-point';
this.#shadow.innerHTML = html` <slot></slot> `;
this.#shadow.appendChild(this.#centerPoint);
// Listen for changes in the slot to layout children when they change
const slot = this.#shadow.querySelector('slot');
slot?.addEventListener('slotchange', () => this.#layoutChildren());
}
connectedCallback() {
this.#layoutChildren();
}
#layoutChildren() {
const slot = this.#shadow.querySelector('slot');
const assignedElements = slot?.assignedElements() || [];
const count = assignedElements.length;
// Determine the radius and center of the radial layout
const radius = Math.min(this.clientWidth, this.clientHeight) / 2 - 50;
const centerX = this.clientWidth / 2;
const centerY = this.clientHeight / 2;
assignedElements.forEach((element, index) => {
if (!(element instanceof FolkShape)) return;
// Calculate the angle for each child
const angle = (index / count) * 2 * Math.PI;
// Create a transform for each child
const transform = new DOMRectTransform({
x: centerX + radius * Math.cos(angle),
y: centerY + radius * Math.sin(angle),
rotation: angle,
transformOrigin: { x: 0.5, y: 0 },
});
// Set the transform on the child
element.setTransform(transform);
});
}
}
FolkSpaceRadial.define();

View File

@ -0,0 +1,5 @@
import { FolkSpaceRadial } from '../folk-space-radial';
FolkSpaceRadial.define();
export { FolkSpaceRadial };