refactor sets to use lit
This commit is contained in:
parent
d7b0cfe85b
commit
45cbde27e2
|
|
@ -44,11 +44,11 @@
|
|||
<folk-shape x="100" y="300" width="50" height="50"></folk-shape>
|
||||
<folk-hull sources="h1, body > folk-shape"></folk-hull>
|
||||
|
||||
<!-- <folk-hull sources="h1">
|
||||
<folk-hull sources="h1">
|
||||
<folk-shape x="350" y="100" width="50" height="50"></folk-shape>
|
||||
<folk-shape x="500" y="200" width="50" height="50"></folk-shape>
|
||||
<folk-shape x="400" y="300" width="50" height="50"></folk-shape>
|
||||
</folk-hull> -->
|
||||
</folk-hull>
|
||||
|
||||
<script type="module">
|
||||
import '../src/standalone/folk-shape.ts';
|
||||
|
|
|
|||
|
|
@ -1,28 +1,13 @@
|
|||
import { property, state } from '@lit/reactive-element/decorators.js';
|
||||
import { ClientRectObserverEntry } from './common/client-rect-observer.ts';
|
||||
import { FolkElement } from './common/folk-element.ts';
|
||||
import { FolkObserver } from './common/folk-observer.ts';
|
||||
import { PropertyValues } from '@lit/reactive-element';
|
||||
|
||||
const folkObserver = new FolkObserver();
|
||||
|
||||
const defaultRect = DOMRectReadOnly.fromRect();
|
||||
|
||||
export class FolkBaseSet extends HTMLElement {
|
||||
static tagName = '';
|
||||
|
||||
static define() {
|
||||
if (customElements.get(this.tagName)) return;
|
||||
customElements.define(this.tagName, this);
|
||||
}
|
||||
|
||||
#sources = this.getAttribute('sources') || '';
|
||||
/** A CSS selector for the sources of the arrow. */
|
||||
get sources() {
|
||||
return this.#sources;
|
||||
}
|
||||
|
||||
set sources(sources) {
|
||||
this.#sources = sources;
|
||||
this.observeSources();
|
||||
}
|
||||
export class FolkBaseSet extends FolkElement {
|
||||
@property({ type: String, reflect: true }) sources = '';
|
||||
|
||||
#sourcesMap = new Map<Element, DOMRectReadOnly>();
|
||||
get sourcesMap(): ReadonlyMap<Element, DOMRectReadOnly> {
|
||||
|
|
@ -33,34 +18,32 @@ export class FolkBaseSet extends HTMLElement {
|
|||
return Array.from(this.#sourcesMap.values());
|
||||
}
|
||||
|
||||
#sourceElements = new Set<Element>();
|
||||
get sourceElements(): ReadonlySet<Element> {
|
||||
return this.#sourceElements;
|
||||
}
|
||||
@state() sourceElements = new Set<Element>();
|
||||
|
||||
#sourcesCallback = (entry: ClientRectObserverEntry) => {
|
||||
this.#sourcesMap.set(entry.target, entry.contentRect);
|
||||
if (this.#sourceElements.size === this.#sourcesMap.size) {
|
||||
this.update();
|
||||
}
|
||||
this.requestUpdate();
|
||||
};
|
||||
|
||||
connectedCallback() {
|
||||
this.observeSources();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.unobserveSources();
|
||||
}
|
||||
|
||||
override update(changedProperties: PropertyValues<this>) {
|
||||
super.update(changedProperties);
|
||||
|
||||
if (changedProperties.has('sources')) {
|
||||
this.observeSources();
|
||||
}
|
||||
}
|
||||
|
||||
observeSources() {
|
||||
const elements = this.sources ? document.querySelectorAll(this.sources) : [];
|
||||
const childElements = new Set(this.children);
|
||||
const elements = this.sources ? document.querySelectorAll(this.sources) : [];
|
||||
const sourceElements = new Set(elements).union(childElements);
|
||||
|
||||
const elementsToObserve = sourceElements.difference(this.#sourceElements);
|
||||
|
||||
const elementsToUnobserve = this.#sourceElements.difference(sourceElements);
|
||||
const elementsToObserve = sourceElements.difference(this.sourceElements);
|
||||
const elementsToUnobserve = this.sourceElements.difference(sourceElements);
|
||||
|
||||
this.unobserveSources(elementsToUnobserve);
|
||||
|
||||
|
|
@ -68,16 +51,14 @@ export class FolkBaseSet extends HTMLElement {
|
|||
folkObserver.observe(el, this.#sourcesCallback);
|
||||
}
|
||||
|
||||
this.#sourceElements = sourceElements;
|
||||
this.sourceElements = sourceElements;
|
||||
}
|
||||
|
||||
unobserveSources(elements: Set<Element> = this.#sourceElements) {
|
||||
unobserveSources(elements: Set<Element> = this.sourceElements) {
|
||||
for (const el of elements) {
|
||||
folkObserver.unobserve(el, this.#sourcesCallback);
|
||||
this.#sourcesMap.delete(el);
|
||||
this.#sourceElements.delete(el);
|
||||
this.sourceElements.delete(el);
|
||||
}
|
||||
}
|
||||
|
||||
update() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { glsl } from './common/tags.ts';
|
|||
import { WebGLUtils } from './common/webgl.ts';
|
||||
import { FolkBaseSet } from './folk-base-set.ts';
|
||||
import { FolkShape } from './folk-shape.ts';
|
||||
import { PropertyValues } from '@lit/reactive-element';
|
||||
|
||||
/**
|
||||
* The DistanceField class calculates a distance field using the Jump Flooding Algorithm (JFA) in WebGL.
|
||||
|
|
@ -76,7 +77,11 @@ export class FolkDistanceField extends FolkBaseSet {
|
|||
/**
|
||||
* Handles updates to geometry elements by re-initializing seed points and rerunning the JFA.
|
||||
*/
|
||||
override update() {
|
||||
override update(changedProperties: PropertyValues<this>) {
|
||||
super.update(changedProperties);
|
||||
|
||||
if (this.sourcesMap.size !== this.sourceElements.size) return;
|
||||
|
||||
this.populateSeedPoints();
|
||||
this.runJumpFloodingAlgorithm();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { FolkBaseSet } from './folk-base-set';
|
||||
import { verticesToPolygon } from './common/utils';
|
||||
import type { Point } from './common/types';
|
||||
import { css, html } from './common/tags';
|
||||
import { PropertyValues, css } from '@lit/reactive-element';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
|
@ -9,44 +9,40 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
const styles = css`
|
||||
:host {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#hull {
|
||||
background-color: var(--folk-hull-bg, #b4d8f644);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::slotted(*) {
|
||||
pointer-events: auto;
|
||||
}
|
||||
`;
|
||||
|
||||
export class FolkHull extends FolkBaseSet {
|
||||
static tagName = 'folk-hull';
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#hull {
|
||||
background-color: var(--folk-hull-bg, #b4d8f644);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::slotted(*) {
|
||||
pointer-events: auto;
|
||||
}
|
||||
`;
|
||||
|
||||
#hull: Point[] = [];
|
||||
|
||||
get hull(): ReadonlyArray<Point> {
|
||||
return this.#hull;
|
||||
}
|
||||
|
||||
#shadow = this.attachShadow({ mode: 'open' });
|
||||
|
||||
#slot = document.createElement('slot');
|
||||
#hullEl = document.createElement('div');
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
override firstUpdated(changedProperties: PropertyValues<this>): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
|
||||
this.#hullEl.id = 'hull';
|
||||
|
||||
this.#shadow.adoptedStyleSheets.push(styles);
|
||||
|
||||
this.#shadow.append(this.#hullEl, this.#slot);
|
||||
this.renderRoot.append(this.#hullEl, this.#slot);
|
||||
|
||||
this.#slot.addEventListener('slotchange', this.#onSlotchange);
|
||||
}
|
||||
|
|
@ -54,14 +50,15 @@ export class FolkHull extends FolkBaseSet {
|
|||
// we might not need to react to the first slot change
|
||||
#onSlotchange = () => this.observeSources();
|
||||
|
||||
update() {
|
||||
if (this.sourcesMap.size === 0) {
|
||||
override update(changedProperties: PropertyValues<this>) {
|
||||
super.update(changedProperties);
|
||||
|
||||
if (this.sourcesMap.size !== this.sourceElements.size) {
|
||||
this.style.clipPath = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const rects = Array.from(this.sourcesMap.values());
|
||||
this.#hull = makeHull(rects);
|
||||
this.#hull = makeHull(this.sourceRects);
|
||||
this.#hullEl.style.clipPath = verticesToPolygon(this.#hull);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue