@teachinglab/omd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/README.md +138 -0
  2. package/canvas/core/canvasConfig.js +203 -0
  3. package/canvas/core/omdCanvas.js +475 -0
  4. package/canvas/drawing/segment.js +168 -0
  5. package/canvas/drawing/stroke.js +386 -0
  6. package/canvas/events/eventManager.js +435 -0
  7. package/canvas/events/pointerEventHandler.js +263 -0
  8. package/canvas/features/focusFrameManager.js +287 -0
  9. package/canvas/index.js +49 -0
  10. package/canvas/tools/eraserTool.js +322 -0
  11. package/canvas/tools/pencilTool.js +319 -0
  12. package/canvas/tools/selectTool.js +457 -0
  13. package/canvas/tools/tool.js +223 -0
  14. package/canvas/tools/toolManager.js +394 -0
  15. package/canvas/ui/cursor.js +438 -0
  16. package/canvas/ui/toolbar.js +304 -0
  17. package/canvas/utils/boundingBox.js +378 -0
  18. package/canvas/utils/mathUtils.js +259 -0
  19. package/docs/api/configuration-options.md +104 -0
  20. package/docs/api/eventManager.md +68 -0
  21. package/docs/api/focusFrameManager.md +150 -0
  22. package/docs/api/index.md +91 -0
  23. package/docs/api/main.md +58 -0
  24. package/docs/api/omdBinaryExpressionNode.md +227 -0
  25. package/docs/api/omdCanvas.md +142 -0
  26. package/docs/api/omdConfigManager.md +192 -0
  27. package/docs/api/omdConstantNode.md +117 -0
  28. package/docs/api/omdDisplay.md +121 -0
  29. package/docs/api/omdEquationNode.md +161 -0
  30. package/docs/api/omdEquationSequenceNode.md +301 -0
  31. package/docs/api/omdEquationStack.md +139 -0
  32. package/docs/api/omdFunctionNode.md +141 -0
  33. package/docs/api/omdGroupNode.md +182 -0
  34. package/docs/api/omdHelpers.md +96 -0
  35. package/docs/api/omdLeafNode.md +163 -0
  36. package/docs/api/omdNode.md +101 -0
  37. package/docs/api/omdOperationDisplayNode.md +139 -0
  38. package/docs/api/omdOperatorNode.md +127 -0
  39. package/docs/api/omdParenthesisNode.md +122 -0
  40. package/docs/api/omdPopup.md +117 -0
  41. package/docs/api/omdPowerNode.md +127 -0
  42. package/docs/api/omdRationalNode.md +128 -0
  43. package/docs/api/omdSequenceNode.md +128 -0
  44. package/docs/api/omdSimplification.md +110 -0
  45. package/docs/api/omdSqrtNode.md +79 -0
  46. package/docs/api/omdStepVisualizer.md +115 -0
  47. package/docs/api/omdStepVisualizerHighlighting.md +61 -0
  48. package/docs/api/omdStepVisualizerInteractiveSteps.md +129 -0
  49. package/docs/api/omdStepVisualizerLayout.md +60 -0
  50. package/docs/api/omdStepVisualizerNodeUtils.md +140 -0
  51. package/docs/api/omdStepVisualizerTextBoxes.md +68 -0
  52. package/docs/api/omdToolbar.md +102 -0
  53. package/docs/api/omdTranscriptionService.md +76 -0
  54. package/docs/api/omdTreeDiff.md +134 -0
  55. package/docs/api/omdUnaryExpressionNode.md +174 -0
  56. package/docs/api/omdUtilities.md +70 -0
  57. package/docs/api/omdVariableNode.md +148 -0
  58. package/docs/api/selectTool.md +74 -0
  59. package/docs/api/simplificationEngine.md +98 -0
  60. package/docs/api/simplificationRules.md +77 -0
  61. package/docs/api/simplificationUtils.md +64 -0
  62. package/docs/api/transcribe.md +43 -0
  63. package/docs/api-reference.md +85 -0
  64. package/docs/index.html +454 -0
  65. package/docs/user-guide.md +9 -0
  66. package/index.js +67 -0
  67. package/omd/config/omdConfigManager.js +267 -0
  68. package/omd/core/index.js +150 -0
  69. package/omd/core/omdEquationStack.js +347 -0
  70. package/omd/core/omdUtilities.js +115 -0
  71. package/omd/display/omdDisplay.js +443 -0
  72. package/omd/display/omdToolbar.js +502 -0
  73. package/omd/nodes/omdBinaryExpressionNode.js +460 -0
  74. package/omd/nodes/omdConstantNode.js +142 -0
  75. package/omd/nodes/omdEquationNode.js +1223 -0
  76. package/omd/nodes/omdEquationSequenceNode.js +1273 -0
  77. package/omd/nodes/omdFunctionNode.js +352 -0
  78. package/omd/nodes/omdGroupNode.js +68 -0
  79. package/omd/nodes/omdLeafNode.js +77 -0
  80. package/omd/nodes/omdNode.js +557 -0
  81. package/omd/nodes/omdOperationDisplayNode.js +322 -0
  82. package/omd/nodes/omdOperatorNode.js +109 -0
  83. package/omd/nodes/omdParenthesisNode.js +293 -0
  84. package/omd/nodes/omdPowerNode.js +236 -0
  85. package/omd/nodes/omdRationalNode.js +295 -0
  86. package/omd/nodes/omdSqrtNode.js +308 -0
  87. package/omd/nodes/omdUnaryExpressionNode.js +178 -0
  88. package/omd/nodes/omdVariableNode.js +123 -0
  89. package/omd/simplification/omdSimplification.js +171 -0
  90. package/omd/simplification/omdSimplificationEngine.js +886 -0
  91. package/omd/simplification/package.json +6 -0
  92. package/omd/simplification/rules/binaryRules.js +1037 -0
  93. package/omd/simplification/rules/functionRules.js +111 -0
  94. package/omd/simplification/rules/index.js +48 -0
  95. package/omd/simplification/rules/parenthesisRules.js +19 -0
  96. package/omd/simplification/rules/powerRules.js +143 -0
  97. package/omd/simplification/rules/rationalRules.js +475 -0
  98. package/omd/simplification/rules/sqrtRules.js +48 -0
  99. package/omd/simplification/rules/unaryRules.js +37 -0
  100. package/omd/simplification/simplificationRules.js +32 -0
  101. package/omd/simplification/simplificationUtils.js +1056 -0
  102. package/omd/step-visualizer/omdStepVisualizer.js +597 -0
  103. package/omd/step-visualizer/omdStepVisualizerHighlighting.js +206 -0
  104. package/omd/step-visualizer/omdStepVisualizerLayout.js +245 -0
  105. package/omd/step-visualizer/omdStepVisualizerTextBoxes.js +163 -0
  106. package/omd/utils/omdNodeOverlay.js +638 -0
  107. package/omd/utils/omdPopup.js +1084 -0
  108. package/omd/utils/omdStepVisualizerInteractiveSteps.js +491 -0
  109. package/omd/utils/omdStepVisualizerNodeUtils.js +268 -0
  110. package/omd/utils/omdTranscriptionService.js +125 -0
  111. package/omd/utils/omdTreeDiff.js +734 -0
  112. package/package.json +46 -0
  113. package/src/index.js +62 -0
  114. package/src/json-schemas.md +109 -0
  115. package/src/omd-json-samples.js +115 -0
  116. package/src/omd.js +109 -0
  117. package/src/omdApp.js +391 -0
  118. package/src/omdAppCanvas.js +336 -0
  119. package/src/omdBalanceHanger.js +172 -0
  120. package/src/omdColor.js +13 -0
  121. package/src/omdCoordinatePlane.js +467 -0
  122. package/src/omdEquation.js +125 -0
  123. package/src/omdExpression.js +104 -0
  124. package/src/omdFunction.js +113 -0
  125. package/src/omdMetaExpression.js +287 -0
  126. package/src/omdNaturalExpression.js +564 -0
  127. package/src/omdNode.js +384 -0
  128. package/src/omdNumber.js +53 -0
  129. package/src/omdNumberLine.js +107 -0
  130. package/src/omdNumberTile.js +119 -0
  131. package/src/omdOperator.js +73 -0
  132. package/src/omdPowerExpression.js +92 -0
  133. package/src/omdProblem.js +55 -0
  134. package/src/omdRatioChart.js +232 -0
  135. package/src/omdRationalExpression.js +115 -0
  136. package/src/omdSampleData.js +215 -0
  137. package/src/omdShapes.js +476 -0
  138. package/src/omdSpinner.js +148 -0
  139. package/src/omdString.js +39 -0
  140. package/src/omdTable.js +369 -0
  141. package/src/omdTapeDiagram.js +245 -0
  142. package/src/omdTerm.js +92 -0
  143. package/src/omdTileEquation.js +349 -0
  144. package/src/omdVariable.js +51 -0
@@ -0,0 +1,336 @@
1
+
2
+ import { omdColor } from "./omdColor.js";
3
+ import { omdNumber } from "./omdNumber.js";
4
+ import { omdVariable } from "./omdVariable.js";
5
+ import { omdTerm } from "./omdTerm.js";
6
+ import { omdOperator } from "./omdOperator.js";
7
+ import { omdExpression } from "./omdExpression.js";
8
+ import { omdPowerExpression } from "./omdPowerExpression.js";
9
+ import { omdRationalExpression } from "./omdRationalExpression.js";
10
+ import { omdEquation } from "./omdEquation.js";
11
+ import { omdFunction } from "./omdFunction.js";
12
+ import { omdNumberLine } from "./omdNumberLine.js";
13
+ import { omdTapeDiagram } from "./omdTapeDiagram.js";
14
+ import { omdBalanceHanger } from "./omdBalanceHanger.js";
15
+ import { omdNumberTile } from "./omdNumberTile.js";
16
+ import { omdRatioChart } from "./omdRatioChart.js";
17
+ import { omdCoordinatePlane } from "./omdCoordinatePlane.js";
18
+ import { omdSpinner } from "./omdSpinner.js";
19
+ import { omdRightTriangle } from "./omdShapes.js";
20
+ import { omdIsoscelesTriangle } from "./omdShapes.js";
21
+ import { omdRectangle } from "./omdShapes.js";
22
+ import { omdEllipse } from "./omdShapes.js";
23
+ import { omdCircle } from "./omdShapes.js";
24
+ import { omdRegularPolygon } from "./omdShapes.js";
25
+ import { omdProblem } from "./omdProblem.js";
26
+ import { jsvgGroup, jsvgTextBox, jsvgTextArea, jsvgButton, jsvgEllipse } from "@teachinglab/jsvg";
27
+
28
+ export class omdAppCanvas extends jsvgGroup
29
+ {
30
+ constructor()
31
+ {
32
+ // initialization
33
+ super();
34
+
35
+ console.log("canvas!!!");
36
+
37
+ window.theApp = this;
38
+
39
+ window.addEventListener("resize", this.onResize.bind(this) );
40
+ window.addEventListener("keydown", this.onKeydown.bind(this) );
41
+
42
+ // upward shift
43
+ this.setPosition( 0, -50 );
44
+
45
+ // AI stuff
46
+ this.inputField = new jsvgTextArea();
47
+ this.inputField.setPlaceholderText( "please enter your request here" );
48
+ this.inputField.setWidthAndHeight( 600, 100 );
49
+ this.inputField.setPosition( 100, 100 );
50
+ this.inputField.setFontFamily( "Albert Sans" );
51
+ this.inputField.setFontColor( "black" );
52
+ this.inputField.setFontSize( 18 );
53
+ this.inputField.div.style.backgroundColor = "#FFDD00"; //omdColor.lightGray;
54
+ this.inputField.div.style.border = "0px";
55
+ this.inputField.div.style.padding = "10px";
56
+ this.addChild( this.inputField );
57
+
58
+ this.inputButton = new jsvgButton();
59
+ this.inputButton.setText( "submit" );
60
+ this.inputButton.setFillColor( omdColor.lightGray );
61
+ this.inputButton.setPosition( 100, 220 );
62
+ this.inputButton.setClickCallback( this.handleSubmitClick.bind(this) );
63
+ this.addChild( this.inputButton );
64
+
65
+ this.responseText = new jsvgTextBox();
66
+ this.responseText.setText("");
67
+ this.responseText.setWidthAndHeight( 400, 30 );
68
+ this.responseText.setPosition( 100, 260 );
69
+ this.responseText.setFontFamily( "Albert Sans" );
70
+ this.responseText.setFontColor( omdColor.darkGray );
71
+ this.responseText.setFontSize( 14 );
72
+ this.addChild( this.responseText );
73
+
74
+ this.AIholder = new jsvgGroup();
75
+ this.AIholder.setPosition( 100, 350 );
76
+ this.addChild( this.AIholder );
77
+
78
+ // resize
79
+ this.onResize();
80
+ }
81
+
82
+ onKeydown( event )
83
+ {
84
+ }
85
+
86
+ update()
87
+ {
88
+ super.update();
89
+
90
+ window.equatorScale = 1.5;
91
+ }
92
+
93
+ onResize()
94
+ {
95
+ }
96
+
97
+ handleSubmitClick( B )
98
+ {
99
+ this.responseText.setText( "working..." );
100
+
101
+ var text = this.inputField.getText();
102
+ console.log( text );
103
+ this.fetchAI( text );
104
+ }
105
+
106
+ handleAIResponse( jsonData )
107
+ {
108
+ var N = null;
109
+
110
+ if ( jsonData.omdType == "number" ) { var N = new omdNumber(); }
111
+
112
+ if ( jsonData.omdType == "variable" ) { var N = new omdVariable(); }
113
+
114
+ if ( jsonData.omdType == "operator" ) { var N = new omdOperator(); }
115
+
116
+ if ( jsonData.omdType == "term" ) { var N = new omdTerm(); }
117
+
118
+ if ( jsonData.omdType == "expression" ) { var N = new omdExpression(); }
119
+
120
+ if ( jsonData.omdType == "powerExpression" ) { var N = new omdPowerExpression(); }
121
+
122
+ if ( jsonData.omdType == "rationalExpression" ) { var N = new omdRationalExpression(); }
123
+
124
+ if ( jsonData.omdType == "function" ) { var N = new omdFunction(); }
125
+
126
+ if ( jsonData.omdType == "equation" ) { var N = new omdEquation(); }
127
+
128
+ if ( jsonData.omdType == "numberLine" ) { var N = new omdNumberLine(); }
129
+
130
+ if ( jsonData.omdType == "balanceHanger" )
131
+ {
132
+ var N = new omdBalanceHanger();
133
+ N.setPosition( 150, 0 );
134
+ }
135
+
136
+ if ( jsonData.omdType == "tapeDiagram" ) { var N = new omdTapeDiagram(); }
137
+
138
+ if ( jsonData.omdType == "numberTile" ) { var N = new omdNumberTile(); }
139
+
140
+ if ( jsonData.omdType == "ratioChart" ) { var N = new omdRatioChart(); }
141
+
142
+ if ( jsonData.omdType == "coordinatePlane" ) { var N = new omdCoordinatePlane(); }
143
+
144
+ if ( jsonData.omdType == "spinner" ) { var N = new omdSpinner(); }
145
+
146
+ if ( jsonData.omdType == "rightTriangle" ) { var N = new omdRightTriangle(); }
147
+
148
+ if ( jsonData.omdType == "isoscelesTriangle" ) { var N = new omdIsoscelesTriangle(); }
149
+
150
+ if ( jsonData.omdType == "rectangle" ) { var N = new omdRectangle(); }
151
+
152
+ if ( jsonData.omdType == "ellipse" ) { var N = new omdEllipse(); }
153
+
154
+ if ( jsonData.omdType == "circle" ) { var N = new omdCircle(); }
155
+
156
+ if ( jsonData.omdType == "regularPolygon" ) { var N = new omdRegularPolygon(); }
157
+
158
+ if ( jsonData.omdType == "problem" ) { var N = new omdProblem(); }
159
+
160
+ // load from json
161
+ N.loadFromJSON( jsonData );
162
+
163
+ // add to the AI holder
164
+ var E = new omdCanvasEntry();
165
+ E.addObject( N );
166
+ this.AIholder.addChild( E );
167
+ return E;
168
+ }
169
+
170
+ fetchAI( topic )
171
+ {
172
+ // console.log( "=== fetchAI ===" );
173
+ // console.log( topic );
174
+
175
+ // consturct url based on topic
176
+ var urlToFetch = "";
177
+ if ( window.location.hostname.includes("localhost") )
178
+ urlToFetch = "http://localhost:8888/.netlify/functions/ai-omd-lookup/";
179
+ else
180
+ urlToFetch = "https://teaching-lab-omd.netlify.app/.netlify/functions/ai-omd-lookup/";
181
+
182
+ // add topic
183
+ urlToFetch += "?topic='" + topic + "'";
184
+ // console.log( "URL: " + urlToFetch );
185
+
186
+ // fetch the data
187
+ fetch( urlToFetch )
188
+ .then((response) => response.text())
189
+ .then((body) => {
190
+
191
+ // console.log("==== raw data ======");
192
+ // console.log( body );
193
+
194
+ // console.log("==== preParseData ======");
195
+ var preParseData = body;
196
+ preParseData = preParseData.replaceAll( "`", "" );
197
+ preParseData = preParseData.replaceAll( "json", "" );
198
+ console.log( "=== pre-parse ===" );
199
+ console.log( preParseData );
200
+
201
+ try
202
+ {
203
+ var data = JSON.parse( preParseData );
204
+ console.log( "=== parsedData ===" );
205
+ console.log( data );
206
+
207
+ this.responseText.setText( "" );
208
+ this.handleAIResponse( data );
209
+ }
210
+ catch
211
+ {
212
+ // if parsing failed, try again
213
+ console.log( preParseData );
214
+ console.log(">>> data not parse-able");
215
+ this.responseText.setText( "An error occured. Please try again." );
216
+ }
217
+ });
218
+ }
219
+
220
+ }
221
+
222
+
223
+ class omdCanvasEntry extends jsvgGroup
224
+ {
225
+ constructor()
226
+ {
227
+ // initialization
228
+ super();
229
+
230
+ this.clickRect = new jsvgEllipse();
231
+ this.clickRect.setWidthAndHeight( 40,40 );
232
+ this.clickRect.setPosition( 10,10 );
233
+ this.clickRect.setFillColor( "transparent" );
234
+ this.addChild( this.clickRect );
235
+
236
+ this.clickRect.svgObject.onmousedown = this.handleMouseDown.bind( this );
237
+ this.clickRect.svgObject.ontouchstart = this.handleMouseDown.bind( this );
238
+ this.clickRect.svgObject.style.cursor = "pointer";
239
+
240
+ this.backRect = new jsvgEllipse();
241
+ this.backRect.setWidthAndHeight( 20,20 );
242
+ this.backRect.setPosition( 10,10 );
243
+ this.backRect.setFillColor( "#DDDDDD" );
244
+ this.addChild( this.backRect );
245
+
246
+ this.backRect.svgObject.onmousedown = this.handleMouseDown.bind( this );
247
+ this.backRect.svgObject.ontouchstart = this.handleMouseDown.bind( this );
248
+ this.backRect.svgObject.style.cursor = "pointer";
249
+ }
250
+
251
+ addObject( obj )
252
+ {
253
+ this.theObject = obj;
254
+ obj.setPosition( 10,10 );
255
+ this.addChild( obj );
256
+
257
+ //var W = this.theObject.width;
258
+ //var H = this.theObject.height;
259
+ //this.backRect.setWidthAndHeight( W+20,H+20 );
260
+ //this.backRect.setWidthAndHeight( 20,20 );
261
+ }
262
+
263
+ handleMouseDown( event )
264
+ {
265
+ if ( ! this.visible )
266
+ return;
267
+
268
+ // select
269
+ // window.theApp.setActiveEntry( this );
270
+
271
+ // handle dragging
272
+ function handleMouseMove(event)
273
+ {
274
+ event.preventDefault();
275
+
276
+ // get mouseX and mouseY
277
+ var mouseX, mouseY;
278
+ if ( event.touches && event.touches.length >= 1 )
279
+ {
280
+ mouseX = event.touches[0].clientX;
281
+ mouseY = event.touches[0].clientY;
282
+ }
283
+ else
284
+ {
285
+ mouseX = event.clientX;
286
+ mouseY = event.clientY;
287
+ }
288
+
289
+ // calculate dX and dY
290
+ if ( this.oldMouseX && this.oldMouseY )
291
+ {
292
+ var dX = mouseX - this.oldMouseX;
293
+ var dY = mouseY - this.oldMouseY;
294
+
295
+ // dX /= window.dragScale; // adjust for drag scale
296
+ // dY /= window.dragScale; // adjust for drag scale
297
+
298
+ var pX = this.xpos + dX;
299
+ var pY = this.ypos + dY;
300
+
301
+ // move the circle
302
+ this.setPosition( pX, pY );
303
+ }
304
+
305
+ // set oldMouseX and oldMouseY
306
+ this.oldMouseX = mouseX;
307
+ this.oldMouseY = mouseY;
308
+ }
309
+
310
+ // on mouse up
311
+ function handleMouseUp(event)
312
+ {
313
+ // set active dot
314
+ // window.theApp.setActiveEntry( this ); // this forces an update to the detail panel
315
+
316
+ // update data in firebase
317
+ // this.updateEntryInDatabase();
318
+
319
+ // console.log("handleMouseUp");
320
+ // this.activeDot = null;
321
+ window.onmousemove = null;
322
+ window.ontouchmove = null;
323
+ window.onmouseup = null;
324
+ window.ontouchend = null;
325
+ this.oldMouseX = 0;
326
+ this.oldMouseY = 0;
327
+
328
+ // this.dotHilite.hide();
329
+ }
330
+
331
+ window.onmousemove = handleMouseMove.bind(this);
332
+ window.ontouchmove = handleMouseMove.bind(this);;
333
+ window.onmouseup = handleMouseUp.bind(this);
334
+ window.ontouchend = handleMouseUp.bind(this);;
335
+ }
336
+ }
@@ -0,0 +1,172 @@
1
+
2
+ import { omdColor } from "./omdColor.js";
3
+ import { jsvgGroup, jsvgLine, jsvgEllipse, jsvgRect } from "@teachinglab/jsvg";
4
+
5
+ export class omdBalanceHanger extends jsvgGroup
6
+ {
7
+ constructor()
8
+ {
9
+ // initialization
10
+ super();
11
+
12
+ this.type = "omdBalanceHanger";
13
+
14
+ this.leftValues = [];
15
+ this.rightValues = [];
16
+ this.tilt = "none";
17
+ this.fontFamily = "Albert Sans";
18
+ this.fontSize = 18;
19
+
20
+ this.updateLayout();
21
+ }
22
+
23
+ loadFromJSON( data )
24
+ {
25
+ if ( typeof data.leftValues != "undefined" )
26
+ this.leftValues = data.leftValues;
27
+
28
+ if ( typeof data.rightValues != "undefined" )
29
+ this.rightValues = data.rightValues;
30
+
31
+ if ( typeof data.tilt != "undefined" )
32
+ this.tilt = data.tilt;
33
+
34
+ if ( typeof data.fontFamily != "undefined" )
35
+ this.fontFamily = data.fontFamily;
36
+
37
+ if ( typeof data.fontSize != "undefined" )
38
+ this.fontSize = data.fontSize;
39
+
40
+ this.updateLayout();
41
+ }
42
+
43
+ setLeftAndRightValues( leftValues, rightValues )
44
+ {
45
+ this.leftValues = leftValues;
46
+ this.rightValues = rightValues;
47
+ }
48
+
49
+ updateLayout()
50
+ {
51
+ this.removeAllChildren();
52
+
53
+ // Calculate actual content dimensions
54
+ var maxValues = Math.max(this.leftValues.length, this.rightValues.length);
55
+ var bX = 50; // Half beam width
56
+ var bY = 0;
57
+
58
+ if ( this.tilt == "left" )
59
+ bY = -10;
60
+ if ( this.tilt == "right" )
61
+ bY = 10;
62
+
63
+ var slackOnTop = 20;
64
+ var valueStackHeight = maxValues > 0 ? (maxValues - 1) * 40 + 30 : 0; // Height of value stacks
65
+
66
+ // Calculate the actual content bounds
67
+ var contentWidth = bX * 2; // Total beam width
68
+ var contentHeight = Math.abs(bY) + slackOnTop + valueStackHeight;
69
+
70
+ // make line (centered at origin)
71
+ this.line = new jsvgLine();
72
+ this.line.setStrokeColor( "black" );
73
+ this.line.setStrokeWidth( 1 );
74
+ this.line.setEndpoints( -bX, bY, bX, -bY );
75
+ this.addChild( this.line );
76
+
77
+ // left line
78
+ var leftLine = new jsvgLine();
79
+ leftLine.setStrokeColor( "black" );
80
+ leftLine.setStrokeWidth( 1 );
81
+ leftLine.setEndpoints( -bX, bY, -bX, bY + slackOnTop + 40*(this.leftValues.length-1) );
82
+ this.addChild( leftLine );
83
+
84
+ // right line
85
+ var right = new jsvgLine();
86
+ right.setStrokeColor( "black" );
87
+ right.setStrokeWidth( 1 );
88
+ right.setEndpoints( bX, -bY, bX, -bY + slackOnTop + 40*(this.rightValues.length-1) );
89
+ this.addChild( right );
90
+
91
+ // center dot (centered at origin)
92
+ var dot = new jsvgEllipse();
93
+ dot.setWidthAndHeight( 10, 10 );
94
+ dot.setFillColor( "black" );
95
+ dot.setPosition( 0, 0 ); // Ellipse is centered at its transform; origin aligns with beam midpoint
96
+ this.addChild( dot );
97
+
98
+ this.makeValueStack( this.leftValues, -bX, bY + slackOnTop );
99
+ this.makeValueStack( this.rightValues, bX, -bY + slackOnTop );
100
+
101
+ // Choose a comfortable display size and center the view on origin
102
+ const padding = 40;
103
+ const displayWidth = Math.max(300, contentWidth + padding);
104
+ const displayHeight = Math.max(200, contentHeight + padding);
105
+ this.setWidthAndHeight(displayWidth, displayHeight);
106
+ // Store desired viewBox on the group so the wrapper <svg> can use it
107
+ // Centered on (0,0) to accommodate negative/positive coordinates used above
108
+ this.svgObject.setAttribute("viewBox", `${-displayWidth/2} ${-displayHeight/2} ${displayWidth} ${displayHeight}`);
109
+ // Ensure no extra offset; content already drawn around origin
110
+ this.setPosition(0, 0);
111
+ }
112
+
113
+ makeValueStack( values, xOffset, yOffset )
114
+ {
115
+ // make boxes on each side
116
+ for( var i=0; i<values.length; i++ )
117
+ {
118
+ // get value
119
+ var value = values[i];
120
+ var W = 30;
121
+ if ( typeof value == "string" )
122
+ {
123
+ W = 20 + value.length*10;
124
+ }
125
+ else
126
+ {
127
+ W = 30;
128
+ }
129
+
130
+ // make box
131
+ var box;
132
+ if ( typeof value == "string" )
133
+ {
134
+ box = new jsvgEllipse();
135
+ box.setWidthAndHeight( W, 30 );
136
+ box.setPosition( xOffset-W/2 + W/2, yOffset + i*40 + 15);
137
+ }
138
+ else
139
+ {
140
+ box = new jsvgRect();
141
+ box.setWidthAndHeight( W, 30 );
142
+ box.setCornerRadius(5);
143
+ box.setPosition( xOffset-W/2, yOffset + i*40 );
144
+ }
145
+ box.setFillColor( omdColor.lightGray );
146
+
147
+ this.addChild( box );
148
+
149
+ // make box text
150
+ var boxText = new jsvgTextBox();
151
+ boxText.setWidthAndHeight( W,30 );
152
+ boxText.setText ( this.name );
153
+ boxText.setFontFamily( this.fontFamily );
154
+ boxText.setFontColor( "black" );
155
+ boxText.setFontSize( this.fontSize );
156
+ boxText.setAlignment("center");
157
+ boxText.setVerticalCentering();
158
+ boxText.setText( value );
159
+ boxText.setPosition( xOffset-W/2, yOffset + i*40 );
160
+ this.addChild( boxText );
161
+ }
162
+ }
163
+
164
+ setFont( fontFamily, fontSize )
165
+ {
166
+ this.fontFamily = fontFamily;
167
+ if ( fontSize )
168
+ this.fontSize = fontSize;
169
+ this.updateLayout();
170
+ }
171
+
172
+ }
@@ -0,0 +1,13 @@
1
+
2
+ export var omdColor =
3
+ {
4
+ lightGray : '#EEEEEE',
5
+ mediumGray : '#DDDDDD',
6
+ darkGray : '#AAAAAA',
7
+ hiliteColor : '#FF69B4',
8
+ stepColor: "#9FDAFF",
9
+ explainColor: "#FFD9B3",
10
+ red: '#DB2323',
11
+ green: '#6FDE29',
12
+ blue: '#2386DB',
13
+ }