UNPKG

@teachinglab/omd

Version:

omd

200 lines (167 loc) 6.96 kB
import { omdColor } from "./omdColor.js"; import { jsvgGroup, jsvgLine, jsvgEllipse, jsvgRect, jsvgTextBox } from "@teachinglab/jsvg"; export class omdBalanceHanger extends jsvgGroup { constructor() { // initialization super(); this.type = "omdBalanceHanger"; this.leftValues = []; this.rightValues = []; this.tilt = "none"; this.fontFamily = "Albert Sans"; this.fontSize = 18; // Background customization properties this.backgroundColor = omdColor.lightGray; this.backgroundCornerRadius = 5; this.backgroundOpacity = 1.0; this.showBackground = true; this.updateLayout(); } loadFromJSON( data ) { if ( typeof data.leftValues != "undefined" ) this.leftValues = data.leftValues; if ( typeof data.rightValues != "undefined" ) this.rightValues = data.rightValues; if ( typeof data.tilt != "undefined" ) this.tilt = data.tilt; if ( typeof data.fontFamily != "undefined" ) this.fontFamily = data.fontFamily; if ( typeof data.fontSize != "undefined" ) this.fontSize = data.fontSize; // Load background customization properties if ( typeof data.backgroundColor != "undefined" ) this.backgroundColor = data.backgroundColor; if ( typeof data.backgroundCornerRadius != "undefined" ) this.backgroundCornerRadius = data.backgroundCornerRadius; if ( typeof data.backgroundOpacity != "undefined" ) this.backgroundOpacity = data.backgroundOpacity; if ( typeof data.showBackground != "undefined" ) this.showBackground = data.showBackground; this.updateLayout(); } setLeftAndRightValues( leftValues, rightValues ) { this.leftValues = leftValues; this.rightValues = rightValues; } updateLayout() { this.removeAllChildren(); // Calculate actual content dimensions var maxValues = Math.max(this.leftValues.length, this.rightValues.length); var bX = 50; // Half beam width var bY = 0; if ( this.tilt == "left" ) bY = -10; if ( this.tilt == "right" ) bY = 10; var slackOnTop = 20; var valueStackHeight = maxValues > 0 ? (maxValues - 1) * 40 + 30 : 0; // Height of value stacks // Calculate the actual content bounds var contentWidth = bX * 2; // Total beam width var contentHeight = Math.abs(bY) + slackOnTop + valueStackHeight; // make line (centered at origin) this.line = new jsvgLine(); this.line.setStrokeColor( "black" ); this.line.setStrokeWidth( 1 ); this.line.setEndpoints( -bX, bY, bX, -bY ); this.addChild( this.line ); // left line var leftLine = new jsvgLine(); leftLine.setStrokeColor( "black" ); leftLine.setStrokeWidth( 1 ); leftLine.setEndpoints( -bX, bY, -bX, bY + slackOnTop + 40*(this.leftValues.length-1) ); this.addChild( leftLine ); // right line var right = new jsvgLine(); right.setStrokeColor( "black" ); right.setStrokeWidth( 1 ); right.setEndpoints( bX, -bY, bX, -bY + slackOnTop + 40*(this.rightValues.length-1) ); this.addChild( right ); // center dot (centered at origin) var dot = new jsvgEllipse(); dot.setWidthAndHeight( 10, 10 ); dot.setFillColor( "black" ); dot.setPosition( 0, 0 ); // Ellipse is centered at its transform; origin aligns with beam midpoint this.addChild( dot ); this.makeValueStack( this.leftValues, -bX, bY + slackOnTop ); this.makeValueStack( this.rightValues, bX, -bY + slackOnTop ); // Choose a comfortable display size and center the view on origin const padding = 40; const displayWidth = Math.max(300, contentWidth + padding); const displayHeight = Math.max(200, contentHeight + padding); this.setWidthAndHeight(displayWidth, displayHeight); this.svgObject.setAttribute("viewBox", `${-displayWidth/2} ${-displayHeight/2} ${displayWidth} ${displayHeight}`); // Don't set position since the viewBox already handles centering // this.setPosition(-displayWidth / 2, -displayHeight / 2); } makeValueStack( values, xOffset, yOffset ) { // make boxes on each side for( var i=0; i<values.length; i++ ) { // get value var value = values[i]; var W = 30; if ( typeof value == "string" ) { W = 20 + value.length*10; } else { W = 30; } // make box var box; if ( typeof value == "string" ) { box = new jsvgEllipse(); box.setWidthAndHeight( W, 30 ); box.setPosition( xOffset-W/2 + W/2, yOffset + i*40 + 15); } else { box = new jsvgRect(); box.setWidthAndHeight( W, 30 ); box.setCornerRadius(5); box.setPosition( xOffset-W/2, yOffset + i*40 ); } // Apply customizable background properties if (this.showBackground) { box.setFillColor(this.backgroundColor); if (this.backgroundOpacity < 1.0) { box.setOpacity(this.backgroundOpacity); } } else { box.setFillColor("transparent"); } // Only apply corner radius to rectangular boxes (jsvgRect), not ellipses if (this.backgroundCornerRadius > 0 && box.setCornerRadius) { box.setCornerRadius(this.backgroundCornerRadius); } this.addChild( box ); // make box text var boxText = new jsvgTextBox(); boxText.setWidthAndHeight( W,30 ); boxText.setText ( this.name ); boxText.setFontFamily( this.fontFamily ); boxText.setFontColor( "black" ); boxText.setFontSize( this.fontSize ); boxText.setAlignment("center"); boxText.setVerticalCentering(); boxText.setText( value ); boxText.setPosition( xOffset-W/2, yOffset + i*40 ); this.addChild( boxText ); } } setFont( fontFamily, fontSize ) { this.fontFamily = fontFamily; if ( fontSize ) this.fontSize = fontSize; this.updateLayout(); } }