NorthwoodsSoftware / GoJS

JavaScript diagramming library for interactive flowcharts, org charts, design tools, planning tools, visual languages.
http://gojs.net
Other
7.7k stars 2.86k forks source link

SVG output doesn't write the link to embedded bitmap files #121

Closed YanikTheYak closed 3 years ago

YanikTheYak commented 3 years ago

Following the fix to this issue: cannot render server side image that contains a Picture #80 https://github.com/NorthwoodsSoftware/GoJS/issues/80

I modified the sample code you provided in this fix to use the standard template example, but added a PNG to the template (see myDiagram below). Looking at the SVG produced there is no reference to the PNG file found in the output. I also added a Blue background, to the Picture component, as without it there is no reference to the Picture component at all. Since the Blue rectangle displays correctly, I believe the picture reference should also be there.

 // define a simple Node template
    myDiagram.nodeTemplate =
      $(go.Node, "Auto",  // the Shape will go around the TextBlock
        $(go.Shape, "RoundedRectangle", { strokeWidth: 0 },
          new go.Binding("fill", "color")),
        $(go.TextBlock,
          { margin: 8 },
          new go.Binding("text", "key")),
        $(go.Picture, {
            desiredSize: new go.Size(55,55),
            background: "blue",
            source: "images/55x55.png"
        })          
      );

    myDiagram.model = new go.GraphLinksModel(
      [
        { key: "Alpha", color: "lightblue" },
        { key: "Beta", color: "orange" },
        { key: "Gamma", color: "lightgreen" },
        { key: "Delta", color: "pink" }
      ],
      [
        { from: "Alpha", to: "Beta" },
        { from: "Alpha", to: "Gamma" },
        { from: "Beta", to: "Beta" },
        { from: "Gamma", to: "Delta" },
        { from: "Delta", to: "Alpha" }
      ]);
simonsarris commented 3 years ago

see myDiagram below

The code you have below only has a PNG, did you mean to paste something else?

YanikTheYak commented 3 years ago

Sorry, I meant PNG. (I tried both) I'll change the text so it matches. I'll attach the entire code too if that helps.

If you compare the original code from issue 80, with the code below. I changed it to use a local GoJS and replaced the use of myDiagram.add with a template node and a model, where the template node has an image. Hope this is clearer.

YanikTheYak commented 3 years ago

Full code from the original sample, including the change I made:


  const puppeteer = require('puppeteer');
  const fs = require('fs');

  const parseDataUrl = (dataUrl) => {
    const matches = dataUrl.match(/^data:(.+);base64,(.+)$/);
    if (matches.length !== 3) {
      throw new Error('Could not parse data URL.');
    }
    return { mime: matches[1], buffer: Buffer.from(matches[2], 'base64') };
  };

  (async () => {
    const browser = await puppeteer.launch({
      // headless: false,
      // devtools: true
    });
    const page = await browser.newPage();
    page.setContent('<div id="myDiagramDiv"></div>');

    await page.addScriptTag({
      url: 'https://gojs.net/2.0.14/release/go.js'
      // path: 'node_modules/gojs/release/go.js'
    });

    const results = await page.evaluate(() => {
      var $ = go.GraphObject.make;
      var myDiagram = $(go.Diagram, "myDiagramDiv",
        {
          "animationManager.isEnabled": false,
          "undoManager.isEnabled": true  // enable undo & redo
        });

      // define a simple Node template
      myDiagram.nodeTemplate =
        $(go.Node, "Auto",  // the Shape will go around the TextBlock
          $(go.Shape, "RoundedRectangle", { strokeWidth: 0 },
            new go.Binding("fill", "color")),
          $(go.TextBlock,
            { margin: 8 },
            new go.Binding("text", "key")),
          $(go.Picture, {
            desiredSize: new go.Size(55, 55),
            background: "blue",
            source: "images/55x55.png"
          })
        );

      myDiagram.model = new go.GraphLinksModel(
        [
          { key: "Alpha", color: "lightblue" },
          { key: "Beta", color: "orange" },
          { key: "Gamma", color: "lightgreen" },
          { key: "Delta", color: "pink" }
        ],
        [
          { from: "Alpha", to: "Beta" },
          { from: "Alpha", to: "Gamma" },
          { from: "Beta", to: "Beta" },
          { from: "Gamma", to: "Delta" },
          { from: "Delta", to: "Alpha" }
        ]);

      myDiagram.makeImageData({
        callback: function (imagedata) {
          const { buffer } = parseDataUrl(imagedata);
          fs.writeFileSync('_gojs-screenshot.png', buffer, 'base64');
        }
      });

      const getIMG = () => {
        return new Promise((resolve, reject) => {
          myDiagram.makeImageData({
            background: 'red',
            size: new go.Size(300, NaN),
            callback: function (data) {
              resolve(data);
            }
          });
        })
      }

      async function fetchIMG() {
        return await getIMG();
      }

      const getSVG = () => {
        return new Promise((resolve, reject) => {
          myDiagram.makeSVG({
            size: new go.Size(300, NaN),
            callback: function (svgdata) {
              let svgstr = new XMLSerializer().serializeToString(svgdata);
              console.log(svgstr)
              resolve(svgstr)
            }
          });
        })
      }

      async function fetchSVG() {
        return await getSVG();
      }

      // var results =  [fetchIMG(), fetchSVG()];
      return fetchSVG();
    });

    console.log(results);
    fs.writeFileSync('_gojs.svg', results);
    //const { buffer } = parseDataUrl(imagedata);
    //fs.writeFileSync('_gojs-screenshot.png', buffer, 'base64');

    await browser.close();
  })();
YanikTheYak commented 3 years ago

The SVG output contains the blue rectangle, but not the xlink for the image:

 <rect x="0" y="0" width="55" height="55" fill="blue" stroke="none"
                    transform="matrix(1, 0, 0, 1, 2.761423749153968, 2.761423749153968)" />

I think it should include this:

xlink:href="images/55x55.png"
simonsarris commented 3 years ago

I see what you mean. I'll investigate and get back to you.

simonsarris commented 3 years ago

This is fixed and will be out with the next release, probably within a week. Thanks for reporting.

If you need a workaround in the meantime you may need to use elementFinished, something like:

elementFinished: function(obj, svg) {
  if (obj instanceof go.Picture) {
    if (svg.getAttribute("xlink:href") === null && svg.getAttribute("href") === null)
    svg.setAttribute("xlink:href", obj.source);
  }
}

should work.

YanikTheYak commented 3 years ago

Quick work. Thanks so much!!

simonsarris commented 3 years ago

This should now be fixed in the newest release, GoJS 2.1.32.