better text area for propagators

This commit is contained in:
“chrisshank” 2024-11-24 17:44:57 -08:00
parent b8aae90d1b
commit 328442627f
3 changed files with 40 additions and 25 deletions

View File

@ -33,7 +33,7 @@
</head> </head>
<body> <body>
<fc-geometry id="box1" x="100" y="100" width="30" height="30"></fc-geometry> <fc-geometry id="box1" x="100" y="100" width="30" height="30"></fc-geometry>
<fc-geometry id="box2" x="200" y="300">Hello World</fc-geometry> <fc-geometry id="box2" x="200" y="350">Hello World</fc-geometry>
<event-propagator <event-propagator
source="#box1" source="#box1"
target="#box2" target="#box2"
@ -41,8 +41,8 @@
expression="$target.textContent += '!'" expression="$target.textContent += '!'"
></event-propagator> ></event-propagator>
<fc-geometry id="box3" x="150" y="200" width="30" height="30"></fc-geometry> <fc-geometry id="box3" x="350" y="200" width="30" height="30"></fc-geometry>
<fc-geometry id="box4" x="300" y="350" width="30" height="30"></fc-geometry> <fc-geometry id="box4" x="500" y="250" width="30" height="30"></fc-geometry>
<event-propagator <event-propagator
source="#box3" source="#box3"
target="#box4" target="#box4"

View File

@ -1,5 +1,23 @@
import { FolkRope } from './fc-rope.ts'; import { FolkRope } from './fc-rope.ts';
const styles = new CSSStyleSheet();
styles.replaceSync(`
textarea {
position: absolute;
width: auto;
min-width: 60px;
height: auto;
resize: none;
background: rgba(256, 256, 256, 0.8);
border: 1px solid #ccc;
padding: 4px;
pointer-events: auto;
overflow: hidden;
field-sizing: content;
translate: -50% -50%;
}
`);
export class EventPropagator extends FolkRope { export class EventPropagator extends FolkRope {
static override tagName = 'event-propagator'; static override tagName = 'event-propagator';
@ -24,7 +42,7 @@ export class EventPropagator extends FolkRope {
} catch (error) { } catch (error) {
console.warn('Failed to parse expression:', error); console.warn('Failed to parse expression:', error);
// Use no-op function when parsing fails // Use no-op function when parsing fails
this.break(); this.cut();
this.#function = () => {}; this.#function = () => {};
} }
} }
@ -34,27 +52,15 @@ export class EventPropagator extends FolkRope {
constructor() { constructor() {
super(); super();
this.#textarea.style.cssText = ` this.shadowRoot?.adoptedStyleSheets.push(styles);
position: absolute;
width: auto;
min-width: 60px;
height: auto;
resize: none;
background: white;
border: 1px solid #ccc;
padding: 4px;
pointer-events: auto;
overflow: hidden;
field-sizing: content;
`;
this.#textarea.value = this.getAttribute('expression') || '';
this.#textarea.addEventListener('input', () => { this.#textarea.addEventListener('input', () => {
this.expression = this.#textarea.value; this.expression = this.#textarea.value;
}); });
this.shadowRoot?.appendChild(this.#textarea); this.shadowRoot?.appendChild(this.#textarea);
this.expression = this.#textarea.value;
this.expression = this.#textarea.value = this.getAttribute('expression') || '';
} }
override render(sourceRect: DOMRectReadOnly, targetRect: DOMRectReadOnly) { override render(sourceRect: DOMRectReadOnly, targetRect: DOMRectReadOnly) {
@ -63,10 +69,15 @@ export class EventPropagator extends FolkRope {
// Position textarea between source and target // Position textarea between source and target
const midX = (sourceRect.x + targetRect.x) / 2; const midX = (sourceRect.x + targetRect.x) / 2;
const midY = (sourceRect.y + targetRect.y) / 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 // Center the textarea by subtracting half its width and height
this.#textarea.style.left = `${midX - this.#textarea.offsetWidth / 2}px`; this.#textarea.style.left = `${point.pos.x}px`;
this.#textarea.style.top = `${midY - this.#textarea.offsetHeight / 2}px`; this.#textarea.style.top = `${point.pos.y}px`;
} }
override observeSource() { override observeSource() {

View File

@ -61,6 +61,10 @@ export class FolkRope extends AbstractArrow {
#gravity = { x: 0, y: 3000 }; #gravity = { x: 0, y: 3000 };
#points: RopePoint[] = []; #points: RopePoint[] = [];
get points() {
return this.#points;
}
#stroke = this.getAttribute('stroke') || 'black'; #stroke = this.getAttribute('stroke') || 'black';
get stroke() { get stroke() {
return this.#stroke; return this.#stroke;
@ -92,7 +96,7 @@ export class FolkRope extends AbstractArrow {
#onResize = (entry: ResizeObserverEntry) => { #onResize = (entry: ResizeObserverEntry) => {
this.#canvas.width = entry.contentRect.width; this.#canvas.width = entry.contentRect.width;
this.#canvas.height = entry.contentRect.height; this.#canvas.height = entry.contentRect.height;
this.#drawRopePoints(); this.draw();
}; };
#tick = (timestamp: number = performance.now()) => { #tick = (timestamp: number = performance.now()) => {
@ -117,7 +121,7 @@ export class FolkRope extends AbstractArrow {
this.#previousDelta = dts; this.#previousDelta = dts;
this.#drawRopePoints(); this.draw();
this.#lastTime = this.#currentTime - (this.#deltaTime % this.#interval); this.#lastTime = this.#currentTime - (this.#deltaTime % this.#interval);
} }
@ -149,7 +153,7 @@ export class FolkRope extends AbstractArrow {
endingPoint.pos.y = targetRect.bottom; endingPoint.pos.y = targetRect.bottom;
} }
#drawRopePoints() { draw() {
this.#context.clearRect(0, 0, this.#canvas.width, this.#canvas.height); this.#context.clearRect(0, 0, this.#canvas.width, this.#canvas.height);
for (let i = 0; i < this.#points.length; i++) { for (let i = 0; i < this.#points.length; i++) {
@ -264,7 +268,7 @@ export class FolkRope extends AbstractArrow {
} }
} }
break(index = Math.floor(this.#points.length / 2)) { cut(index = Math.floor(this.#points.length / 2)) {
if (this.#points.length === 0) return; if (this.#points.length === 0) return;
this.#points[index].next = null; this.#points[index].next = null;