@teachinglab/omd 0.6.0 → 0.6.2
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/README.md +257 -251
- package/README.old.md +137 -137
- package/canvas/core/canvasConfig.js +202 -202
- package/canvas/drawing/segment.js +167 -167
- package/canvas/drawing/stroke.js +385 -385
- package/canvas/events/eventManager.js +444 -444
- package/canvas/events/pointerEventHandler.js +262 -262
- package/canvas/index.js +48 -48
- package/canvas/tools/PointerTool.js +71 -71
- package/canvas/tools/tool.js +222 -222
- package/canvas/utils/boundingBox.js +377 -377
- package/canvas/utils/mathUtils.js +258 -258
- package/docs/api/configuration-options.md +198 -198
- package/docs/api/eventManager.md +82 -82
- package/docs/api/focusFrameManager.md +144 -144
- package/docs/api/index.md +105 -105
- package/docs/api/main.md +62 -62
- package/docs/api/omdBinaryExpressionNode.md +86 -86
- package/docs/api/omdCanvas.md +83 -83
- package/docs/api/omdConfigManager.md +112 -112
- package/docs/api/omdConstantNode.md +52 -52
- package/docs/api/omdDisplay.md +87 -87
- package/docs/api/omdEquationNode.md +174 -174
- package/docs/api/omdEquationSequenceNode.md +258 -258
- package/docs/api/omdEquationStack.md +192 -192
- package/docs/api/omdFunctionNode.md +82 -82
- package/docs/api/omdGroupNode.md +78 -78
- package/docs/api/omdHelpers.md +87 -87
- package/docs/api/omdLeafNode.md +85 -85
- package/docs/api/omdNode.md +201 -201
- package/docs/api/omdOperationDisplayNode.md +117 -117
- package/docs/api/omdOperatorNode.md +91 -91
- package/docs/api/omdParenthesisNode.md +133 -133
- package/docs/api/omdPopup.md +191 -191
- package/docs/api/omdPowerNode.md +131 -131
- package/docs/api/omdRationalNode.md +144 -144
- package/docs/api/omdSequenceNode.md +128 -128
- package/docs/api/omdSimplification.md +78 -78
- package/docs/api/omdSqrtNode.md +144 -144
- package/docs/api/omdStepVisualizer.md +146 -146
- package/docs/api/omdStepVisualizerHighlighting.md +65 -65
- package/docs/api/omdStepVisualizerInteractiveSteps.md +108 -108
- package/docs/api/omdStepVisualizerLayout.md +70 -70
- package/docs/api/omdStepVisualizerNodeUtils.md +140 -140
- package/docs/api/omdStepVisualizerTextBoxes.md +76 -76
- package/docs/api/omdToolbar.md +130 -130
- package/docs/api/omdTranscriptionService.md +95 -95
- package/docs/api/omdTreeDiff.md +169 -169
- package/docs/api/omdUnaryExpressionNode.md +137 -137
- package/docs/api/omdUtilities.md +82 -82
- package/docs/api/omdVariableNode.md +123 -123
- package/docs/api/selectTool.md +74 -74
- package/docs/api/simplificationEngine.md +97 -97
- package/docs/api/simplificationRules.md +76 -76
- package/docs/api/simplificationUtils.md +64 -64
- package/docs/api/transcribe.md +43 -43
- package/docs/api-reference.md +85 -85
- package/docs/index.html +453 -453
- package/docs/index.md +38 -38
- package/docs/omd-objects.md +258 -258
- package/index.js +79 -79
- package/jsvg/index.js +3 -0
- package/jsvg/jsvg.js +898 -898
- package/jsvg/jsvgComponents.js +357 -358
- package/npm-docs/DOCUMENTATION_SUMMARY.md +220 -220
- package/npm-docs/README.md +251 -251
- package/npm-docs/api/api-reference.md +85 -85
- package/npm-docs/api/configuration-options.md +198 -198
- package/npm-docs/api/eventManager.md +82 -82
- package/npm-docs/api/expression-nodes.md +561 -561
- package/npm-docs/api/focusFrameManager.md +144 -144
- package/npm-docs/api/index.md +105 -105
- package/npm-docs/api/main.md +62 -62
- package/npm-docs/api/omdBinaryExpressionNode.md +86 -86
- package/npm-docs/api/omdCanvas.md +83 -83
- package/npm-docs/api/omdConfigManager.md +112 -112
- package/npm-docs/api/omdConstantNode.md +52 -52
- package/npm-docs/api/omdDisplay.md +87 -87
- package/npm-docs/api/omdEquationNode.md +174 -174
- package/npm-docs/api/omdEquationSequenceNode.md +258 -258
- package/npm-docs/api/omdEquationStack.md +192 -192
- package/npm-docs/api/omdFunctionNode.md +82 -82
- package/npm-docs/api/omdGroupNode.md +78 -78
- package/npm-docs/api/omdHelpers.md +87 -87
- package/npm-docs/api/omdLeafNode.md +85 -85
- package/npm-docs/api/omdNode.md +201 -201
- package/npm-docs/api/omdOperationDisplayNode.md +117 -117
- package/npm-docs/api/omdOperatorNode.md +91 -91
- package/npm-docs/api/omdParenthesisNode.md +133 -133
- package/npm-docs/api/omdPopup.md +191 -191
- package/npm-docs/api/omdPowerNode.md +131 -131
- package/npm-docs/api/omdRationalNode.md +144 -144
- package/npm-docs/api/omdSequenceNode.md +128 -128
- package/npm-docs/api/omdSimplification.md +78 -78
- package/npm-docs/api/omdSqrtNode.md +144 -144
- package/npm-docs/api/omdStepVisualizer.md +146 -146
- package/npm-docs/api/omdStepVisualizerHighlighting.md +65 -65
- package/npm-docs/api/omdStepVisualizerInteractiveSteps.md +108 -108
- package/npm-docs/api/omdStepVisualizerLayout.md +70 -70
- package/npm-docs/api/omdStepVisualizerNodeUtils.md +140 -140
- package/npm-docs/api/omdStepVisualizerTextBoxes.md +76 -76
- package/npm-docs/api/omdToolbar.md +130 -130
- package/npm-docs/api/omdTranscriptionService.md +95 -95
- package/npm-docs/api/omdTreeDiff.md +169 -169
- package/npm-docs/api/omdUnaryExpressionNode.md +137 -137
- package/npm-docs/api/omdUtilities.md +82 -82
- package/npm-docs/api/omdVariableNode.md +123 -123
- package/npm-docs/api/selectTool.md +74 -74
- package/npm-docs/api/simplificationEngine.md +97 -97
- package/npm-docs/api/simplificationRules.md +76 -76
- package/npm-docs/api/simplificationUtils.md +64 -64
- package/npm-docs/api/transcribe.md +43 -43
- package/npm-docs/guides/equations.md +854 -854
- package/npm-docs/guides/factory-functions.md +354 -354
- package/npm-docs/guides/getting-started.md +318 -318
- package/npm-docs/guides/quick-examples.md +525 -525
- package/npm-docs/guides/visualizations.md +682 -682
- package/npm-docs/index.html +12 -0
- package/npm-docs/json-schemas.md +826 -826
- package/omd/config/omdConfigManager.js +279 -267
- package/omd/core/index.js +158 -158
- package/omd/core/omdEquationStack.js +546 -546
- package/omd/core/omdUtilities.js +113 -113
- package/omd/display/omdDisplay.js +969 -962
- package/omd/display/omdToolbar.js +501 -501
- package/omd/nodes/omdBinaryExpressionNode.js +459 -459
- package/omd/nodes/omdConstantNode.js +141 -141
- package/omd/nodes/omdEquationNode.js +1327 -1327
- package/omd/nodes/omdFunctionNode.js +351 -351
- package/omd/nodes/omdGroupNode.js +67 -67
- package/omd/nodes/omdLeafNode.js +76 -76
- package/omd/nodes/omdNode.js +556 -556
- package/omd/nodes/omdOperationDisplayNode.js +321 -321
- package/omd/nodes/omdOperatorNode.js +108 -108
- package/omd/nodes/omdParenthesisNode.js +292 -292
- package/omd/nodes/omdPowerNode.js +235 -235
- package/omd/nodes/omdRationalNode.js +295 -295
- package/omd/nodes/omdSqrtNode.js +307 -307
- package/omd/nodes/omdUnaryExpressionNode.js +227 -227
- package/omd/nodes/omdVariableNode.js +122 -122
- package/omd/simplification/omdSimplification.js +140 -140
- package/omd/simplification/omdSimplificationEngine.js +887 -887
- package/omd/simplification/package.json +5 -5
- package/omd/simplification/rules/binaryRules.js +1037 -1037
- package/omd/simplification/rules/functionRules.js +111 -111
- package/omd/simplification/rules/index.js +48 -48
- package/omd/simplification/rules/parenthesisRules.js +19 -19
- package/omd/simplification/rules/powerRules.js +143 -143
- package/omd/simplification/rules/rationalRules.js +725 -725
- package/omd/simplification/rules/sqrtRules.js +48 -48
- package/omd/simplification/rules/unaryRules.js +37 -37
- package/omd/simplification/simplificationRules.js +31 -31
- package/omd/simplification/simplificationUtils.js +1055 -1055
- package/omd/step-visualizer/omdStepVisualizer.js +947 -947
- package/omd/step-visualizer/omdStepVisualizerHighlighting.js +246 -246
- package/omd/step-visualizer/omdStepVisualizerLayout.js +892 -892
- package/omd/step-visualizer/omdStepVisualizerTextBoxes.js +200 -200
- package/omd/utils/aiNextEquationStep.js +106 -106
- package/omd/utils/omdNodeOverlay.js +638 -638
- package/omd/utils/omdPopup.js +1203 -1203
- package/omd/utils/omdStepVisualizerInteractiveSteps.js +684 -684
- package/omd/utils/omdStepVisualizerNodeUtils.js +267 -267
- package/omd/utils/omdTranscriptionService.js +123 -123
- package/omd/utils/omdTreeDiff.js +733 -733
- package/package.json +59 -56
- package/readme.html +184 -120
- package/src/index.js +74 -74
- package/src/json-schemas.md +576 -576
- package/src/omd-json-samples.js +147 -147
- package/src/omdApp.js +391 -391
- package/src/omdAppCanvas.js +335 -335
- package/src/omdBalanceHanger.js +199 -199
- package/src/omdColor.js +13 -13
- package/src/omdCoordinatePlane.js +541 -541
- package/src/omdExpression.js +115 -115
- package/src/omdFactory.js +150 -150
- package/src/omdFunction.js +114 -114
- package/src/omdMetaExpression.js +290 -290
- package/src/omdNaturalExpression.js +563 -563
- package/src/omdNode.js +383 -383
- package/src/omdNumber.js +52 -52
- package/src/omdNumberLine.js +114 -112
- package/src/omdNumberTile.js +118 -118
- package/src/omdOperator.js +72 -72
- package/src/omdPowerExpression.js +91 -91
- package/src/omdProblem.js +259 -259
- package/src/omdRatioChart.js +251 -251
- package/src/omdRationalExpression.js +114 -114
- package/src/omdSampleData.js +215 -215
- package/src/omdShapes.js +512 -512
- package/src/omdSpinner.js +151 -151
- package/src/omdString.js +49 -49
- package/src/omdTable.js +498 -498
- package/src/omdTapeDiagram.js +244 -244
- package/src/omdTerm.js +91 -91
- package/src/omdTileEquation.js +349 -349
- package/src/omdUtils.js +84 -84
- package/src/omdVariable.js +51 -51
package/omd/core/omdUtilities.js
CHANGED
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
import { omdBinaryExpressionNode } from "../nodes/omdBinaryExpressionNode.js";
|
|
2
|
-
import { omdParenthesisNode } from "../nodes/omdParenthesisNode.js";
|
|
3
|
-
import { omdPowerNode } from "../nodes/omdPowerNode.js";
|
|
4
|
-
import { omdRationalNode } from "../nodes/omdRationalNode.js";
|
|
5
|
-
import { omdNode } from "../nodes/omdNode.js";
|
|
6
|
-
import { omdFunctionNode } from "../nodes/omdFunctionNode.js";
|
|
7
|
-
import { omdSqrtNode } from "../nodes/omdSqrtNode.js";
|
|
8
|
-
import { omdLeafNode } from "../nodes/omdLeafNode.js";
|
|
9
|
-
import { omdConstantNode } from "../nodes/omdConstantNode.js";
|
|
10
|
-
import { omdVariableNode } from "../nodes/omdVariableNode.js";
|
|
11
|
-
import { omdEquationNode } from "../nodes/omdEquationNode.js";
|
|
12
|
-
import { omdUnaryExpressionNode } from "../nodes/omdUnaryExpressionNode.js";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Maps an AST node type to its corresponding OMD node class
|
|
16
|
-
* @param {string} type - The type of the AST node (e.g., "OperatorNode", "ParenthesisNode")
|
|
17
|
-
* @param {Object} ast - The AST node data containing additional context
|
|
18
|
-
* @returns {class} The appropriate OMD node class for the given AST node type
|
|
19
|
-
*/
|
|
20
|
-
export function astToOmdType(type, ast) {
|
|
21
|
-
switch (type) {
|
|
22
|
-
case "AssignmentNode":
|
|
23
|
-
return omdEquationNode;
|
|
24
|
-
case "OperatorNode":
|
|
25
|
-
// Check for unary minus: op is '-' and there's only one argument.
|
|
26
|
-
if (ast?.op === '-' && ast.args.length === 1 && !ast.implicit) {
|
|
27
|
-
return omdUnaryExpressionNode;
|
|
28
|
-
}
|
|
29
|
-
if (ast?.op === '=') return omdEquationNode;
|
|
30
|
-
if (ast?.op === '^') return omdPowerNode;
|
|
31
|
-
if (ast?.op === '/') {
|
|
32
|
-
return omdRationalNode;
|
|
33
|
-
}
|
|
34
|
-
return omdBinaryExpressionNode;
|
|
35
|
-
case "ParenthesisNode":
|
|
36
|
-
return omdParenthesisNode;
|
|
37
|
-
case "ConstantNode":
|
|
38
|
-
return omdConstantNode;
|
|
39
|
-
case "SymbolNode":
|
|
40
|
-
return omdVariableNode;
|
|
41
|
-
case "FunctionNode":
|
|
42
|
-
// Handle implicit multiplication from math.js AST
|
|
43
|
-
if ((ast?.fn?.name === 'multiply' || ast?.name === 'multiply') && ast.implicit) {
|
|
44
|
-
return omdBinaryExpressionNode;
|
|
45
|
-
}
|
|
46
|
-
// Check if this is a sqrt function
|
|
47
|
-
if (ast?.fn?.name === 'sqrt' || ast?.name === 'sqrt') {
|
|
48
|
-
return omdSqrtNode;
|
|
49
|
-
}
|
|
50
|
-
return omdFunctionNode;
|
|
51
|
-
default:
|
|
52
|
-
return omdNode;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Determines whether a division operation should be rendered as a fraction
|
|
58
|
-
* @param {Object} ast - The AST node representing a division operation
|
|
59
|
-
* @returns {boolean} True if the division should be rendered as a fraction, false otherwise
|
|
60
|
-
*/
|
|
61
|
-
function shouldUseFractionNotation(ast) {
|
|
62
|
-
const numeratorComplex = isComplexExpression(ast.args[0]);
|
|
63
|
-
const denominatorComplex = isComplexExpression(ast.args[1]);
|
|
64
|
-
return !(numeratorComplex || denominatorComplex);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Checks if an AST node represents a complex expression
|
|
69
|
-
* @param {Object} ast - The AST node to check
|
|
70
|
-
* @returns {boolean} True if the expression is complex (contains multiple operations), false otherwise
|
|
71
|
-
*/
|
|
72
|
-
function isComplexExpression(ast) {
|
|
73
|
-
if (!ast) return false;
|
|
74
|
-
// A binary plus/minus is complex. A unary minus is not.
|
|
75
|
-
if (ast.type === "OperatorNode" && (ast.op === "+" || ast.op === "-") && ast.args.length === 2) return true;
|
|
76
|
-
return ast.args?.some(arg => isComplexExpression(arg)) || false;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Gets the appropriate OMD node class for an AST node
|
|
81
|
-
* @param {Object} ast - The AST node to get the class for
|
|
82
|
-
* @returns {class} The appropriate OMD node class for the given AST node
|
|
83
|
-
*/
|
|
84
|
-
export function getNodeForAST(ast) {
|
|
85
|
-
let nodeType = ast.type;
|
|
86
|
-
if (ast.mathjs) {
|
|
87
|
-
nodeType = ast.mathjs;
|
|
88
|
-
}
|
|
89
|
-
return astToOmdType(nodeType, ast);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/* Gerard - Added utility function */
|
|
93
|
-
export function getTextBounds(text, fontSize) {
|
|
94
|
-
// Create a temporary span element
|
|
95
|
-
const span = document.createElement('span');
|
|
96
|
-
span.style.visibility = 'hidden';
|
|
97
|
-
span.style.position = 'absolute';
|
|
98
|
-
span.style.whiteSpace = 'nowrap';
|
|
99
|
-
span.style.fontFamily = "Albert Sans";
|
|
100
|
-
span.style.fontSize = `${fontSize || 16}px`;
|
|
101
|
-
span.textContent = text;
|
|
102
|
-
|
|
103
|
-
// Append to the body to measure
|
|
104
|
-
document.body.appendChild(span);
|
|
105
|
-
|
|
106
|
-
// Measure dimensions using DOM
|
|
107
|
-
const width = span.offsetWidth;
|
|
108
|
-
const height = span.offsetHeight;
|
|
109
|
-
|
|
110
|
-
// Clean up DOM element
|
|
111
|
-
document.body.removeChild(span);
|
|
112
|
-
|
|
113
|
-
return {width: width, height: height};
|
|
1
|
+
import { omdBinaryExpressionNode } from "../nodes/omdBinaryExpressionNode.js";
|
|
2
|
+
import { omdParenthesisNode } from "../nodes/omdParenthesisNode.js";
|
|
3
|
+
import { omdPowerNode } from "../nodes/omdPowerNode.js";
|
|
4
|
+
import { omdRationalNode } from "../nodes/omdRationalNode.js";
|
|
5
|
+
import { omdNode } from "../nodes/omdNode.js";
|
|
6
|
+
import { omdFunctionNode } from "../nodes/omdFunctionNode.js";
|
|
7
|
+
import { omdSqrtNode } from "../nodes/omdSqrtNode.js";
|
|
8
|
+
import { omdLeafNode } from "../nodes/omdLeafNode.js";
|
|
9
|
+
import { omdConstantNode } from "../nodes/omdConstantNode.js";
|
|
10
|
+
import { omdVariableNode } from "../nodes/omdVariableNode.js";
|
|
11
|
+
import { omdEquationNode } from "../nodes/omdEquationNode.js";
|
|
12
|
+
import { omdUnaryExpressionNode } from "../nodes/omdUnaryExpressionNode.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Maps an AST node type to its corresponding OMD node class
|
|
16
|
+
* @param {string} type - The type of the AST node (e.g., "OperatorNode", "ParenthesisNode")
|
|
17
|
+
* @param {Object} ast - The AST node data containing additional context
|
|
18
|
+
* @returns {class} The appropriate OMD node class for the given AST node type
|
|
19
|
+
*/
|
|
20
|
+
export function astToOmdType(type, ast) {
|
|
21
|
+
switch (type) {
|
|
22
|
+
case "AssignmentNode":
|
|
23
|
+
return omdEquationNode;
|
|
24
|
+
case "OperatorNode":
|
|
25
|
+
// Check for unary minus: op is '-' and there's only one argument.
|
|
26
|
+
if (ast?.op === '-' && ast.args.length === 1 && !ast.implicit) {
|
|
27
|
+
return omdUnaryExpressionNode;
|
|
28
|
+
}
|
|
29
|
+
if (ast?.op === '=') return omdEquationNode;
|
|
30
|
+
if (ast?.op === '^') return omdPowerNode;
|
|
31
|
+
if (ast?.op === '/') {
|
|
32
|
+
return omdRationalNode;
|
|
33
|
+
}
|
|
34
|
+
return omdBinaryExpressionNode;
|
|
35
|
+
case "ParenthesisNode":
|
|
36
|
+
return omdParenthesisNode;
|
|
37
|
+
case "ConstantNode":
|
|
38
|
+
return omdConstantNode;
|
|
39
|
+
case "SymbolNode":
|
|
40
|
+
return omdVariableNode;
|
|
41
|
+
case "FunctionNode":
|
|
42
|
+
// Handle implicit multiplication from math.js AST
|
|
43
|
+
if ((ast?.fn?.name === 'multiply' || ast?.name === 'multiply') && ast.implicit) {
|
|
44
|
+
return omdBinaryExpressionNode;
|
|
45
|
+
}
|
|
46
|
+
// Check if this is a sqrt function
|
|
47
|
+
if (ast?.fn?.name === 'sqrt' || ast?.name === 'sqrt') {
|
|
48
|
+
return omdSqrtNode;
|
|
49
|
+
}
|
|
50
|
+
return omdFunctionNode;
|
|
51
|
+
default:
|
|
52
|
+
return omdNode;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Determines whether a division operation should be rendered as a fraction
|
|
58
|
+
* @param {Object} ast - The AST node representing a division operation
|
|
59
|
+
* @returns {boolean} True if the division should be rendered as a fraction, false otherwise
|
|
60
|
+
*/
|
|
61
|
+
function shouldUseFractionNotation(ast) {
|
|
62
|
+
const numeratorComplex = isComplexExpression(ast.args[0]);
|
|
63
|
+
const denominatorComplex = isComplexExpression(ast.args[1]);
|
|
64
|
+
return !(numeratorComplex || denominatorComplex);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Checks if an AST node represents a complex expression
|
|
69
|
+
* @param {Object} ast - The AST node to check
|
|
70
|
+
* @returns {boolean} True if the expression is complex (contains multiple operations), false otherwise
|
|
71
|
+
*/
|
|
72
|
+
function isComplexExpression(ast) {
|
|
73
|
+
if (!ast) return false;
|
|
74
|
+
// A binary plus/minus is complex. A unary minus is not.
|
|
75
|
+
if (ast.type === "OperatorNode" && (ast.op === "+" || ast.op === "-") && ast.args.length === 2) return true;
|
|
76
|
+
return ast.args?.some(arg => isComplexExpression(arg)) || false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Gets the appropriate OMD node class for an AST node
|
|
81
|
+
* @param {Object} ast - The AST node to get the class for
|
|
82
|
+
* @returns {class} The appropriate OMD node class for the given AST node
|
|
83
|
+
*/
|
|
84
|
+
export function getNodeForAST(ast) {
|
|
85
|
+
let nodeType = ast.type;
|
|
86
|
+
if (ast.mathjs) {
|
|
87
|
+
nodeType = ast.mathjs;
|
|
88
|
+
}
|
|
89
|
+
return astToOmdType(nodeType, ast);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* Gerard - Added utility function */
|
|
93
|
+
export function getTextBounds(text, fontSize) {
|
|
94
|
+
// Create a temporary span element
|
|
95
|
+
const span = document.createElement('span');
|
|
96
|
+
span.style.visibility = 'hidden';
|
|
97
|
+
span.style.position = 'absolute';
|
|
98
|
+
span.style.whiteSpace = 'nowrap';
|
|
99
|
+
span.style.fontFamily = "Albert Sans";
|
|
100
|
+
span.style.fontSize = `${fontSize || 16}px`;
|
|
101
|
+
span.textContent = text;
|
|
102
|
+
|
|
103
|
+
// Append to the body to measure
|
|
104
|
+
document.body.appendChild(span);
|
|
105
|
+
|
|
106
|
+
// Measure dimensions using DOM
|
|
107
|
+
const width = span.offsetWidth;
|
|
108
|
+
const height = span.offsetHeight;
|
|
109
|
+
|
|
110
|
+
// Clean up DOM element
|
|
111
|
+
document.body.removeChild(span);
|
|
112
|
+
|
|
113
|
+
return {width: width, height: height};
|
|
114
114
|
}
|