Import GoJS JSON into GoDiagram

Hello,

My company use case requires us to interface our .Net project with our clients’ web projects. More specifically we need to import GoJS serialized JSON into our .Net Framework project and use that to generate an image of the diagram. The diagram can be anything, and our only certainty is that it came from GoJS.

I’d like to ask for confirmation that the current way to do this would be:

  • Use the Json. NET library to convert JSON to XML
  • Write GoXmlTransformer and GoXmlBindingTransformer classes for all element types and properties.
  • Add them to the GoDocument instance
  • Read the XML
  • Use the SVG namespace to generate an SVG file
  • Convert the SVG to is final output image format

Is there a reason you can’t use the WebView2 control to host the same GoJS diagram code that your web app uses?
Get started with WebView2 in WinForms apps - Microsoft Edge Development | Microsoft Docs

We do not have a web app. Apologies if that wasn’t clear.
Out client is the one sending us this JSON. We need to be able to consume it and generate the image ourselves for archival purposes.

Our project doesn’t use WinForms either. It’s a collection of WCF and DLL services that read our clients data in different formats, processes it, and outputs into several different other formats. We need GoDiagram to be able to start consuming this new input format.

The JSON generated by GoJS is a model, not a document.

A document will have all of the information needed to produce a rendering.

A model has only abstract information from which many renderings could be produced, depending on the styling (templates) and layout that is applied.

I don’t know what is in the JSON that you will be consuming, so you will have to look at it and decide what it is that you want to show for each node and for each link.

Why don’t they just send you the image of the diagram from their app?

We need to also store the diagram in an editable format. The client is a test administrator, the diagram is a drawing by a test taker that was created in a web application belonging to the client. We do not control any of these.

The client then needs to send us the exam, complete with all the question and answers (in a standard format) , including the diagram(s) in a format that can be read, interpreted and stored by our internal systems that are responsible for grading and outputting results.

I’m not sure what impact templating or layout has in any of this. I was convinced from looking at the GoJS documentation that a Model has what is needed for rendering shapes, lines and text. Any templating and layout would be accessory in this context. And that’s the reason of my original question.

But in a very short sentence what I am asking is this: Can a diagram generated by GoJS be consumed by GoDiagram for editing or any other purposes?

So if I sent you some HTML, but you didn’t know how a browser worked or anything about the HTML standard, could you reproduce the page the same way Chrome would?

In the general case, that’s what you’re asking to do.

Walter is right, you at least need a full specification of the diagrams built by the app and how they use the model data. Even then, getting pixel level accuracy going to be very, very hard.

Plugging in the WebView2 control (in the same way you would plug in the GoDiagram control) and running a copy of the client’s GoJS code inside that WebView is the only way to guarantee results. (and yes, you can do this in a .NET app running on Windows).

And even then you have a versioning problem when they make enhancements.

Why do you need to involve GoDiagram or GoJS at all? If you only need to read and write the diagrams (actually models) produced by the client, I believe you have already decided that you can work with the JSON data structures in any language on any server.

You only need to use GoDiagram or GoJS if you want to render raster images or SVG. But if you do, it cannot be a pixel-perfect rendering compared with what is seen by the user in a web app. First, rendering of text varies by platform and even between different browsers on the same machine. Second, as Jake has pointed out, the client’s web app might change with newer versions, and even with the same version if the user might control any of the styling. Third, I’m guessing that you would actually prefer a different rendering than what the client’s app produces.

Thank you for all the replies.

There is no User Interface on our end to plug WebView2 into. It’s just middleware and backend. The JSON I saw coming from our client gave me the impression I could process the data and faithfully render and store the diagram on our backend. And because our middleware is .Net/C#, I considered GoDiagram nuget package as the means to do just that.

I’ll have to reach out to business and understand the requirements for the generated image. We would be storing in our backend both the JSON and the generated image (which our client can’t give to us pre-rendered). If the requirements are we do not need a pixel-perfect representation of the original, where does that leave me regarding the initial question at the top of this thread?

I got confirmation that we are not required to generate and store a pixel-perfect representation of the original diagram created in GoJS. These are the requirements for the generated image:

  • Objects are correctly scaled
  • Relative position of objects in the diagram are respected
  • All objects created in GoJS can be generated with GoDiagram

No other styling requirements exist. The current JSON schema already contains what we need (fonts types and sizes, colors, line weights, etc…)

So, with this in mind, is the flow in the original post in this thread correct?

We’re currently working on a new version of GoDiagram similar in design to GoJS. We’re working to put out an alpha soon, but we may want to integrate some features that would simplify your process flow for a case like this.

Are you able to provide any sample JSON data? And what sorts of images formats would you be looking to output to? Which version of .NET Framework are you using?

That is good news.

I can give you the baseline image, and the JSON generated in GoJS, that is going to be the target of the proof of concept I am working to help management decide on the purchase of GoDiagram licenses. I cannot provide any other sample data at this time.

The image format is yet to be decided. But, in addition to SVG, if GoDiagram can provide at least one lossless raster format like PNG, we would be able to convert it to any other image format. We would prefer not to have to convert from an SVG base though, as this is still a constant evolving image format, and we would rather have a more stable source that doesn’t require constant updates.

In our use case images will never be very big or complex. But we do have some hard requirements that I listed in the previous post.

{
    "class": "go.GraphLinksModel",
    "linkFromPortIdProperty": "fromPort",
    "linkToPortIdProperty": "toPort",
    "nodeDataArray": [{
            "category": "Basic",
            "icon": "rectangle_icon",
            "tooltip": "Rectangle",
            "shapeType": "Rectangle",
            "strokeDashArray": null,
            "zOrder": 1,
            "strokeWidth": 2,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "width": 120,
            "height": 90,
            "key": -1,
            "loc": "71 116",
            "angle": 16.015439606265673
        }, {
            "category": "Basic",
            "icon": "ellipse_icon",
            "tooltip": "Ellipse",
            "shapeType": "Ellipse",
            "zOrder": 2,
            "strokeWidth": 2,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "width": 120,
            "height": 90,
            "key": -2,
            "loc": "67 221"
        }, {
            "category": "Basic",
            "icon": "square_icon",
            "tooltip": "Square",
            "shapeType": "Square",
            "strokeDashArray": null,
            "keepAspectRatio": true,
            "zOrder": 3,
            "strokeWidth": 2,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "width": 120,
            "height": 120,
            "key": -3,
            "loc": "62 343"
        }, {
            "category": "Basic",
            "icon": "circle_icon",
            "tooltip": "Circle",
            "shapeType": "Circle",
            "zOrder": 4,
            "keepAspectRatio": true,
            "strokeWidth": 5,
            "fill": "#2ECC71",
            "stroke": "#2E9ED8",
            "width": 120,
            "height": 120,
            "key": -4,
            "loc": "63 477",
            "strokeDashArray": [5, 5],
            "strokeCap": "butt",
            "strokeStyle": "dashed"
        }, {
            "category": "Basic",
            "icon": "diamond_icon",
            "tooltip": "Diamond",
            "shapeType": "Diamond",
            "zOrder": 5,
            "keepAspectRatio": true,
            "strokeWidth": 2,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "width": 120,
            "height": 120,
            "key": -5,
            "loc": "73 627"
        }, {
            "category": "Basic",
            "icon": "right_triangle_icon",
            "tooltip": "Right Angled Triangle",
            "shapeType": "RightTriangle",
            "zOrder": 6,
            "strokeWidth": 2,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "width": 120,
            "height": 120,
            "key": -6,
            "loc": "212 655"
        }, {
            "category": "BasicFlow",
            "icon": "square_icon",
            "tooltip": "Rectangle",
            "shapeType": "Rectangle",
            "text": "???",
            "zOrder": 7,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 128,
            "height": 78,
            "key": -7,
            "loc": "232 142"
        }, {
            "category": "BasicFlow",
            "icon": "circle_icon",
            "tooltip": "Circle",
            "shapeType": "Circle",
            "text": "???",
            "keepAspectRatio": true,
            "zOrder": 8,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -8,
            "loc": "222 262"
        }, {
            "category": "BasicFlow",
            "icon": "diamond_icon",
            "tooltip": "Diamond",
            "shapeType": "Diamond",
            "text": "q3aergdr",
            "keepAspectRatio": true,
            "zOrder": 9,
            "fill": "#2E9ED8",
            "stroke": "#2ECC71",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -9,
            "loc": "221 410"
        }, {
            "category": "BasicFlow",
            "icon": "circle_icon",
            "tooltip": "Circle",
            "shapeType": "Circle",
            "text": "???",
            "keepAspectRatio": true,
            "zOrder": 10,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -10,
            "loc": "255 598"
        }, {
            "category": "ComplexShape",
            "icon": "triangle_icon",
            "tooltip": "Triangle equilateral",
            "shapeType": "TriangleUp",
            "zOrder": 11,
            "keepAspectRatio": true,
            "strokeWidth": 2,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "width": 120,
            "height": 120,
            "key": -11,
            "loc": "391 124",
            "angle": 36.96428928946521
        }, {
            "category": "ComplexShape",
            "icon": "diamond_icon",
            "tooltip": "Rhombus",
            "shapeType": "Diamond",
            "zOrder": 12,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -12,
            "loc": "389 272"
        }, {
            "category": "ComplexShape",
            "icon": "x_icon",
            "tooltip": "'X' Shape",
            "shapeType": "ThinX",
            "zOrder": 13,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -13,
            "loc": "390 351"
        }, {
            "category": "ComplexShape",
            "icon": "arc_icon",
            "tooltip": "Quartered circle curves",
            "shapeType": "Curve4",
            "zOrder": 14,
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 60,
            "height": 110,
            "key": -14,
            "loc": "422 418",
            "angle": 303.27488798483495
        }, {
            "category": "ComplexShape",
            "icon": "trapezium_icon",
            "tooltip": "Trapezium shape",
            "shapeType": "Trapezoid",
            "zOrder": 15,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -15,
            "loc": "366 489",
            "angle": 331.45380926895666
        }, {
            "category": "ComplexShape",
            "icon": "3d-cube_icon",
            "tooltip": "3D cube shape",
            "shapeType": "Cube1",
            "zOrder": 16,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -16,
            "loc": "393 630",
            "angle": 6.709836807756933
        }, {
            "category": "ComplexShape",
            "icon": "3d-cylinder_icon",
            "tooltip": "3D cylinder",
            "shapeType": "Cylinder1",
            "zOrder": 17,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -17,
            "loc": "541 621"
        }, {
            "category": "ComplexShape",
            "icon": "btl.l-shape_icon",
            "tooltip": "L Shape",
            "shapeType": "btl.l-shape",
            "zOrder": 18,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -18,
            "loc": "538 481"
        }, {
            "category": "ComplexShape",
            "icon": "btl.t-shape_icon",
            "tooltip": "T Shape",
            "shapeType": "btl.t-shape",
            "zOrder": 19,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -19,
            "loc": "570 408"
        }, {
            "category": "ComplexShape",
            "icon": "btl.c-shape_icon",
            "tooltip": "C Shape",
            "shapeType": "btl.c-shape",
            "zOrder": 20,
            "fill": "#FFFFFF",
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "width": 120,
            "height": 120,
            "key": -20,
            "loc": "532 269"
        }, {
            "category": "LineShape",
            "tooltip": "Solid",
            "zOrder": 21,
            "stroke": "#2E9ED8",
            "strokeWidth": 2,
            "strokeDashArray": null,
            "strokeCap": "butt",
            "strokeStyle": "solid",
            "loc": "488 98",
            "leftArrowVisible": false,
            "rightArrowVisible": false,
            "arrows": true,
            "key": -21
        }, {
            "category": "LineShape",
            "tooltip": "Solid",
            "zOrder": 22,
            "stroke": "#FF644D",
            "strokeWidth": 10,
            "strokeDashArray": null,
            "strokeCap": "butt",
            "strokeStyle": "solid",
            "loc": "474 102",
            "leftArrowVisible": true,
            "rightArrowVisible": true,
            "arrows": true,
            "key": -22,
            "geo": "M0 0 L97 76",
            "arrow1Position": "-8 -8",
            "arrow1Angle": 38.07888236156501,
            "arrow2Angle": 38.07888236156501,
            "arrow2Position": "89 68"
        }, {
            "category": "Text",
            "angle": 0,
            "text": "Enter\nYour\nText",
            "textAlign": "center",
            "textColor": "#000000",
            "font": "italic 12pt Helvetica, Arial, sans-serif",
            "textStyle": "",
            "zOrder": 23,
            "width": 166,
            "height": 70,
            "loc": "704 147",
            "key": -23
        }, {
            "stroke": "#2ECC71",
            "strokeWidth": 5,
            "category": "FreehandShape",
            "width": 213,
            "height": 238,
            "key": -24,
            "loc": "715.5 193",
            "geo": "F M28 139 L28 139 L30 142 L31 147 L34 153 L36 158 L38 163 L39 166 L40 170 L41 172 L42 177 L43 182 L44 184 L44 186 L44 187 L44 188 L44 190 L44 191 L44 192 L44 194 L44 196 L45 199 L45 201 L46 202 L46 204 L46 206 L46 207 L47 209 L47 210 L47 212 L49 214 L49 216 L50 217 L51 219 L51 220 L52 222 L53 225 L54 226 L56 228 L58 229 L60 231 L63 233 L66 234 L67 235 L70 236 L72 237 L75 238 L77 238 L80 238 L83 238 L84 238 L86 238 L89 238 L91 238 L92 238 L96 238 L98 238 L101 238 L103 238 L107 238 L113 237 L118 236 L121 236 L123 235 L125 235 L127 234 L131 233 L135 232 L140 231 L143 230 L147 229 L150 228 L154 226 L158 225 L162 222 L167 221 L170 219 L172 219 L173 219 L174 219 L177 218 L178 218 L180 218 L181 218 L183 218 L185 218 L187 218 L190 217 L194 216 L197 215 L201 214 L204 211 L205 210 L206 208 L207 203 L209 197 L211 186 L212 174 L213 161 L213 149 L212 138 L211 128 L209 119 L207 108 L205 100 L204 95 L201 90 L201 84 L201 79 L201 75 L200 72 L199 69 L198 65 L198 63 L198 59 L198 56 L198 51 L198 49 L198 45 L197 42 L196 38 L196 36 L196 33 L196 30 L196 27 L195 25 L194 23 L193 21 L192 20 L191 19 L188 17 L184 15 L176 13 L166 11 L155 8 L147 7 L138 5 L129 3 L122 2 L117 1 L109 1 L104 1 L100 1 L94 1 L87 1 L81 0 L75 0 L71 0 L67 0 L64 0 L61 0 L53 0 L48 0 L44 0 L40 0 L36 0 L34 0 L33 0 L31 0 L30 0 L28 0 L26 0 L24 0 L20 0 L18 0 L16 0 L13 1 L11 1 L10 3 L8 3 L6 4 L5 6 L3 7 L2 9 L1 14 L0 22 L0 27 L0 32 L0 38 L1 44 L3 48 L6 54 L9 57 L11 61 L12 65 L14 67 L15 71 L17 74 L19 79 L21 81 L22 84 L23 86 L23 88 L24 90 L25 91 L25 92 L26 94 L27 95 L27 97 L28 98 L29 101 L29 103 L29 105 L29 108 L29 109 L29 113 L29 115 L29 116 L29 118 L29 119 L29 121 L30 124 L30 125 L30 127 L30 128 L30 129 L30 131 L31 131"
        }, {
            "stroke": "#000000",
            "strokeWidth": 3,
            "category": "FreehandShape",
            "width": 0,
            "height": 0,
            "key": -25,
            "loc": "657 338",
            "geo": "F M0 0 L0 0"
        }, {
            "stroke": "#000000",
            "strokeWidth": 3,
            "category": "FreehandShape",
            "width": 170,
            "height": 4,
            "key": -26,
            "loc": "744 339",
            "geo": "F M0 1 L0 1 L7 1 L18 1 L33 1 L51 1 L71 1 L86 1 L94 0 L96 0 L97 0 L101 0 L104 0 L109 0 L114 0 L116 0 L117 0 L120 0 L123 0 L126 0 L127 0 L128 0 L131 0 L135 1 L139 1 L142 2 L143 3 L144 3 L147 3 L151 3 L156 4 L163 4 L166 4 L167 4 L168 4 L169 4 L170 4"
        }, {
            "stroke": "#000000",
            "strokeWidth": 3,
            "category": "FreehandShape",
            "width": 183,
            "height": 10,
            "key": -27,
            "loc": "766.5 372",
            "geo": "F M0 0 L0 0 L4 1 L10 3 L24 5 L42 7 L64 9 L90 9 L115 10 L139 10 L159 10 L175 10 L181 10 L183 10"
        }, {
            "stroke": "#000000",
            "strokeWidth": 3,
            "category": "FreehandShape",
            "width": 207,
            "height": 4,
            "key": -28,
            "loc": "789.5 409",
            "geo": "F M0 0 L0 0 L5 0 L20 0 L45 1 L78 1 L120 2 L169 4 L193 4 L205 4 L207 4"
        }, {
            "stroke": "#000000",
            "strokeWidth": 3,
            "category": "FreehandShape",
            "width": 291,
            "height": 40,
            "key": -29,
            "loc": "762.8336827155185 500.8219885248894",
            "geo": "F M0 6 L0 6 L3 5 L7 2 L15 1 L27 0 L42 0 L59 0 L74 3 L84 6 L89 8 L90 10 L92 14 L96 19 L97 26 L100 39 L100 46 L100 50 L100 54 L99 58 L97 62 L94 67 L92 73 L89 81 L88 86 L87 91 L88 95 L90 99 L94 103 L101 107 L106 110 L114 116 L122 118 L131 120 L142 120 L152 120 L164 119 L174 116 L184 112 L189 111 L192 111 L195 111 L197 111 L199 111 L202 114 L204 118 L207 122 L210 128 L213 134 L215 138 L217 147 L219 150 L220 156 L222 160 L224 164 L226 168 L227 171 L230 174 L232 177 L236 179 L237 181 L238 181 L239 182 L242 182 L248 182 L253 182",
            "size": "291 40"
        }, {
            "stroke": "#000000",
            "strokeWidth": 3,
            "category": "FreehandShape",
            "width": 0,
            "height": 0,
            "key": -30,
            "loc": "773 472",
            "geo": "F M0 0 L0 0"
        }, {
            "category": "Text",
            "angle": 330.10109816138544,
            "text": "Enter\nYour\nText",
            "textAlign": "left",
            "textColor": "#000000",
            "font": "bold 12pt Helvetica, Arial, sans-serif",
            "textStyle": "",
            "zOrder": 24,
            "width": 166,
            "height": 70,
            "loc": "747 535",
            "key": -31,
            "isUnderline": true
        }
    ],
    "linkDataArray": [{
            "from": -7,
            "to": -8,
            "fromPort": "B",
            "toPort": "T",
            "visible": false,
            "points": [232, 187.5, 232, 197.5, 227, 197.5, 227, 185.5, 222, 185.5, 222, 195.5]
        }, {
            "from": -8,
            "to": -9,
            "fromPort": "B",
            "toPort": "T",
            "visible": false,
            "points": [222, 328.5, 222, 338.5, 221.5, 338.5, 221.5, 333.5, 221, 333.5, 221, 343.5]
        }, {
            "from": -8,
            "to": -9,
            "fromPort": "R",
            "toPort": "R",
            "visible": false,
            "points": [288.5, 262, 298.5, 262, 298.5, 410, 298, 410, 297.5, 410, 287.5, 410]
        }, {
            "from": -10,
            "to": -9,
            "fromPort": "T",
            "toPort": "B",
            "visible": false,
            "points": [255, 531.5, 255, 521.5, 255, 504, 221, 504, 221, 486.5, 221, 476.5]
        }
    ]
}

The alpha should be out later this month. I can let you know when we release it if you’d like. FYI, we’re currently planning to target .NET Framework 4.8, .NET 5 Windows, and .NET 6 Windows.

If you’d like to experiment sooner, I could send you a simplified kit. Just know that it’s still a work in progress and the documentation is not yet complete.

Actually, if you have the templates that the GoJS app uses, they are straight-forward to translate to C# with the new GoDiagram.

@jhardy, that won’t work for us. We have unfortunately a tighter timeline to push a mock to our client. I have no other option than to work the proof of concept with the current version of GoDiagram. I will however be very interested in knowing when you have a closer-to-production beta version of the new workflow. It’s very likely we will want to upgrade to it, especially if it makes things simpler.

@walter, good to know. I think I should be able to obtain the templates. And I’ll check GoDiagram documentation on how to apply these.

Hope we make business with your company.

I think it would be much easier for you if you give the new GoDiagram a try. It will be much simpler to get the GoJS templates written with it, and it includes JSON deserialization. You’d just need to write your templates, define your model structure, and do some sanitization of the GoJS JSON. We can help out with that if needed.

I can send you an example that demonstrates JSON deserialization and output to various image formats if you are interested.

Do you have a an expected release date? In the meantime, I’m willing to give it a go.

Hello @Marfig, for a demo, what version(s) of .NET are you currently targeting or intending to target?

I just sent a private message with a link to the kit you can try out.