Serialize scenegraph data to JSON?

@stevekwak, is it possible to convert this topic to feature request? Suggested library seems to be an overhead way to convert objects tree into json (e.g. if properties list change library should be adjusted as well).
As quick fix it might be:

  • make properties enumerable;
  • adjust types (by some reason typeof removeFromParent is object).

In general it will be great to have toJson method which will do all the job in async manner.

For now serializing of default document (which goes with xd to show functionality) to json takes 118 secs and make xd unresponsive. Is there any way to call it async right now? And it’s just 9 artboards. How it will work if it will be 70 artboards with much more complex layout?
As the next step I need to export artboards previews and zip them. I’m afraid all these operations will put Xd on freeze for a much longer time.
UPD: It seems that the slowest operation in my case was console.log. I dropped mostly all of them and time reduced to couple seconds :slight_smile:

My attempt to convert scenegraph root object to json: https://gist.github.com/GDreyV/65b2a90eacbb48ca59fe3add737bdb54

Really useful :slight_smile: Although it doesn’t seem to extract Bounds and Points properly

I changed line 16 to

const keys = Object.keys(value).concat(Object.keys(keyDescriptors));

to temporarily fix that

1 Like

Ah I spoke too soon - that line crashes XD for certain nodes

It crashes XD? Or just the plugin?

haha the whole of XD :wink: I think I’ve figured out why - it causes some kind of infinite loop, so I’m guessing XD notices and kills it.

Holy Crap!!! That shouldn’t happen, that’s for sure!

OK I’ve improved the code a bit to prevent the loops - it now only considers plain types from Object.keys which I think is what we want. I added the following at line 43:

    // also pull any plain types from Object.keys - be careful of initite loops!
    for(const key of Object.keys(value)){
      if (skipFields.indexOf(key) > -1 || key[0] === "_" || !isPlainType(value[key])) {
        continue;
      }
      json[key] = value[key];
    }

@kerrishotts I have made the recursive crash code into a reproducible example. This plugin consistently crashes XD each time I run it. https://gist.github.com/robintindale/adb5d49fce34895a123f2b6f088e35de

1 Like

Thank you! Very good point! I made slightly different fix based on the points of inheritance and magic XD crashes. I just do not iterate over elements which extends Objects or something weird called “” (empty string). So plain type check now looks like:

return (!value
  || ["object", "function"].indexOf(typeof value) === -1
  || value instanceof Date
  || ["Object", ""].indexOf(Object.getPrototypeOf(value).constructor.name) > -1);

updated the gist.

Won’t that still fail to expand Bounds and Points? I think you might still need to iterate Object.keys(value) instead of just the prototype keys.

You are completely right! I made another attempt by including Object.keys into getDescriptors as value might be complex object (e.g. color stops for linear gradient) and will be filtered out by isPlainType.

That seems to work mostly, but I’ve found that line 80 can now crash if descriptor is null.

Fixed it by changing it to

: !descriptor || typeof (descriptor.value === "undefined") ? entity[key] : descriptor.value;

Hmm actually it’s still not going deep enough into color stops in a linear gradient

image

update - it’s because colorStops[0] is classed as a “plain” type

I removed your new plain type thing (line 72) and then tracked down the infinite loop. It’s in the key triggeredInteractions, so I added that to skipFields. Seems to be running OK now, until we find the next problem :stuck_out_tongue:

edit: I’ve added incomingInteractions and selected to skipFields too. How would you feel about open sourcing this to github/npm @gdreyv? Just so we don’t have to post here every time we find something :stuck_out_tongue: I’m happy to host on https://github.com/zeroheight if you don’t have time to put it up

1 Like

I just thought that opensourcing a single file which is temporary solution doesn’t make any sense :slight_smile: Anyway I made several changed to dive into interactions (as the idea to have full mapping) and published draft here: https://github.com/sympli/xd-to-json-mapper/blob/master/json.service.ts but I will try to keep gist https://gist.github.com/GDreyV/65b2a90eacbb48ca59fe3add737bdb54 up to date as well.

What about selected field? How can I reproduce it? The point about interaction is to replace real nodes with references to keep data but prevent infinite loops.

What’s wrong with .selected? Isn’t it just a bool?

yeah sorry, selected is fine. For my particular use-case it’s irrelevant because I’m trying to see if the node has changed or not (which isn’t affected by whether it’s selected or not).

yeah I think we can fix the infinite loops if we add a bit more logic - we just need to ensure that Action is properly handled so destination or overlay don’t get fully expanded. Obviously we are trying to avoid “special cases”, as that’s the whole point of doing it this way vs. manually mapping all the classes, but yeah I see your related discussion in typeof(scenegraph.SceneNode) is undefined - #7 by gdreyv so hopefully we can find something generic

heh yeah but I guess we don’t know how long “temporary” is. I don’t personally use Typescript so it would need a bit more work to make it ingestible in my plugin - will PR if I get any time

@kerrishotts do you have any updates on that? It’s weird that we can’t serialize js objects into json.
For I’m facing multiple exceptions on custom serialization e.g. trying to access horizontalConstraints on Symbol throws parent not defined error.