@teachinglab/omd 0.2.6 → 0.2.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teachinglab/omd",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "omd",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -17,6 +17,12 @@ export class omdBalanceHanger extends jsvgGroup
17
17
  this.fontFamily = "Albert Sans";
18
18
  this.fontSize = 18;
19
19
 
20
+ // Background customization properties
21
+ this.backgroundColor = omdColor.lightGray;
22
+ this.backgroundCornerRadius = 5;
23
+ this.backgroundOpacity = 1.0;
24
+ this.showBackground = true;
25
+
20
26
  this.updateLayout();
21
27
  }
22
28
 
@@ -37,6 +43,16 @@ export class omdBalanceHanger extends jsvgGroup
37
43
  if ( typeof data.fontSize != "undefined" )
38
44
  this.fontSize = data.fontSize;
39
45
 
46
+ // Load background customization properties
47
+ if ( typeof data.backgroundColor != "undefined" )
48
+ this.backgroundColor = data.backgroundColor;
49
+ if ( typeof data.backgroundCornerRadius != "undefined" )
50
+ this.backgroundCornerRadius = data.backgroundCornerRadius;
51
+ if ( typeof data.backgroundOpacity != "undefined" )
52
+ this.backgroundOpacity = data.backgroundOpacity;
53
+ if ( typeof data.showBackground != "undefined" )
54
+ this.showBackground = data.showBackground;
55
+
40
56
  this.updateLayout();
41
57
  }
42
58
 
@@ -139,7 +155,21 @@ export class omdBalanceHanger extends jsvgGroup
139
155
  box.setCornerRadius(5);
140
156
  box.setPosition( xOffset-W/2, yOffset + i*40 );
141
157
  }
142
- box.setFillColor( omdColor.lightGray );
158
+
159
+ // Apply customizable background properties
160
+ if (this.showBackground) {
161
+ box.setFillColor(this.backgroundColor);
162
+ if (this.backgroundOpacity < 1.0) {
163
+ box.setOpacity(this.backgroundOpacity);
164
+ }
165
+ } else {
166
+ box.setFillColor("transparent");
167
+ }
168
+
169
+ // Only apply corner radius to rectangular boxes (jsvgRect), not ellipses
170
+ if (this.backgroundCornerRadius > 0 && box.setCornerRadius) {
171
+ box.setCornerRadius(this.backgroundCornerRadius);
172
+ }
143
173
 
144
174
  this.addChild( box );
145
175
 
package/src/omdColor.js CHANGED
@@ -10,4 +10,5 @@ export var omdColor =
10
10
  red: '#DB2323',
11
11
  green: '#6FDE29',
12
12
  blue: '#2386DB',
13
+ white: '#FFFFFF',
13
14
  }
@@ -33,6 +33,12 @@ export class omdCoordinatePlane extends jsvgGroup {
33
33
  this.tickLabelOffsetPx = 5; //offset from axes
34
34
  this.showTickLabels = true; // show numeric tick labels
35
35
 
36
+ // Background customization properties
37
+ this.backgroundColor = omdColor.lightGray;
38
+ this.backgroundCornerRadius = 15;
39
+ this.backgroundOpacity = 1.0;
40
+ this.showBackground = true;
41
+
36
42
  this.calculatePadding();
37
43
  this.updateLayout();
38
44
  }
@@ -62,6 +68,12 @@ export class omdCoordinatePlane extends jsvgGroup {
62
68
  this.forceAllTickLabels = (data.forceAllTickLabels !== undefined) ? data.forceAllTickLabels : this.forceAllTickLabels;
63
69
  this.showTickLabels = (data.showTickLabels !== undefined) ? data.showTickLabels : this.showTickLabels;
64
70
 
71
+ // Load background customization properties
72
+ this.backgroundColor = data.backgroundColor || this.backgroundColor;
73
+ this.backgroundCornerRadius = (data.backgroundCornerRadius !== undefined) ? data.backgroundCornerRadius : this.backgroundCornerRadius;
74
+ this.backgroundOpacity = (data.backgroundOpacity !== undefined) ? data.backgroundOpacity : this.backgroundOpacity;
75
+ this.showBackground = (data.showBackground !== undefined) ? data.showBackground : this.showBackground;
76
+
65
77
  this.calculatePadding();
66
78
  this.updateLayout();
67
79
  }
@@ -80,11 +92,20 @@ export class omdCoordinatePlane extends jsvgGroup {
80
92
 
81
93
  const whiteRect = new jsvgRect();
82
94
  whiteRect.setWidthAndHeight(outerWidth, outerHeight);
83
- whiteRect.setFillColor(omdColor.lightGray);
95
+
96
+ // Apply customizable background properties
97
+ if (this.showBackground) {
98
+ whiteRect.setFillColor(this.backgroundColor);
99
+ if (this.backgroundOpacity < 1.0) {
100
+ whiteRect.setOpacity(this.backgroundOpacity);
101
+ }
102
+ } else {
103
+ whiteRect.setFillColor("transparent");
104
+ }
84
105
  whiteRect.setStrokeWidth(0);
85
106
 
86
- if (whiteRect.setCornerRadius) {
87
- whiteRect.setCornerRadius(15);
107
+ if (whiteRect.setCornerRadius && this.backgroundCornerRadius > 0) {
108
+ whiteRect.setCornerRadius(this.backgroundCornerRadius);
88
109
  }
89
110
 
90
111
  clipMask.addChild(whiteRect);
@@ -489,4 +510,33 @@ export class omdCoordinatePlane extends jsvgGroup {
489
510
  holder.addChild(shape);
490
511
  }
491
512
  }
513
+
514
+ // Background customization methods
515
+ setBackgroundColor(color) {
516
+ this.backgroundColor = color;
517
+ this.updateLayout();
518
+ }
519
+
520
+ setBackgroundCornerRadius(radius) {
521
+ this.backgroundCornerRadius = radius;
522
+ this.updateLayout();
523
+ }
524
+
525
+ setBackgroundOpacity(opacity) {
526
+ this.backgroundOpacity = Math.max(0, Math.min(1, opacity));
527
+ this.updateLayout();
528
+ }
529
+
530
+ setShowBackground(show) {
531
+ this.showBackground = show;
532
+ this.updateLayout();
533
+ }
534
+
535
+ setBackgroundStyle(options = {}) {
536
+ if (options.backgroundColor !== undefined) this.backgroundColor = options.backgroundColor;
537
+ if (options.cornerRadius !== undefined) this.backgroundCornerRadius = options.cornerRadius;
538
+ if (options.opacity !== undefined) this.backgroundOpacity = Math.max(0, Math.min(1, options.opacity));
539
+ if (options.show !== undefined) this.showBackground = options.show;
540
+ this.updateLayout();
541
+ }
492
542
  }
@@ -16,7 +16,7 @@ export class omdMetaExpression extends jsvgGroup
16
16
  this.backRect = new jsvgRect();
17
17
  this.backRect.setWidthAndHeight( 30,30 );
18
18
  this.backRect.setCornerRadius( 5 );
19
- this.backRect.setFillColor( omdColor.lightGray );
19
+ this.backRect.setFillColor( this.getBackgroundColor() );
20
20
  this.addChild( this.backRect );
21
21
 
22
22
  // Old events for selection - we will replace these with provenance highlighting
@@ -63,6 +63,10 @@ export class omdMetaExpression extends jsvgGroup
63
63
  return this.fontSize || 16;
64
64
  }
65
65
 
66
+ getBackgroundColor() {
67
+ return this._backgroundStyle?.backgroundColor ?? omdColor.lightGray;
68
+ }
69
+
66
70
  // ===== PROVENANCE HIGHLIGHTING =====
67
71
 
68
72
  highlightProvenance(event, color = omdColor.hiliteColor, minStepNumber = -Infinity) {
@@ -160,7 +164,7 @@ export class omdMetaExpression extends jsvgGroup
160
164
  this.backRect.setOpacity(1.0);
161
165
  } else {
162
166
  // Reset to default state
163
- this.backRect.setFillColor(omdColor.lightGray);
167
+ this.backRect.setFillColor(this.getBackgroundColor());
164
168
  if (!this.defaultOpaqueBack) {
165
169
  this.backRect.setOpacity(0.01);
166
170
  }
@@ -224,7 +228,7 @@ export class omdMetaExpression extends jsvgGroup
224
228
 
225
229
  if (root === this && this.parent instanceof omdMetaExpression) return;
226
230
 
227
- this.backRect.setFillColor( omdColor.lightGray );
231
+ this.backRect.setFillColor( this.getBackgroundColor() );
228
232
  if ( this.defaultOpaqueBack == false )
229
233
  this.backRect.setOpacity(0.01);
230
234
 
@@ -281,7 +285,7 @@ export class omdMetaExpression extends jsvgGroup
281
285
  this.backRect.setOpacity(0.01);
282
286
  }
283
287
 
284
- makeBackgroundLight() { this.backRect.setFillColor( omdColor.lightGray ) }
288
+ makeBackgroundLight() { this.backRect.setFillColor( this.getBackgroundColor() ) }
285
289
  makeBackgroundDark() { this.backRect.setFillColor( omdColor.mediumGray ) }
286
290
 
287
291
  }
package/src/omdTable.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { omdColor } from "./omdColor.js";
2
- import { jsvgGroup, jsvgRect, jsvgTextBox } from "@teachinglab/jsvg";
2
+ import { jsvgGroup, jsvgRect, jsvgTextBox, jsvgClipMask } from "@teachinglab/jsvg";
3
3
 
4
4
  export class omdTable extends jsvgGroup
5
5
  {
@@ -27,6 +27,22 @@ export class omdTable extends jsvgGroup
27
27
  this.maxCellWidth = 300;
28
28
  this.padding = 10;
29
29
 
30
+ // Background customization properties
31
+ this.backgroundColor = omdColor.lightGray;
32
+ this.backgroundCornerRadius = 15;
33
+ this.backgroundOpacity = 1.0;
34
+ this.showBackground = true;
35
+
36
+ // Alternating row color properties
37
+ this.alternatingRowColors = null; // Should be an array of colors or null
38
+ this.headerBackgroundColor = omdColor.lightGray;
39
+ this.cellBackgroundColor = "white";
40
+
41
+ // Legacy properties for backward compatibility
42
+ this.evenRowColor = "rgba(255,255,255,0.5)";
43
+ this.oddRowColor = "transparent";
44
+ this.alternatingRowOpacity = 1.0;
45
+
30
46
  this.updateLayout();
31
47
  }
32
48
 
@@ -92,6 +108,28 @@ export class omdTable extends jsvgGroup
92
108
  if ( typeof data.padding != "undefined" )
93
109
  this.padding = data.padding;
94
110
 
111
+ // Load background customization properties
112
+ if ( typeof data.backgroundColor != "undefined" )
113
+ this.backgroundColor = data.backgroundColor;
114
+ if ( typeof data.backgroundCornerRadius != "undefined" )
115
+ this.backgroundCornerRadius = data.backgroundCornerRadius;
116
+ if ( typeof data.backgroundOpacity != "undefined" )
117
+ this.backgroundOpacity = data.backgroundOpacity;
118
+ if ( typeof data.showBackground != "undefined" )
119
+ this.showBackground = data.showBackground;
120
+
121
+ // Load alternating row color properties
122
+ if ( typeof data.alternatingRowColors != "undefined" ) {
123
+ this.alternatingRowColors = data.alternatingRowColors;
124
+ console.log('LoadFromJSON - Setting alternatingRowColors to:', this.alternatingRowColors);
125
+ }
126
+ if ( typeof data.evenRowColor != "undefined" )
127
+ this.evenRowColor = data.evenRowColor;
128
+ if ( typeof data.oddRowColor != "undefined" )
129
+ this.oddRowColor = data.oddRowColor;
130
+ if ( typeof data.alternatingRowOpacity != "undefined" )
131
+ this.alternatingRowOpacity = data.alternatingRowOpacity;
132
+
95
133
  this.updateLayout();
96
134
  }
97
135
 
@@ -155,6 +193,10 @@ export class omdTable extends jsvgGroup
155
193
 
156
194
  updateLayout()
157
195
  {
196
+ console.log('updateLayout called - alternatingRowColors:', this.alternatingRowColors);
197
+ console.log('alternatingRowColors type:', typeof this.alternatingRowColors);
198
+ console.log('alternatingRowColors isArray:', Array.isArray(this.alternatingRowColors));
199
+
158
200
  this.removeAllChildren();
159
201
 
160
202
  // If an equation is provided, generate data before measuring/layout
@@ -182,29 +224,49 @@ export class omdTable extends jsvgGroup
182
224
  // without changing column widths or table background.
183
225
  const titleBoxWidth = this.estimateTitleWidth();
184
226
  const displayWidth = Math.max(this.width, titleBoxWidth);
185
-
186
- // Table background with corner radius (all four corners, covers full height)
187
- const tableBg = new jsvgRect();
188
- tableBg.setWidthAndHeight(this.width, bodyHeight);
189
- tableBg.setFillColor(omdColor.lightGray);
190
- tableBg.setCornerRadius(15);
191
- tableBg.setStrokeWidth(0);
192
227
  const contentOffsetX = Math.max(0, (displayWidth - this.width) / 2);
193
- tableBg.setPosition(contentOffsetX, titleOffset);
194
- this.addChild(tableBg);
195
-
196
- // Draw a rounded footer rectangle under the last row to provide bottom rounded corners
197
- if (numRows > 0) {
198
- const footer = new jsvgRect();
199
- footer.setWidthAndHeight(this.width, this.cellHeight);
200
- footer.setFillColor(omdColor.lightGray);
201
- footer.setCornerRadius(15);
202
- footer.setStrokeWidth(0);
203
- const footerY = titleOffset + this.headerHeight + (numRows - 1) * this.cellHeight;
204
- footer.setPosition(contentOffsetX, footerY);
205
- this.addChild(footer);
228
+
229
+ // Create a clipped group for rounded corners if corner radius is specified
230
+ let tableContentGroup;
231
+ if (this.backgroundCornerRadius > 0) {
232
+ // Create clip mask with rounded corners
233
+ const clipMask = new jsvgClipMask(this.width, bodyHeight, this.backgroundCornerRadius);
234
+ clipMask.setPosition(contentOffsetX, titleOffset);
235
+ this.addChild(clipMask);
236
+
237
+ // Table content will be added to the clip mask
238
+ tableContentGroup = clipMask;
239
+
240
+ // Create table background inside the clip mask (so it gets rounded corners)
241
+ if (this.showBackground) {
242
+ const tableBg = new jsvgRect();
243
+ tableBg.setWidthAndHeight(this.width, bodyHeight);
244
+ tableBg.setFillColor(this.backgroundColor);
245
+ if (this.backgroundOpacity < 1.0) {
246
+ tableBg.setOpacity(this.backgroundOpacity);
247
+ }
248
+ tableBg.setStrokeWidth(0);
249
+ tableBg.setPosition(0, 0); // Relative to clip mask
250
+ tableContentGroup.addChild(tableBg);
251
+ }
252
+ } else {
253
+ // No clipping needed, create background and use the main group
254
+ if (this.showBackground) {
255
+ const tableBg = new jsvgRect();
256
+ tableBg.setWidthAndHeight(this.width, bodyHeight);
257
+ tableBg.setFillColor(this.backgroundColor);
258
+ if (this.backgroundOpacity < 1.0) {
259
+ tableBg.setOpacity(this.backgroundOpacity);
260
+ }
261
+ tableBg.setStrokeWidth(0);
262
+ tableBg.setPosition(contentOffsetX, titleOffset);
263
+ this.addChild(tableBg);
264
+ }
265
+ tableContentGroup = this;
206
266
  }
207
267
 
268
+ // Remove the separate footer rectangle since the main background now covers everything
269
+
208
270
  // Generate data from equation if provided; otherwise assume valid data/headers
209
271
  if (this.equation && this.equation.length > 0) {
210
272
  this.generateDataFromEquation();
@@ -230,33 +292,45 @@ export class omdTable extends jsvgGroup
230
292
  currentY += 30;
231
293
  }
232
294
 
233
- // Create header row (lightGray, no border, no rounded corners for cells)
295
+ // Create header row
234
296
  let currentX = 0;
297
+ const headerY = 0; // Relative to the clipped content group
298
+
299
+ // First create a full-width header background if using alternating colors
300
+ if (this.alternatingRowColors && Array.isArray(this.alternatingRowColors) && this.alternatingRowColors.length > 0) {
301
+ console.log('Creating header background with color:', this.alternatingRowColors[0]);
302
+ const headerBg = new jsvgRect();
303
+ headerBg.setWidthAndHeight(this.width, this.headerHeight);
304
+ headerBg.setFillColor(this.alternatingRowColors[0]); // Headers use first color
305
+ headerBg.setCornerRadius(0);
306
+ headerBg.setStrokeWidth(0);
307
+ headerBg.setPosition(0, headerY);
308
+ tableContentGroup.addChild(headerBg);
309
+ } else {
310
+ console.log('NOT creating header background - alternatingRowColors:', this.alternatingRowColors);
311
+ }
312
+
235
313
  for (let col = 0; col < numCols; col++) {
236
314
  const cellWidth = cellWidths[col];
237
- var headerRect = new jsvgRect();
238
- headerRect.setWidthAndHeight(cellWidth, this.headerHeight);
239
- headerRect.setFillColor(omdColor.lightGray);
240
- // Use rx/ry for top corners only on first and last header cells
241
- if (col === 0 && numCols === 1) {
242
- headerRect.setCornerRadius(15); // single column, round all corners
243
- } else if (col === 0) {
244
- headerRect.setCornerRadius(15); // round top-left
245
- } else if (col === numCols - 1) {
246
- headerRect.setCornerRadius(15); // round top-right
247
- } else {
315
+
316
+ // Only create individual header background if NOT using alternating colors
317
+ if (!this.alternatingRowColors || !Array.isArray(this.alternatingRowColors) || this.alternatingRowColors.length === 0) {
318
+ var headerRect = new jsvgRect();
319
+ headerRect.setWidthAndHeight(cellWidth, this.headerHeight);
320
+ headerRect.setFillColor(this.headerBackgroundColor || omdColor.lightGray);
248
321
  headerRect.setCornerRadius(0);
322
+ headerRect.setStrokeWidth(0);
323
+ headerRect.setPosition(currentX, headerY);
324
+ tableContentGroup.addChild(headerRect);
249
325
  }
250
- headerRect.setStrokeWidth(0);
251
- headerRect.setPosition(currentX + contentOffsetX, currentY);
252
- this.addChild(headerRect);
326
+
253
327
  const headerText = this.createHeaderTextBox(
254
328
  cellWidth,
255
329
  this.headerHeight,
256
330
  this.headers[col] || `Col ${col + 1}`
257
331
  );
258
- headerText.setPosition(currentX + contentOffsetX, currentY);
259
- this.addChild(headerText);
332
+ headerText.setPosition(currentX, headerY);
333
+ tableContentGroup.addChild(headerText);
260
334
  currentX += cellWidth;
261
335
  }
262
336
  currentY += this.headerHeight;
@@ -265,28 +339,37 @@ export class omdTable extends jsvgGroup
265
339
  for (let row = 0; row < numRows; row++) {
266
340
  const rowData = this.data[row];
267
341
  let currentX = 0;
268
- // Alternating bar: odd rows white 50% opacity, even rows transparent
269
- if (row % 2 === 0) {
342
+ const rowY = this.headerHeight + row * this.cellHeight; // Relative to clipped content group
343
+
344
+ // Create row background with alternating colors if enabled
345
+ if (this.alternatingRowColors && Array.isArray(this.alternatingRowColors) && this.alternatingRowColors.length > 0) {
346
+ const colorIndex = (row + 1) % this.alternatingRowColors.length; // +1 to account for header
347
+ const rowColor = this.alternatingRowColors[colorIndex];
348
+
349
+ console.log(`Creating row ${row} background with color:`, rowColor, 'at position:', 0, rowY);
350
+
270
351
  var barRect = new jsvgRect();
271
352
  barRect.setWidthAndHeight(this.width, this.cellHeight);
272
- barRect.setFillColor("rgba(255,255,255,0.5)");
273
- // Round the bottom corners on the last row to respect the table background rounding
274
- if (row === numRows - 1) {
275
- barRect.setCornerRadius(15);
276
- } else {
277
- barRect.setCornerRadius(0);
353
+ barRect.setFillColor(rowColor);
354
+ if (this.backgroundOpacity < 1.0) {
355
+ barRect.setOpacity(this.backgroundOpacity);
278
356
  }
357
+ // No corner radius on individual row backgrounds - clip mask handles the rounding
358
+ barRect.setCornerRadius(0);
279
359
  barRect.setStrokeWidth(0);
280
- barRect.setPosition(contentOffsetX, currentY);
281
- this.addChild(barRect);
360
+ barRect.setPosition(0, rowY);
361
+ tableContentGroup.addChild(barRect);
362
+ } else {
363
+ console.log(`Row ${row}: No alternating colors - alternatingRowColors:`, this.alternatingRowColors);
282
364
  }
365
+
283
366
  for (let col = 0; col < numCols; col++) {
284
367
  const cellWidth = cellWidths[col];
285
368
  const cellText = this.createBodyTextBox(cellWidth, this.cellHeight, "");
286
369
  const cellValue = rowData[col];
287
370
  cellText.setText((cellValue ?? '').toString());
288
- cellText.setPosition(currentX + contentOffsetX, currentY);
289
- this.addChild(cellText);
371
+ cellText.setPosition(currentX, rowY);
372
+ tableContentGroup.addChild(cellText);
290
373
  currentX += cellWidth;
291
374
  }
292
375
  currentY += this.cellHeight;
@@ -302,8 +385,8 @@ export class omdTable extends jsvgGroup
302
385
  vline.setCornerRadius(0);
303
386
  vline.setOpacity(0.5);
304
387
  vline.setStrokeWidth(0);
305
- vline.setPosition(x + contentOffsetX, titleOffset);
306
- this.addChild(vline);
388
+ vline.setPosition(x, 0); // Relative to the clipped content group
389
+ tableContentGroup.addChild(vline);
307
390
  }
308
391
  }
309
392
  // Use displayWidth for the viewBox so the title never clips,
@@ -366,4 +449,51 @@ export class omdTable extends jsvgGroup
366
449
  this.data = [];
367
450
  this.updateLayout();
368
451
  }
452
+
453
+ // Background customization methods
454
+ setBackgroundColor(color) {
455
+ this.backgroundColor = color;
456
+ this.updateLayout();
457
+ }
458
+
459
+ setBackgroundCornerRadius(radius) {
460
+ this.backgroundCornerRadius = radius;
461
+ this.updateLayout();
462
+ }
463
+
464
+ setBackgroundOpacity(opacity) {
465
+ this.backgroundOpacity = Math.max(0, Math.min(1, opacity));
466
+ this.updateLayout();
467
+ }
468
+
469
+ setShowBackground(show) {
470
+ this.showBackground = show;
471
+ this.updateLayout();
472
+ }
473
+
474
+ setBackgroundStyle(options = {}) {
475
+ if (options.backgroundColor !== undefined) this.backgroundColor = options.backgroundColor;
476
+ if (options.cornerRadius !== undefined) this.backgroundCornerRadius = options.cornerRadius;
477
+ if (options.opacity !== undefined) this.backgroundOpacity = Math.max(0, Math.min(1, options.opacity));
478
+ if (options.show !== undefined) this.showBackground = options.show;
479
+ this.updateLayout();
480
+ }
481
+
482
+ // Alternating row colors methods
483
+ setAlternatingRowColors(colors) {
484
+ console.log('setAlternatingRowColors called with:', colors);
485
+ this.alternatingRowColors = colors;
486
+ console.log('alternatingRowColors set to:', this.alternatingRowColors);
487
+ this.updateLayout();
488
+ }
489
+
490
+ setHeaderBackgroundColor(color) {
491
+ this.headerBackgroundColor = color;
492
+ this.updateLayout();
493
+ }
494
+
495
+ setCellBackgroundColor(color) {
496
+ this.cellBackgroundColor = color;
497
+ this.updateLayout();
498
+ }
369
499
  }