FIX: Junction positioning via parent's client-rects

This commit is contained in:
Patrick Haßel 2025-02-03 09:49:26 +01:00
parent d2311a5647
commit 7fe2e3361a
5 changed files with 101 additions and 32 deletions

View File

@ -0,0 +1,14 @@
export class Rect {
static readonly ZERO: Rect = new Rect(0, 0, 0, 0);
constructor(
readonly x: number,
readonly y: number,
readonly w: number,
readonly h: number,
) {
//
}
}

View File

@ -26,6 +26,7 @@ export class Parts {
if (this.dragStartPart !== null && this.dragCursor !== null) { if (this.dragStartPart !== null && this.dragCursor !== null) {
this.dragStartPart.rasterCenterX = Math.floor(this.dragCursor.x / RASTER); this.dragStartPart.rasterCenterX = Math.floor(this.dragCursor.x / RASTER);
this.dragStartPart.rasterCenterY = Math.floor(this.dragCursor.y / RASTER); this.dragStartPart.rasterCenterY = Math.floor(this.dragCursor.y / RASTER);
this.dragStartPart.updateJunctionPositions();
} }
} }

View File

@ -1,5 +1,7 @@
import {Wire} from "../wire/Wire"; import {Wire} from "../wire/Wire";
import {Part} from '../parts/Part'; import {Part} from '../parts/Part';
import {Rect} from '../../Rect';
import {selectTowardsRoot} from '../../selectTowardsRoot';
export const JUNCTION_RADIUS_PERCENT = 15; export const JUNCTION_RADIUS_PERCENT = 15;
@ -13,16 +15,14 @@ export class Junction {
readonly wires: Wire[] = []; readonly wires: Wire[] = [];
private _rect: Rect | null = null;
voltage: number | null = null; voltage: number | null = null;
minCircuitVoltage: number | null = null; minCircuitVoltage: number | null = null;
maxCircuitVoltage: number | null = null; maxCircuitVoltage: number | null = null;
get fullName(): string {
return `'${this.part.name}' '${this.name}'`;
}
constructor( constructor(
public readonly part: Part, public readonly part: Part,
percentX: number, percentX: number,
@ -32,24 +32,16 @@ export class Junction {
this.percentY = percentY - JUNCTION_RADIUS_PERCENT; this.percentY = percentY - JUNCTION_RADIUS_PERCENT;
} }
toString(): string { get fullName(): string {
return `${this.name}`; return `'${this.part.name}' '${this.name}'`;
}
private mapRect(next: (b: DOMRect) => number): number {
const rect = document.getElementById(this.uuid)?.getBoundingClientRect();
if (!rect) {
return 0;
}
return next(rect);
} }
get pixelX(): number { get pixelX(): number {
return this.mapRect(b => b.x + b.width / 2); return this.rect.x + this.rect.w / 2;
} }
get pixelY(): number { get pixelY(): number {
return this.mapRect(b => b.y + b.height / 2); return this.rect.y + this.rect.h / 2;
} }
get percentW(): number { get percentW(): number {
@ -60,6 +52,21 @@ export class Junction {
return (JUNCTION_RADIUS_PERCENT * 2); return (JUNCTION_RADIUS_PERCENT * 2);
} }
get rect(): Rect {
if (this._rect === null) {
this._rect = this.findRect();
}
return this._rect;
}
toString(): string {
return `${this.name}`;
}
updatePosition() {
this._rect = this.findRect();
}
sumAllBut(plus: Junction) { sumAllBut(plus: Junction) {
return this.wires return this.wires
.filter(wire => wire.traverse(this) !== plus) .filter(wire => wire.traverse(this) !== plus)
@ -67,4 +74,25 @@ export class Junction {
.reduce((a, b) => a + b, 0); .reduce((a, b) => a + b, 0);
} }
private findRect(): Rect {
const child = document.getElementById(this.uuid);
if (!child) {
throw Error(`No HTMLElement found for Junction: uuid=${this.uuid}, name=${this.name}`);
}
const parent = selectTowardsRoot(child, "svg.circuit");
if (!parent) {
throw Error(`No parent matching "svg.circuit" found for: ${child}`);
}
const childRect = child.getBoundingClientRect();
const parentRect = parent.getBoundingClientRect();
return {
x: childRect.left - parentRect.left,
y: childRect.top - parentRect.top,
w: childRect.width,
h: childRect.height,
};
}
} }

View File

@ -7,40 +7,60 @@ export abstract class Part {
readonly uuid: string = self.crypto.randomUUID(); readonly uuid: string = self.crypto.randomUUID();
x: number; private _x: number;
y: number; private _y: number;
w: number; private readonly _w: number;
h: number; private readonly _h: number;
protected constructor( protected constructor(
readonly type: PartType, readonly type: PartType,
readonly name: string, readonly name: string,
rasterX: number, rasterX: number,
rasterY: number, rasterY: number,
rasterW: number = 3, rasterW: number = 1,
rasterH: number = 3, rasterH: number = 1,
) { ) {
this.x = rasterX * RASTER; this._x = rasterX * 3 * RASTER;
this.y = rasterY * RASTER; this._y = rasterY * 3 * RASTER;
this.w = rasterW * RASTER; this._w = rasterW * 3 * RASTER;
this.h = rasterH * RASTER; this._h = rasterH * 3 * RASTER;
} }
abstract get junctions(): Junction[]; abstract get junctions(): Junction[];
get x(): number {
return this._x;
}
get y(): number {
return this._y;
}
get w(): number {
return this._w;
}
get h(): number {
return this._h;
}
set rasterCenterX(rx: number) {
this._x = rx * RASTER - this._w / 2;
}
set rasterCenterY(ry: number) {
this._y = ry * RASTER - this._h / 2;
}
toString(): string { toString(): string {
return this.name; return this.name;
} }
set rasterCenterX(rx: number) { updateJunctionPositions() {
this.x = rx * RASTER - this.w / 2; this.junctions.forEach(junction => junction.updatePosition());
}
set rasterCenterY(ry: number) {
this.y = ry * RASTER - this.h / 2;
} }
} }

View File

@ -0,0 +1,6 @@
export function selectTowardsRoot(element: HTMLElement | null, parentSelector: string): HTMLElement | null {
while (!!element && !element.matches(parentSelector)) {
element = element.parentElement || null;
}
return element;
}