From e61ec657d797838e2ae5728355fc15d8c70460ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cchrisshank=E2=80=9D?= Date: Mon, 25 Nov 2024 21:06:41 -0800 Subject: [PATCH] add trigger textarea --- src/arrows/event-propagator.ts | 64 +++++++++++++++++++++++----------- src/arrows/fc-rope.ts | 12 +++---- 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/arrows/event-propagator.ts b/src/arrows/event-propagator.ts index 7783c97..70a990b 100644 --- a/src/arrows/event-propagator.ts +++ b/src/arrows/event-propagator.ts @@ -5,7 +5,7 @@ styles.replaceSync(` textarea { position: absolute; width: auto; - min-width: 60px; + min-width: 3ch; height: auto; resize: none; background: rgba(256, 256, 256, 0.8); @@ -15,18 +15,26 @@ textarea { overflow: hidden; field-sizing: content; translate: -50% -50%; + border-radius: 5px; } `); export class EventPropagator extends FolkRope { static override tagName = 'event-propagator'; - #triggers = (this.getAttribute('triggers') || '').split(','); + #triggers: string[] = []; get triggers() { return this.#triggers; } - set triggers(triggers) { + set triggers(triggers: string | string[]) { + if (typeof triggers === 'string') { + triggers = triggers.split(','); + } + this.#removeEventListenersToSource(); + this.#triggers = triggers; + + this.#addEventListenersToSource(); } #expression = ''; @@ -47,62 +55,78 @@ export class EventPropagator extends FolkRope { } } - #textarea = document.createElement('textarea'); + #triggerTextarea = document.createElement('textarea'); + #expressionTextarea = document.createElement('textarea'); constructor() { super(); this.shadowRoot?.adoptedStyleSheets.push(styles); - this.#textarea.addEventListener('input', () => { - this.expression = this.#textarea.value; + this.#triggerTextarea.addEventListener('change', () => { + this.triggers = this.#triggerTextarea.value; + }); + this.triggers = this.#triggerTextarea.value = this.getAttribute('triggers') || ''; + + this.shadowRoot?.appendChild(this.#triggerTextarea); + + this.#expressionTextarea.addEventListener('input', () => { + this.expression = this.#expressionTextarea.value; }); - this.shadowRoot?.appendChild(this.#textarea); + this.shadowRoot?.appendChild(this.#expressionTextarea); - this.expression = this.#textarea.value = this.getAttribute('expression') || ''; + this.expression = this.#expressionTextarea.value = this.getAttribute('expression') || ''; } override render(sourceRect: DOMRectReadOnly, targetRect: DOMRectReadOnly) { super.render(sourceRect, targetRect); - - // Position textarea between source and target - const midX = (sourceRect.x + targetRect.x) / 2; - const midY = (sourceRect.y + targetRect.y) / 2; } override draw() { super.draw(); - const point = this.points[Math.floor(this.points.length / 2)]; - // Center the textarea by subtracting half its width and height - this.#textarea.style.left = `${point.pos.x}px`; - this.#textarea.style.top = `${point.pos.y}px`; + const triggerPoint = this.points[Math.floor(this.points.length / 5)]; + + if (triggerPoint) { + this.#triggerTextarea.style.left = `${triggerPoint.pos.x}px`; + this.#triggerTextarea.style.top = `${triggerPoint.pos.y}px`; + } + + const expressionPoint = this.points[Math.floor((this.points.length * 3) / 5)]; + + if (expressionPoint) { + this.#expressionTextarea.style.left = `${expressionPoint.pos.x}px`; + this.#expressionTextarea.style.top = `${expressionPoint.pos.y}px`; + } } override observeSource() { super.observeSource(); + this.#addEventListenersToSource(); + } + + #addEventListenersToSource() { for (const trigger of this.#triggers) { // TODO: add special triggers for intersection, rAF, etc. this.sourceElement?.addEventListener(trigger, this.evaluateExpression); } - //should we evaluate them immediately? - // this.evaluateExpression(); } override unobserveSource() { super.unobserveSource(); + this.#removeEventListenersToSource(); + } + #removeEventListenersToSource() { for (const trigger of this.#triggers) { - // TODO: add special triggers for intersection, rAF, etc. this.sourceElement?.removeEventListener(trigger, this.evaluateExpression); } } override observeTarget() { super.observeTarget(); - // this.evaluateExpression(); } override unobserveTarget() { diff --git a/src/arrows/fc-rope.ts b/src/arrows/fc-rope.ts index 72039c3..a009dbc 100644 --- a/src/arrows/fc-rope.ts +++ b/src/arrows/fc-rope.ts @@ -100,10 +100,10 @@ export class FolkRope extends AbstractArrow { }; #tick = (timestamp: number = performance.now()) => { - this.#rAFId = requestAnimationFrame(this.#tick); - this.#currentTime = timestamp; + this.#rAFId = requestAnimationFrame(this.#tick); + this.#deltaTime = this.#currentTime - this.#lastTime; if (this.#deltaTime > this.#interval) { @@ -130,8 +130,8 @@ export class FolkRope extends AbstractArrow { override render(sourceRect: DOMRectReadOnly, targetRect: DOMRectReadOnly) { if (this.#points.length === 0) { this.#points = this.#generatePoints( - { x: sourceRect.x, y: sourceRect.y }, - { x: targetRect.right, y: targetRect.bottom } + { x: sourceRect.x + sourceRect.width / 2, y: sourceRect.bottom }, + { x: targetRect.x + targetRect.width / 2, y: targetRect.bottom } ); this.#lastTime = 0; @@ -183,7 +183,7 @@ export class FolkRope extends AbstractArrow { x: lerp(start.x, end.x, percentage), y: lerp(start.y, end.y, percentage), }; - // new RopePoint({ x: lerpX, y: lerpY }, resolution, mass, damping, isFixed) + points.push({ pos, oldPos: { ...pos }, @@ -217,7 +217,7 @@ export class FolkRope extends AbstractArrow { point.oldPos = { ...point.pos }; // Drastically improves stability - const timeCorrection = previousFrameDt != 0.0 ? dt / previousFrameDt : 0.0; + const timeCorrection = previousFrameDt !== 0.0 ? dt / previousFrameDt : 0.0; const accel = Vector.add(gravity, { x: 0, y: point.mass });