@teachinglab/omd 0.6.1 → 0.6.3
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 +606 -547
- package/omd/core/omdUtilities.js +113 -113
- package/omd/display/omdDisplay.js +1045 -963
- 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 -57
- 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
|
@@ -1,268 +1,268 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for node operations in step visualizations
|
|
3
|
-
*/
|
|
4
|
-
export class omdStepVisualizerNodeUtils {
|
|
5
|
-
/**
|
|
6
|
-
* Checks if a node is a leaf node (constant, variable, etc.)
|
|
7
|
-
* @param {omdNode} node - Node to check
|
|
8
|
-
* @returns {boolean} True if it's a leaf node
|
|
9
|
-
*/
|
|
10
|
-
static isLeafNode(node) {
|
|
11
|
-
if (!node) return false;
|
|
12
|
-
|
|
13
|
-
const leafTypes = [
|
|
14
|
-
'omdConstantNode',
|
|
15
|
-
'omdVariableNode',
|
|
16
|
-
'omdOperatorNode'
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
if (node.constructor && leafTypes.includes(node.type)) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (node.type === 'constant' || node.type === 'variable' || node.type === 'operator') {
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (!node.left && !node.right && !node.argument && !node.expression) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Checks if a node is a binary operation node
|
|
36
|
-
* @param {omdNode} node - Node to check
|
|
37
|
-
* @returns {boolean} True if it's a binary node
|
|
38
|
-
*/
|
|
39
|
-
static isBinaryNode(node) {
|
|
40
|
-
if (!node) return false;
|
|
41
|
-
return node.type === 'omdBinaryExpressionNode' && node.left && node.right;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Checks if a node is a unary operation node
|
|
46
|
-
* @param {omdNode} node - Node to check
|
|
47
|
-
* @returns {boolean} True if it's a unary node
|
|
48
|
-
*/
|
|
49
|
-
static isUnaryNode(node) {
|
|
50
|
-
if (!node) return false;
|
|
51
|
-
return node.type === 'omdUnaryExpressionNode' && node.argument;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Checks if a node has an expression property
|
|
56
|
-
* @param {omdNode} node - Node to check
|
|
57
|
-
* @returns {boolean} True if it has an expression
|
|
58
|
-
*/
|
|
59
|
-
static hasExpression(node) {
|
|
60
|
-
if (!node) return false;
|
|
61
|
-
return node.expression !== undefined;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Gets the value of a leaf node for comparison
|
|
66
|
-
* @param {omdNode} node - Node to get value from
|
|
67
|
-
* @returns {string} String representation of the node's value
|
|
68
|
-
*/
|
|
69
|
-
static getNodeValue(node) {
|
|
70
|
-
if (!node) return 'undefined';
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
if (node.constructor && node.type === 'omdVariableNode' && node.name !== undefined) {
|
|
74
|
-
return String(node.name);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (node.constructor && node.type === 'omdConstantNode' && typeof node.number === 'number') {
|
|
78
|
-
return String(node.number);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (node.isConstant && node.isConstant() && node.getValue && typeof node.getValue === 'function') {
|
|
82
|
-
return String(node.getValue());
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (node.toString && typeof node.toString === 'function') {
|
|
86
|
-
return node.toString();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (node.value !== undefined) {
|
|
90
|
-
return String(node.value);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (node.number !== undefined) {
|
|
94
|
-
return String(node.number);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return node.constructor ? node.type : 'unknown';
|
|
98
|
-
} catch (err) {
|
|
99
|
-
console.error('Error getting node value:', err);
|
|
100
|
-
return 'error';
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Finds all leaf nodes in a tree
|
|
106
|
-
* @param {omdNode} node - Root node to search from
|
|
107
|
-
* @returns {Array} Array of leaf nodes
|
|
108
|
-
*/
|
|
109
|
-
static findLeafNodes(node) {
|
|
110
|
-
if (!node) return [];
|
|
111
|
-
|
|
112
|
-
if (this.isLeafNode(node)) {
|
|
113
|
-
return [node];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const leafNodes = [];
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
if (this.isBinaryNode(node)) {
|
|
120
|
-
leafNodes.push(...this.findLeafNodes(node.left));
|
|
121
|
-
leafNodes.push(...this.findLeafNodes(node.right));
|
|
122
|
-
} else if (this.isUnaryNode(node)) {
|
|
123
|
-
leafNodes.push(...this.findLeafNodes(node.argument));
|
|
124
|
-
} else if (this.hasExpression(node)) {
|
|
125
|
-
leafNodes.push(...this.findLeafNodes(node.expression));
|
|
126
|
-
}
|
|
127
|
-
} catch (err) {
|
|
128
|
-
console.error('Error finding leaf nodes:', err, node);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return leafNodes;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Finds all variable nodes in a tree
|
|
136
|
-
* @param {omdNode} node - Root node to search from
|
|
137
|
-
* @returns {Array} Array of variable nodes
|
|
138
|
-
*/
|
|
139
|
-
static findVariableNodes(node) {
|
|
140
|
-
const leaves = this.findLeafNodes(node);
|
|
141
|
-
return leaves.filter(leaf => leaf.constructor && leaf.type === 'omdVariableNode');
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Finds all constant nodes in a tree
|
|
146
|
-
* @param {omdNode} node - Root node to search from
|
|
147
|
-
* @returns {Array} Array of constant nodes
|
|
148
|
-
*/
|
|
149
|
-
static findConstantNodes(node) {
|
|
150
|
-
const leaves = this.findLeafNodes(node);
|
|
151
|
-
return leaves.filter(leaf => leaf.constructor && leaf.type === 'omdConstantNode');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Finds leaf nodes with a specific value
|
|
156
|
-
* @param {omdNode} node - Root node to search from
|
|
157
|
-
* @param {string} value - Value to search for
|
|
158
|
-
* @returns {Array} Array of matching leaf nodes
|
|
159
|
-
*/
|
|
160
|
-
static findLeafNodesWithValue(node, value) {
|
|
161
|
-
const leaves = this.findLeafNodes(node);
|
|
162
|
-
|
|
163
|
-
const exactMatches = leaves.filter(leaf => leaf.toString() === value);
|
|
164
|
-
if (exactMatches.length > 0) {
|
|
165
|
-
return exactMatches;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const numValue = parseFloat(value);
|
|
169
|
-
if (!isNaN(numValue)) {
|
|
170
|
-
const numericMatches = leaves.filter(leaf => {
|
|
171
|
-
if (leaf.constructor && leaf.type === 'omdConstantNode') {
|
|
172
|
-
if (leaf.number !== undefined) {
|
|
173
|
-
return Math.abs(leaf.number - numValue) < 0.0001;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return false;
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
if (numericMatches.length > 0) {
|
|
180
|
-
return numericMatches;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return leaves.filter(leaf => {
|
|
185
|
-
const leafStr = leaf.toString();
|
|
186
|
-
return leafStr.includes(value) || value.includes(leafStr);
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Finds all nodes in a tree (not just leaf nodes)
|
|
192
|
-
* @param {omdNode} node - Root node to search from
|
|
193
|
-
* @returns {Array} Array of all nodes in the tree
|
|
194
|
-
*/
|
|
195
|
-
static findAllNodes(node) {
|
|
196
|
-
if (!node) return [];
|
|
197
|
-
|
|
198
|
-
const allNodes = [node];
|
|
199
|
-
|
|
200
|
-
try {
|
|
201
|
-
if (node.childList && Array.isArray(node.childList)) {
|
|
202
|
-
node.childList.forEach(child => {
|
|
203
|
-
if (child && child !== node.backRect) {
|
|
204
|
-
allNodes.push(...this.findAllNodes(child));
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (node.argumentNodeList) {
|
|
210
|
-
Object.values(node.argumentNodeList).forEach(child => {
|
|
211
|
-
if (child && child !== node) {
|
|
212
|
-
if (Array.isArray(child)) {
|
|
213
|
-
child.forEach(item => {
|
|
214
|
-
if (item && item !== node) {
|
|
215
|
-
allNodes.push(...this.findAllNodes(item));
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
} else {
|
|
219
|
-
allNodes.push(...this.findAllNodes(child));
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
} catch (err) {
|
|
225
|
-
console.error('Error finding all nodes:', err, node);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return allNodes;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Finds the rightmost leaf node with a specific value in a tree
|
|
233
|
-
* @param {omdNode} node - Root node to search from
|
|
234
|
-
* @param {string} value - Value to search for
|
|
235
|
-
* @returns {omdNode|null} The rightmost matching leaf node, or null if not found
|
|
236
|
-
*/
|
|
237
|
-
static findRightmostNodeWithValue(node, value) {
|
|
238
|
-
const leaves = this.findLeafNodes(node);
|
|
239
|
-
|
|
240
|
-
const matchingNodes = leaves.filter(leaf => {
|
|
241
|
-
const leafStr = leaf.toString();
|
|
242
|
-
return leafStr === value ||
|
|
243
|
-
(leaf.constructor &&
|
|
244
|
-
leaf.type === 'omdConstantNode' &&
|
|
245
|
-
leaf.number !== undefined &&
|
|
246
|
-
Math.abs(leaf.number - parseFloat(value)) < 0.0001);
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
if (matchingNodes.length === 0) {
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const subtractedNodes = matchingNodes.filter(leaf => {
|
|
254
|
-
const parent = leaf.parent;
|
|
255
|
-
return parent &&
|
|
256
|
-
parent.constructor &&
|
|
257
|
-
parent.type === 'omdBinaryExpressionNode' &&
|
|
258
|
-
parent.operation === 'subtract' &&
|
|
259
|
-
parent.right === leaf;
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
if (subtractedNodes.length > 0) {
|
|
263
|
-
return subtractedNodes[subtractedNodes.length - 1];
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return matchingNodes[matchingNodes.length - 1];
|
|
267
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for node operations in step visualizations
|
|
3
|
+
*/
|
|
4
|
+
export class omdStepVisualizerNodeUtils {
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a node is a leaf node (constant, variable, etc.)
|
|
7
|
+
* @param {omdNode} node - Node to check
|
|
8
|
+
* @returns {boolean} True if it's a leaf node
|
|
9
|
+
*/
|
|
10
|
+
static isLeafNode(node) {
|
|
11
|
+
if (!node) return false;
|
|
12
|
+
|
|
13
|
+
const leafTypes = [
|
|
14
|
+
'omdConstantNode',
|
|
15
|
+
'omdVariableNode',
|
|
16
|
+
'omdOperatorNode'
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
if (node.constructor && leafTypes.includes(node.type)) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (node.type === 'constant' || node.type === 'variable' || node.type === 'operator') {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!node.left && !node.right && !node.argument && !node.expression) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a node is a binary operation node
|
|
36
|
+
* @param {omdNode} node - Node to check
|
|
37
|
+
* @returns {boolean} True if it's a binary node
|
|
38
|
+
*/
|
|
39
|
+
static isBinaryNode(node) {
|
|
40
|
+
if (!node) return false;
|
|
41
|
+
return node.type === 'omdBinaryExpressionNode' && node.left && node.right;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Checks if a node is a unary operation node
|
|
46
|
+
* @param {omdNode} node - Node to check
|
|
47
|
+
* @returns {boolean} True if it's a unary node
|
|
48
|
+
*/
|
|
49
|
+
static isUnaryNode(node) {
|
|
50
|
+
if (!node) return false;
|
|
51
|
+
return node.type === 'omdUnaryExpressionNode' && node.argument;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Checks if a node has an expression property
|
|
56
|
+
* @param {omdNode} node - Node to check
|
|
57
|
+
* @returns {boolean} True if it has an expression
|
|
58
|
+
*/
|
|
59
|
+
static hasExpression(node) {
|
|
60
|
+
if (!node) return false;
|
|
61
|
+
return node.expression !== undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Gets the value of a leaf node for comparison
|
|
66
|
+
* @param {omdNode} node - Node to get value from
|
|
67
|
+
* @returns {string} String representation of the node's value
|
|
68
|
+
*/
|
|
69
|
+
static getNodeValue(node) {
|
|
70
|
+
if (!node) return 'undefined';
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
if (node.constructor && node.type === 'omdVariableNode' && node.name !== undefined) {
|
|
74
|
+
return String(node.name);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (node.constructor && node.type === 'omdConstantNode' && typeof node.number === 'number') {
|
|
78
|
+
return String(node.number);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (node.isConstant && node.isConstant() && node.getValue && typeof node.getValue === 'function') {
|
|
82
|
+
return String(node.getValue());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (node.toString && typeof node.toString === 'function') {
|
|
86
|
+
return node.toString();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (node.value !== undefined) {
|
|
90
|
+
return String(node.value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (node.number !== undefined) {
|
|
94
|
+
return String(node.number);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return node.constructor ? node.type : 'unknown';
|
|
98
|
+
} catch (err) {
|
|
99
|
+
console.error('Error getting node value:', err);
|
|
100
|
+
return 'error';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Finds all leaf nodes in a tree
|
|
106
|
+
* @param {omdNode} node - Root node to search from
|
|
107
|
+
* @returns {Array} Array of leaf nodes
|
|
108
|
+
*/
|
|
109
|
+
static findLeafNodes(node) {
|
|
110
|
+
if (!node) return [];
|
|
111
|
+
|
|
112
|
+
if (this.isLeafNode(node)) {
|
|
113
|
+
return [node];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const leafNodes = [];
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
if (this.isBinaryNode(node)) {
|
|
120
|
+
leafNodes.push(...this.findLeafNodes(node.left));
|
|
121
|
+
leafNodes.push(...this.findLeafNodes(node.right));
|
|
122
|
+
} else if (this.isUnaryNode(node)) {
|
|
123
|
+
leafNodes.push(...this.findLeafNodes(node.argument));
|
|
124
|
+
} else if (this.hasExpression(node)) {
|
|
125
|
+
leafNodes.push(...this.findLeafNodes(node.expression));
|
|
126
|
+
}
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.error('Error finding leaf nodes:', err, node);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return leafNodes;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Finds all variable nodes in a tree
|
|
136
|
+
* @param {omdNode} node - Root node to search from
|
|
137
|
+
* @returns {Array} Array of variable nodes
|
|
138
|
+
*/
|
|
139
|
+
static findVariableNodes(node) {
|
|
140
|
+
const leaves = this.findLeafNodes(node);
|
|
141
|
+
return leaves.filter(leaf => leaf.constructor && leaf.type === 'omdVariableNode');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Finds all constant nodes in a tree
|
|
146
|
+
* @param {omdNode} node - Root node to search from
|
|
147
|
+
* @returns {Array} Array of constant nodes
|
|
148
|
+
*/
|
|
149
|
+
static findConstantNodes(node) {
|
|
150
|
+
const leaves = this.findLeafNodes(node);
|
|
151
|
+
return leaves.filter(leaf => leaf.constructor && leaf.type === 'omdConstantNode');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Finds leaf nodes with a specific value
|
|
156
|
+
* @param {omdNode} node - Root node to search from
|
|
157
|
+
* @param {string} value - Value to search for
|
|
158
|
+
* @returns {Array} Array of matching leaf nodes
|
|
159
|
+
*/
|
|
160
|
+
static findLeafNodesWithValue(node, value) {
|
|
161
|
+
const leaves = this.findLeafNodes(node);
|
|
162
|
+
|
|
163
|
+
const exactMatches = leaves.filter(leaf => leaf.toString() === value);
|
|
164
|
+
if (exactMatches.length > 0) {
|
|
165
|
+
return exactMatches;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const numValue = parseFloat(value);
|
|
169
|
+
if (!isNaN(numValue)) {
|
|
170
|
+
const numericMatches = leaves.filter(leaf => {
|
|
171
|
+
if (leaf.constructor && leaf.type === 'omdConstantNode') {
|
|
172
|
+
if (leaf.number !== undefined) {
|
|
173
|
+
return Math.abs(leaf.number - numValue) < 0.0001;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (numericMatches.length > 0) {
|
|
180
|
+
return numericMatches;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return leaves.filter(leaf => {
|
|
185
|
+
const leafStr = leaf.toString();
|
|
186
|
+
return leafStr.includes(value) || value.includes(leafStr);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Finds all nodes in a tree (not just leaf nodes)
|
|
192
|
+
* @param {omdNode} node - Root node to search from
|
|
193
|
+
* @returns {Array} Array of all nodes in the tree
|
|
194
|
+
*/
|
|
195
|
+
static findAllNodes(node) {
|
|
196
|
+
if (!node) return [];
|
|
197
|
+
|
|
198
|
+
const allNodes = [node];
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
if (node.childList && Array.isArray(node.childList)) {
|
|
202
|
+
node.childList.forEach(child => {
|
|
203
|
+
if (child && child !== node.backRect) {
|
|
204
|
+
allNodes.push(...this.findAllNodes(child));
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (node.argumentNodeList) {
|
|
210
|
+
Object.values(node.argumentNodeList).forEach(child => {
|
|
211
|
+
if (child && child !== node) {
|
|
212
|
+
if (Array.isArray(child)) {
|
|
213
|
+
child.forEach(item => {
|
|
214
|
+
if (item && item !== node) {
|
|
215
|
+
allNodes.push(...this.findAllNodes(item));
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
allNodes.push(...this.findAllNodes(child));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
} catch (err) {
|
|
225
|
+
console.error('Error finding all nodes:', err, node);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return allNodes;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Finds the rightmost leaf node with a specific value in a tree
|
|
233
|
+
* @param {omdNode} node - Root node to search from
|
|
234
|
+
* @param {string} value - Value to search for
|
|
235
|
+
* @returns {omdNode|null} The rightmost matching leaf node, or null if not found
|
|
236
|
+
*/
|
|
237
|
+
static findRightmostNodeWithValue(node, value) {
|
|
238
|
+
const leaves = this.findLeafNodes(node);
|
|
239
|
+
|
|
240
|
+
const matchingNodes = leaves.filter(leaf => {
|
|
241
|
+
const leafStr = leaf.toString();
|
|
242
|
+
return leafStr === value ||
|
|
243
|
+
(leaf.constructor &&
|
|
244
|
+
leaf.type === 'omdConstantNode' &&
|
|
245
|
+
leaf.number !== undefined &&
|
|
246
|
+
Math.abs(leaf.number - parseFloat(value)) < 0.0001);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
if (matchingNodes.length === 0) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const subtractedNodes = matchingNodes.filter(leaf => {
|
|
254
|
+
const parent = leaf.parent;
|
|
255
|
+
return parent &&
|
|
256
|
+
parent.constructor &&
|
|
257
|
+
parent.type === 'omdBinaryExpressionNode' &&
|
|
258
|
+
parent.operation === 'subtract' &&
|
|
259
|
+
parent.right === leaf;
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
if (subtractedNodes.length > 0) {
|
|
263
|
+
return subtractedNodes[subtractedNodes.length - 1];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return matchingNodes[matchingNodes.length - 1];
|
|
267
|
+
}
|
|
268
268
|
}
|