rename visualobserver

This commit is contained in:
“chrisshank” 2024-11-26 01:02:19 -08:00
parent 1475c41a85
commit fee3a9f342
3 changed files with 35 additions and 37 deletions

View File

@ -1,8 +1,8 @@
import { FolkGeometry } from '../canvas/fc-geometry'; import { FolkGeometry } from '../canvas/fc-geometry';
import { Vertex } from './utils'; import { Vertex } from './utils';
import { VisualObserverEntry, VisualObserverManager } from './visual-observer'; import { ClientRectObserverEntry, ClientRectObserverManager } from './visual-observer';
const visualObserver = new VisualObserverManager(); const clientRectObserver = new ClientRectObserverManager();
const vertexRegex = /(?<x>-?([0-9]*[.])?[0-9]+),\s*(?<y>-?([0-9]*[.])?[0-9]+)/; const vertexRegex = /(?<x>-?([0-9]*[.])?[0-9]+),\s*(?<y>-?([0-9]*[.])?[0-9]+)/;
@ -50,7 +50,7 @@ export class AbstractArrow extends HTMLElement {
return this.#sourceElement; return this.#sourceElement;
} }
#sourceCallback = (entry: VisualObserverEntry) => { #sourceCallback = (entry: ClientRectObserverEntry) => {
this.#sourceRect = entry.contentRect; this.#sourceRect = entry.contentRect;
this.#update(); this.#update();
}; };
@ -88,7 +88,7 @@ export class AbstractArrow extends HTMLElement {
} }
}; };
#sourceIframeCallback = (entry: VisualObserverEntry) => { #sourceIframeCallback = (entry: ClientRectObserverEntry) => {
this.#sourceIframeRect = entry.contentRect; this.#sourceIframeRect = entry.contentRect;
this.#updateSourceIframeRect(); this.#updateSourceIframeRect();
}; };
@ -124,7 +124,7 @@ export class AbstractArrow extends HTMLElement {
return this.#targetElement; return this.#targetElement;
} }
#targetCallback = (entry: VisualObserverEntry) => { #targetCallback = (entry: ClientRectObserverEntry) => {
this.#targetRect = entry.contentRect; this.#targetRect = entry.contentRect;
this.#update(); this.#update();
}; };
@ -162,7 +162,7 @@ export class AbstractArrow extends HTMLElement {
} }
}; };
#targetIframeCallback = (entry: VisualObserverEntry) => { #targetIframeCallback = (entry: ClientRectObserverEntry) => {
this.#targetIframeRect = entry.contentRect; this.#targetIframeRect = entry.contentRect;
this.#updateTargetIframeRect(); this.#updateTargetIframeRect();
}; };
@ -214,13 +214,13 @@ export class AbstractArrow extends HTMLElement {
this.#sourceRect = this.#sourceElement.getBoundingClientRect(); this.#sourceRect = this.#sourceElement.getBoundingClientRect();
} else if (this.#sourceElement instanceof HTMLIFrameElement && this.#sourceIframeSelector) { } else if (this.#sourceElement instanceof HTMLIFrameElement && this.#sourceIframeSelector) {
window.addEventListener('message', this.#sourcePostMessage); window.addEventListener('message', this.#sourcePostMessage);
visualObserver.observe(this.#sourceElement, this.#sourceIframeCallback); clientRectObserver.observe(this.#sourceElement, this.#sourceIframeCallback);
this.#sourceElement.contentWindow?.postMessage({ this.#sourceElement.contentWindow?.postMessage({
type: 'folk-observe-element', type: 'folk-observe-element',
selector: this.#sourceIframeSelector, selector: this.#sourceIframeSelector,
}); });
} else { } else {
visualObserver.observe(this.#sourceElement, this.#sourceCallback); clientRectObserver.observe(this.#sourceElement, this.#sourceCallback);
this.#sourceRect = this.#sourceElement.getBoundingClientRect(); this.#sourceRect = this.#sourceElement.getBoundingClientRect();
} }
} }
@ -234,13 +234,13 @@ export class AbstractArrow extends HTMLElement {
this.#sourceElement.removeEventListener('move', this.#sourceHandler); this.#sourceElement.removeEventListener('move', this.#sourceHandler);
} else if (this.#sourceElement instanceof HTMLIFrameElement && this.#sourceIframeSelector) { } else if (this.#sourceElement instanceof HTMLIFrameElement && this.#sourceIframeSelector) {
window.removeEventListener('message', this.#sourcePostMessage); window.removeEventListener('message', this.#sourcePostMessage);
visualObserver.unobserve(this.#sourceElement, this.#sourceIframeCallback); clientRectObserver.unobserve(this.#sourceElement, this.#sourceIframeCallback);
this.#sourceElement.contentWindow?.postMessage({ this.#sourceElement.contentWindow?.postMessage({
type: 'folk-unobserve-element', type: 'folk-unobserve-element',
selector: this.#sourceIframeSelector, selector: this.#sourceIframeSelector,
}); });
} else { } else {
visualObserver.unobserve(this.#sourceElement, this.#sourceCallback); clientRectObserver.unobserve(this.#sourceElement, this.#sourceCallback);
} }
} }
@ -264,13 +264,13 @@ export class AbstractArrow extends HTMLElement {
this.#targetElement.addEventListener('move', this.#targetHandler); this.#targetElement.addEventListener('move', this.#targetHandler);
} else if (this.#targetElement instanceof HTMLIFrameElement && this.#targetIframeSelector) { } else if (this.#targetElement instanceof HTMLIFrameElement && this.#targetIframeSelector) {
window.addEventListener('message', this.#targetPostMessage); window.addEventListener('message', this.#targetPostMessage);
visualObserver.observe(this.#targetElement, this.#targetIframeCallback); clientRectObserver.observe(this.#targetElement, this.#targetIframeCallback);
this.#targetElement.contentWindow?.postMessage({ this.#targetElement.contentWindow?.postMessage({
type: 'folk-observe-element', type: 'folk-observe-element',
selector: this.#targetIframeSelector, selector: this.#targetIframeSelector,
}); });
} else { } else {
visualObserver.observe(this.#targetElement, this.#targetCallback); clientRectObserver.observe(this.#targetElement, this.#targetCallback);
} }
this.#targetRect = this.#targetElement.getBoundingClientRect(); this.#targetRect = this.#targetElement.getBoundingClientRect();
} }
@ -284,13 +284,13 @@ export class AbstractArrow extends HTMLElement {
this.#targetElement.removeEventListener('move', this.#targetHandler); this.#targetElement.removeEventListener('move', this.#targetHandler);
} else if (this.#targetElement instanceof HTMLIFrameElement && this.#targetIframeSelector) { } else if (this.#targetElement instanceof HTMLIFrameElement && this.#targetIframeSelector) {
window.removeEventListener('message', this.#targetPostMessage); window.removeEventListener('message', this.#targetPostMessage);
visualObserver.unobserve(this.#targetElement, this.#targetIframeCallback); clientRectObserver.unobserve(this.#targetElement, this.#targetIframeCallback);
this.#targetElement.contentWindow?.postMessage({ this.#targetElement.contentWindow?.postMessage({
type: 'folk-unobserve-element', type: 'folk-unobserve-element',
selector: this.#targetIframeSelector, selector: this.#targetIframeSelector,
}); });
} else { } else {
visualObserver.unobserve(this.#targetElement, this.#targetCallback); clientRectObserver.unobserve(this.#targetElement, this.#targetCallback);
} }
} }

View File

@ -1,5 +1,5 @@
import { FolkGeometry } from '../canvas/fc-geometry'; import { FolkGeometry } from '../canvas/fc-geometry';
import { VisualObserverManager, VisualObserverEntry } from './visual-observer.ts'; import { ClientRectObserverManager, ClientRectObserverEntry } from './visual-observer.ts';
interface ObservedElementEntry { interface ObservedElementEntry {
selector: string; selector: string;
@ -51,7 +51,7 @@ if (window.parent !== window) {
const observedElements = new Map(); const observedElements = new Map();
const observedSelectors = new Map(); const observedSelectors = new Map();
function boundingBoxCallback(entry: VisualObserverEntry) {} function boundingBoxCallback(entry: ClientRectObserverEntry) {}
function onGeometryChange(event) { function onGeometryChange(event) {
window.parent.postMessage({ window.parent.postMessage({

View File

@ -1,14 +1,14 @@
export interface VisualObserverEntry { export interface ClientRectObserverEntry {
target: Element; target: Element;
contentRect: DOMRectReadOnly; contentRect: DOMRectReadOnly;
isAppearing: boolean; isAppearing: boolean;
} }
export interface VisualObserverCallback { export interface ClientRectObserverCallback {
(this: VisualObserver, entries: VisualObserverEntry[], observer: VisualObserver): void; (this: ClientRectObserver, entries: ClientRectObserverEntry[], observer: ClientRectObserver): void;
} }
interface VisualObserverElement { interface ClientRectObserverElement {
io: IntersectionObserver | null; io: IntersectionObserver | null;
threshold: number; threshold: number;
isFirstUpdate: boolean; isFirstUpdate: boolean;
@ -17,20 +17,20 @@ interface VisualObserverElement {
/** /**
* Create an observer that notifies when an element is resized, moved, or added/removed from the DOM. * Create an observer that notifies when an element is resized, moved, or added/removed from the DOM.
*/ */
export class VisualObserver { export class ClientRectObserver {
#root = document.documentElement; #root = document.documentElement;
#rootRect = this.#root.getBoundingClientRect(); #rootRect = this.#root.getBoundingClientRect();
#entries: VisualObserverEntry[] = []; #entries: ClientRectObserverEntry[] = [];
#rafId = 0; #rafId = 0;
#callback: VisualObserverCallback; #callback: ClientRectObserverCallback;
constructor(callback: VisualObserverCallback) { constructor(callback: ClientRectObserverCallback) {
this.#callback = callback; this.#callback = callback;
} }
#elements = new Map<Element, VisualObserverElement>(); #elements = new Map<Element, ClientRectObserverElement>();
#resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => { #resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {
const rootEntry = entries.find((entry) => entry.target === this.#root); const rootEntry = entries.find((entry) => entry.target === this.#root);
@ -49,7 +49,7 @@ export class VisualObserver {
} }
}); });
#appendEntry(entry: VisualObserverEntry) { #appendEntry(entry: ClientRectObserverEntry) {
// deduplicate the same target // deduplicate the same target
this.#entries.push(entry); this.#entries.push(entry);
@ -66,9 +66,7 @@ export class VisualObserver {
}; };
// We should be guaranteed that each `IntersectionObserver` only observes one element. // We should be guaranteed that each `IntersectionObserver` only observes one element.
#onIntersection = ([ #onIntersection = ([{ target, intersectionRatio, boundingClientRect }]: IntersectionObserverEntry[]) => {
{ target, intersectionRatio, boundingClientRect },
]: IntersectionObserverEntry[]) => {
const el = this.#elements.get(target); const el = this.#elements.get(target);
if (el === undefined) return; if (el === undefined) return;
@ -100,7 +98,7 @@ export class VisualObserver {
#refreshElement( #refreshElement(
target: Element, target: Element,
contentRect: DOMRectReadOnly = target.getBoundingClientRect() contentRect: DOMRectReadOnly = target.getBoundingClientRect()
): VisualObserverEntry { ): ClientRectObserverEntry {
// Assume el exists // Assume el exists
const el = this.#elements.get(target)!; const el = this.#elements.get(target)!;
@ -176,7 +174,7 @@ export class VisualObserver {
this.#resizeObserver.observe(target); this.#resizeObserver.observe(target);
} }
takeRecords(): VisualObserverEntry[] { takeRecords(): ClientRectObserverEntry[] {
if (this.#rafId === 0) return []; if (this.#rafId === 0) return [];
const entries = this.#entries; const entries = this.#entries;
@ -203,12 +201,12 @@ export class VisualObserver {
} }
} }
export type VisualObserverEntryCallback = (entry: VisualObserverEntry) => void; export type ClientRectObserverEntryCallback = (entry: ClientRectObserverEntry) => void;
export class VisualObserverManager { export class ClientRectObserverManager {
#elementMap = new WeakMap<Element, Set<VisualObserverEntryCallback>>(); #elementMap = new WeakMap<Element, Set<ClientRectObserverEntryCallback>>();
#vo = new VisualObserver((entries) => { #vo = new ClientRectObserver((entries) => {
for (const entry of entries) { for (const entry of entries) {
const callbacks = this.#elementMap.get(entry.target); const callbacks = this.#elementMap.get(entry.target);
@ -218,7 +216,7 @@ export class VisualObserverManager {
} }
}); });
observe(target: Element, callback: VisualObserverEntryCallback): void { observe(target: Element, callback: ClientRectObserverEntryCallback): void {
let callbacks = this.#elementMap.get(target); let callbacks = this.#elementMap.get(target);
if (callbacks === undefined) { if (callbacks === undefined) {
@ -231,7 +229,7 @@ export class VisualObserverManager {
callbacks.add(callback); callbacks.add(callback);
} }
unobserve(target: Element, callback: VisualObserverEntryCallback): void { unobserve(target: Element, callback: ClientRectObserverEntryCallback): void {
let callbacks = this.#elementMap.get(target); let callbacks = this.#elementMap.get(target);
if (callbacks === undefined) return; if (callbacks === undefined) return;