-
Notifications
You must be signed in to change notification settings - Fork 287
Description
It looks like the toSVG method mutates the models passed into it, which is expected. This came up while trying to cache submodels to improve performance.
Here's a minimal repro case:
const makerjs = require("makerjs");
const opentype = require("opentype.js");
const font = opentype.loadSync("./src/fonts/ReliefSingleLineCAD-Regular.ttf");
const text = new makerjs.models.Text(font, "Hi", 12);
const model = {
models: {
text1: text,
text2: text,
},
};
const svg = makerjs.exporter.toSVG(model);
console.log(svg);The result is this exception:
TypeError: Cannot read properties of undefined (reading 'startT')
at getActualBezierRange (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8591:43)
at /Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8790:37
at Array.forEach (<anonymous>)
at /Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8785:27
at _loop_3 (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6054:21)
at Object.findChains (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6058:17)
at BezierCurve.getBezierSeeds (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:8773:31)
at /Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6170:73
at Array.forEach (<anonymous>)
at swapBezierPathsWithSeeds (/Users/xavi/code/maker-test/server/node_modules/makerjs/dist/index.js:6161:21)
I'm using node v22.11.0 with [email protected] and [email protected]
The issue seems to be somewhere in here:
maker.js/packages/maker.js/src/core/chain.ts
Lines 405 to 453 in 1ed796b
| beziers.forEach(wm => { | |
| var b = wm.childModel as models.BezierCurve; | |
| if (swap) { | |
| //set layer prior to looking for seeds by layer | |
| if (wm.layer != undefined && wm.layer !== '') { | |
| b[tempLayerKey] = (b as IModel).layer; | |
| (b as IModel).layer = wm.layer; | |
| } | |
| //use seeds as path, hide the arc paths from findChains() | |
| var bezierPartsByLayer = models.BezierCurve.getBezierSeeds(b, { byLayers: true, pointMatchingDistance }); | |
| for (var layer in bezierPartsByLayer) { | |
| var bezierSeeds = bezierPartsByLayer[layer]; | |
| if (bezierSeeds.length > 0) { | |
| b[tempKey] = b.paths; | |
| var newPaths: IPathMap = {}; | |
| bezierSeeds.forEach(function (seed, i) { | |
| seed.layer = layer; | |
| newPaths['seed_' + i] = seed; | |
| }); | |
| b.paths = newPaths; | |
| } | |
| } | |
| } else { | |
| //revert the above | |
| if (tempKey in b) { | |
| b.paths = b[tempKey] as IPathMap; | |
| delete b[tempKey]; | |
| } | |
| if (tempLayerKey in b) { | |
| if (b[tempLayerKey] == undefined) { | |
| delete (b as IModel).layer; | |
| } else { | |
| (b as IModel).layer = b[tempLayerKey] as string; | |
| } | |
| delete b[tempLayerKey]; | |
| } | |
| } | |
| }); |
It's not obvious to me how to fix it, so I figured I'd open an issue
The exception doesn't occur when useSvgPathOnly option is enabled, which double confirms that the issue is related to the findChains function
Workaround
// Clone submodels
const model = {
models: {
text1: makerjs.cloneObject(text),
text2: makerjs.cloneObject(text),
},
};This does works, but it add a bit of overhead. Also, it's surprising that an exporter mutates the underlying model