@teachinglab/omd 0.7.8 → 0.7.10
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.
|
@@ -445,13 +445,64 @@ export class ResizeHandleManager {
|
|
|
445
445
|
if (!this.selectedElement) return { x: 0, y: 0, width: 0, height: 0 };
|
|
446
446
|
|
|
447
447
|
try {
|
|
448
|
-
// Get
|
|
448
|
+
// Get the content inside the wrapper (usually an SVG element)
|
|
449
449
|
const content = this.selectedElement.firstElementChild;
|
|
450
|
-
if (content) {
|
|
451
|
-
return content.getBBox();
|
|
452
|
-
} else {
|
|
450
|
+
if (!content) {
|
|
453
451
|
return this.selectedElement.getBBox();
|
|
454
452
|
}
|
|
453
|
+
|
|
454
|
+
// For elements with clip paths (like coordinate planes),
|
|
455
|
+
// the graph lines extend beyond the visible area causing getBBox() to be too large.
|
|
456
|
+
// We need to find the clip rect to get the actual visible bounds.
|
|
457
|
+
const clipPaths = content.querySelectorAll('clipPath');
|
|
458
|
+
|
|
459
|
+
if (clipPaths.length > 0) {
|
|
460
|
+
let maxArea = 0;
|
|
461
|
+
let clipBounds = null;
|
|
462
|
+
|
|
463
|
+
for (const clipPath of clipPaths) {
|
|
464
|
+
const rect = clipPath.querySelector('rect');
|
|
465
|
+
if (rect) {
|
|
466
|
+
const w = parseFloat(rect.getAttribute('width')) || 0;
|
|
467
|
+
const h = parseFloat(rect.getAttribute('height')) || 0;
|
|
468
|
+
const x = parseFloat(rect.getAttribute('x')) || 0;
|
|
469
|
+
const y = parseFloat(rect.getAttribute('y')) || 0;
|
|
470
|
+
|
|
471
|
+
const area = w * h;
|
|
472
|
+
if (area > maxArea) {
|
|
473
|
+
maxArea = area;
|
|
474
|
+
|
|
475
|
+
// Find the transform on the content group
|
|
476
|
+
const contentGroup = content.firstElementChild;
|
|
477
|
+
let tx = 0, ty = 0;
|
|
478
|
+
if (contentGroup) {
|
|
479
|
+
const transform = contentGroup.getAttribute('transform');
|
|
480
|
+
if (transform) {
|
|
481
|
+
const translateMatch = transform.match(/translate\(\s*([^,]+)(?:,\s*([^)]+))?\s*\)/);
|
|
482
|
+
if (translateMatch) {
|
|
483
|
+
tx = parseFloat(translateMatch[1]) || 0;
|
|
484
|
+
ty = parseFloat(translateMatch[2]) || 0;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
clipBounds = {
|
|
490
|
+
x: x + tx,
|
|
491
|
+
y: y + ty,
|
|
492
|
+
width: w,
|
|
493
|
+
height: h
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (clipBounds) {
|
|
500
|
+
return clipBounds;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Fallback to getBBox if no clip path found
|
|
505
|
+
return content.getBBox();
|
|
455
506
|
} catch (error) {
|
|
456
507
|
// Fallback if getBBox fails
|
|
457
508
|
return { x: 0, y: 0, width: 100, height: 100 };
|
package/package.json
CHANGED
package/src/omdTable.js
CHANGED
|
@@ -172,22 +172,46 @@ export class omdTable extends jsvgGroup
|
|
|
172
172
|
this.data = [];
|
|
173
173
|
this.headers = ['x', 'y'];
|
|
174
174
|
|
|
175
|
-
// Basic normalization for inline math
|
|
176
175
|
let expression = this.equation;
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
// Remove "y=" from start or "=y" from end, case insensitive, handling spaces
|
|
177
|
+
expression = expression.replace(/^\s*y\s*=\s*/i, '').replace(/\s*=\s*y\s*$/i, '');
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
// Use math.js if available (preferred)
|
|
181
|
+
if (typeof math !== 'undefined' && math.compile) {
|
|
182
|
+
const compiled = math.compile(expression);
|
|
183
|
+
for (let x = this.xMin; x <= this.xMax; x += this.stepSize) {
|
|
184
|
+
try {
|
|
185
|
+
let y = compiled.evaluate({ x });
|
|
186
|
+
// Round to 2 decimal places for display
|
|
187
|
+
y = Math.round(y * 100) / 100;
|
|
188
|
+
this.data.push([x, y]);
|
|
189
|
+
} catch (e) {
|
|
190
|
+
// Skip points that fail to evaluate
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
} catch (e) {
|
|
196
|
+
console.warn("math.js evaluation failed, falling back to simple parser:", e);
|
|
179
197
|
}
|
|
198
|
+
|
|
199
|
+
// Fallback to simple regex-based parsing
|
|
180
200
|
expression = expression
|
|
181
201
|
.replace(/(\d)([a-z])/gi, '$1*$2')
|
|
182
202
|
.replace(/([a-z])(\d)/gi, '$1*$2')
|
|
183
203
|
.replace(/\^/g, '**');
|
|
184
204
|
|
|
185
|
-
|
|
205
|
+
try {
|
|
206
|
+
const evaluateExpression = new Function('x', `return ${expression};`);
|
|
186
207
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
208
|
+
for (let x = this.xMin; x <= this.xMax; x += this.stepSize) {
|
|
209
|
+
let y = evaluateExpression(x);
|
|
210
|
+
y = Math.round(y * 100) / 100;
|
|
211
|
+
this.data.push([x, y]);
|
|
212
|
+
}
|
|
213
|
+
} catch (e) {
|
|
214
|
+
console.error("Error generating table data from equation:", e);
|
|
191
215
|
}
|
|
192
216
|
}
|
|
193
217
|
|