UNPKG

@teachinglab/omd

Version:

omd

116 lines (90 loc) 4.09 kB
import { jsvgGroup } from "@teachinglab/jsvg"; import { omdTapeDiagram } from "./omdTapeDiagram.js"; export class omdDoubleTapeDiagram extends jsvgGroup { constructor() { // initialization super(); this.type = "omdDoubleTapeDiagram"; this.topTapeDiagram = new omdTapeDiagram(); this.bottomTapeDiagram = new omdTapeDiagram(); this.spacing = 30; this.updateLayout(); } loadFromJSON( data ) { // Load spacing first, before updating layout if ( typeof data.spacing !== "undefined" ) { this.spacing = data.spacing; } if ( typeof data.topTapeDiagram !== "undefined" ) { this.topTapeDiagram.loadFromJSON(data.topTapeDiagram); } if ( typeof data.bottomTapeDiagram !== "undefined" ) { this.bottomTapeDiagram.loadFromJSON(data.bottomTapeDiagram); } this.updateLayout(); } updateLayout() { this.removeAllChildren(); // Calculate total numeric values for both tapes to determine unit width const topTotal = this.calculateTotalValue(this.topTapeDiagram); const bottomTotal = this.calculateTotalValue(this.bottomTapeDiagram); // Find the maximum total to determine a consistent unit width const maxTotal = Math.max(topTotal, bottomTotal); const baseWidth = 300; // Base width for the longest tape const unitWidth = maxTotal > 0 ? baseWidth / maxTotal : baseWidth; // Set each tape's width based on its total value this.topTapeDiagram.totalWidth = topTotal * unitWidth; this.bottomTapeDiagram.totalWidth = bottomTotal * unitWidth; // Force update of both tape diagrams with new widths this.topTapeDiagram.updateLayout(); this.bottomTapeDiagram.updateLayout(); // Calculate the maximum left padding needed to align the start of the tapes const topLeftPadding = this.topTapeDiagram.title ? 80 : 20; const bottomLeftPadding = this.bottomTapeDiagram.title ? 80 : 20; const maxLeftPadding = Math.max(topLeftPadding, bottomLeftPadding); // Position top tape diagram const topXOffset = maxLeftPadding - topLeftPadding; this.topTapeDiagram.setPosition(topXOffset, 0); this.addChild(this.topTapeDiagram); // Position bottom tape diagram // spacing controls the gap between the bottom of top tape and top of bottom tape const bottomXOffset = maxLeftPadding - bottomLeftPadding; const bottomYPosition = this.topTapeDiagram.height + this.spacing; this.bottomTapeDiagram.setPosition(bottomXOffset, bottomYPosition); this.addChild(this.bottomTapeDiagram); // Set overall dimensions const maxWidth = Math.max( this.topTapeDiagram.width + topXOffset, this.bottomTapeDiagram.width + bottomXOffset ); this.width = maxWidth; this.height = this.topTapeDiagram.height + this.spacing + this.bottomTapeDiagram.height; this.svgObject.setAttribute('viewBox', `0 0 ${this.width} ${this.height}`); } calculateTotalValue(tapeDiagram) { let total = 0; for (const valueData of tapeDiagram.values) { let value = ""; // Handle both old format (simple values) and new format (objects) if (typeof valueData === "object" && valueData !== null) { value = valueData.value || ""; } else { value = valueData.toString(); } // Parse numeric value from string (e.g., "3", "2x", "5y") const match = value.match(/^([0-9.]+)?([a-zA-Z]*)$/); if (match) { const coefficient = match[1] ? parseFloat(match[1]) : (match[2] ? 1 : 1); total += coefficient; } else { total += 1; // Default for unparseable values } } return total; } }