Hi @some_5675, DOM reference in Illustrator are fragile, so I wouldn't waste any time trying to keep one. They are broken by many common actions, such as closing/re-opening the document, or simply adding or removing a page item "before" the reference page item (altering the DOM "after" the page item should be fine).
One of your problems is the speed to retrieve your page items graph. Have you tried using
var myItem = doc.getPageItemFromUuid(myPageItemID);
exclusively to create your graph? Is it too slow?
- Mark
P.S. As you noticed the JSON library cannot stringify DOM items. This is for two immediate reasons: (1) they contain cyclic structures that would cause JSON.stringify to loop forever if not aborted, eg. there are properties that return a parent object, which itself has properties that return the original child object, and (2) Illustrator crashes when trying to read some properties of some DOM items! Not to mention that you really don't want to serialize the entire thing—it can be quite long and slow process.
The usual approach is to provide JSON.stringify with a `replacer` function (and JSON.parse with a `reviver` function, if necessary). Here is a little example of a replacer for stringifying a PathItem:
/**
* Example replacer for PathItem
* @param {String|Number} [key] - the access key (default: undefined).
* @param {*} value - the value to replace.
* @returns {*?} - the value to serialize.
*/
function pathItemReplacer(key, value) {
// unfortunately we have to try/catch here
// because some DOM objects throw weird errors
// for no good reasons
try {
if ('parent' === key)
// parent objects usually cause cyclic structure
// and we don't want them anyway
return undefined;
if ('Number' === key.constructor.name)
// don't interfere with normal array access
return value;
if (
'PathItem' === value.typename
|| 'PathPoint' === value.typename
)
// send this back for further serialising
return value;
switch (key) {
case 'uuid':
case 'anchor':
case 'leftDirection':
case 'rightDirection':
// JSON can stringify these
return value;
case 'note':
// only if exists
return '' !== value ? value : undefined;
case 'pointType':
// special handling
return String(value);
case 'pathPoints':
// JSON can't always handle "collections"
// so return a normal Array
var pathPoints = [];
for (var i = 0; i < value.length; i++)
pathPoints[i] = value[i];
return pathPoints;
case 'fillColor':
case 'strokeColor':
// just for an example, we'll
// only stringify a swatch name
if (
value
&& value.typename
&& 'SpotColor' === value.typename
)
return value.spot.name;
default:
// ignore everything else
return undefined;
};
}
catch (error) {
// we definitely don't want anything that throws errors!
return undefined;
}
};