# Creating Images on the Server

It may be useful for many applications to create images of Diagrams with GoJS, and this page details some of the options for such a task.

## PhantomJS

One of the best options for creating images server-side (or anywhere) is PhantomJS, a platform-agnostic "headless" implementation of WebKit. PhantomJS allows us to run anything we would normally run inside of a browser in a command shell (terminal, command prompt), creating screen captures or image output as we go.

The following code is a small example using PhantomJS. If you saved the JavaScript as `createImage.js` and ran it with phantom (`phantomjs createImage.js`) it would create an image of a Diagram called `myDiagramImage.png`. It has the requirement that `go.js` is in the same folder, though this path can be modified as appropriate. The Diagram code in the sample is the same as that in the Minimal sample.

    // Example of (server-side or headless) image creation using PhantomJS
    // PhantomJS can be found at: https://github.com/ariya/phantomjs

    // Our page will contain nothing but a div tag and an img tag.
    // We will create our Diagram on the div and use Diagram.makeImageData to give the img a source.
    // Then we will render only the image created.
    var page = require('webpage').create();
    page.content = '<html><body><div id="myDiagramDiv"></div> <img id="myImg" /></body></html>';

    // We include go.js before acting on our page, assuming it is in the same directory
    page.injectJs('go.js');

    page.evaluate(function() {
      // GoJS is loaded, now we set up a diagram and make the image we want

      // This example GoJS code is taken from the Minimal.html sample
      var $ = go.GraphObject.make;  // for conciseness in defining templates

      myDiagram = new go.Diagram("myDiagramDiv");  // create a Diagram for the DIV HTML element
      myDiagram.initialContentAlignment = go.Spot.Center;

      // define a simple Node template (but use the default Link template)
      myDiagram.nodeTemplate =
        $(go.Node, "Auto",
          $(go.Shape, "RoundedRectangle",
            // Shape.fill is bound to Node.data.color
            new go.Binding("fill", "color")),
          $(go.TextBlock,
            { margin: 3 },  // some room around the text
            // TextBlock.text is bound to Node.data.key
            new go.Binding("text", "key"))
        );

      // create the model data that will be represented by Nodes and Links
      var nodeDataArray = [
        { key: "Alpha", color: "lightblue" },
        { key: "Beta", color: "orange" },
        { key: "Gamma", color: "lightgreen" },
        { key: "Delta", color: "pink" }
      ];
      var linkDataArray = [
        { from: "Alpha", to: "Beta" },
        { from: "Alpha", to: "Gamma" },
        { from: "Beta", to: "Beta" },
        { from: "Gamma", to: "Delta" },
        { from: "Delta", to: "Alpha" }
      ];
      myDiagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
      // end of code from Minimal.html sample

      var img = document.getElementById('myImg');
      img.src = myDiagram.makeImageData({
        scale: 1,
        // PhantomJS tends to handle transparency poorly in the images it renders,
        // so we prefer to use a white background:
        background: "white"
      })

      document.body.style.margin = '0px';
    });

    // We want to ensure that the image is done loading before we render
    setInterval(function() {
      var imgComplete = page.evaluate(function() {
        return document.getElementById('myImg').complete
      });

      if (imgComplete) {
        // PhantomJS renders the entire page, and we just want to output the <img>,
        // so we must clip to its bounding rect:
        var clipRect = page.evaluate(function() {
          return document.getElementById('myImg').getBoundingClientRect();
        });
        page.clipRect = {
          top:    clipRect.top,
          left:   clipRect.left,
          width:  clipRect.width,
          height: clipRect.height
        }
        page.render('myDiagramImage.png');
        phantom.exit();
      }
    }, 100);

Since PhantomJS contains a full, native DOM implementation, any work you wish to do with GoJS server-side (such as complex layouts or positioning) is also entirely possible.

## Using GoJS with Node.js

GoJS can also be used with Node.js for server-side image creation, though Node.js does not have native support for DOM, CSS, or the canvas element. Therefore using Node.js with GoJS requires the installation of Node packages for DOM and canvas simulation that are not guaranteed to work. To use the GoJS library with Node.js, you must install the following:

- NodeJS: https://nodejs.org/download/
- node-canvas: https://github.com/LearnBoost/node-canvas/wiki
- JSDom: https://github.com/tmpvar/jsdom

We recommend that you follow the installation instructions for each of these carefully, as there are a few dependencies, such as Python for Node's package manager.

The following code gives a complete example of create a Diagram inside of Node.js and outputting it to a site. The Diagram code in the sample is the same as that in the Minimal sample.

    // Example of server-side image creation using Node.js
    // Node.js can be found at https://nodejs.org

    // Module dependencies
    var http = require("http");
    var fs = require("fs");
    var Canvas = require('canvas'); // https://github.com/LearnBoost/node-canvas
    var jsdom = require('jsdom');  // https://github.com/tmpvar/jsdom

    // Navigating to lochalhost:8888 will show an image of a Diagram made server-side with Node.js
    http.createServer(function(request, response) {
      writeResponse(response);
    }).listen(8888);

    function writeResponse(response) {
      // In writing our response, we use jsdom to create a fake window and DOM,
      // create a Diagram in that environment, and
      jsdom.env(
        '<html><body></body></html>', // we create an empty HTML page
        ["go.js"], // assuming go.js is in the same folder as this file
        function(errors, window) {
          // Necessary in this environment, as typing simply "go" will not find "window.go"
          // Alternatively, we could have written this statement in makeDiagramAndData,
          // or made it global here
          var go = window.go;

          var data = makeDiagramAndData(window, go);

          if (response) {
            response.writeHeader(200, {"Content-Type": "text/html"});
            response.write('<img src="' + data + '" />');
            response.end();
          }
        }
      );
    }

    // All GoJS specific code is in this function
    function makeDiagramAndData(window, go) {
      // This example GoJS code is taken from the Minimal.html sample
      var $ = go.GraphObject.make;  // for conciseness in defining templates
      myDiagram = new go.Diagram(); // Note that no DIV is supplied

      // define a simple Node template (but use the default Link template)
      myDiagram.nodeTemplate =
        $(go.Node, "Auto",
          $(go.Shape, "RoundedRectangle",
            // Shape.fill is bound to Node.data.color
            new go.Binding("fill", "color")),
          $(go.TextBlock,
            { margin: 3 },  // some room around the text
            // TextBlock.text is bound to Node.data.key
            new go.Binding("text", "key"))
        );

      // create the model data that will be represented by Nodes and Links
      var nodeDataArray = [
        { key: "Alpha", color: "lightblue" },
        { key: "Beta", color: "orange" },
        { key: "Gamma", color: "lightgreen" },
        { key: "Delta", color: "pink" }
      ];
      var linkDataArray = [
        { from: "Alpha", to: "Beta" },
        { from: "Alpha", to: "Gamma" },
        { from: "Beta", to: "Beta" },
        { from: "Gamma", to: "Delta" },
        { from: "Delta", to: "Alpha" }
      ];
      myDiagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
      // end of code from Minimal.html sample

      // Create image data
      return myDiagram.makeImageData({
        scale: 1
      });
    }

### Known issue with Node.js and node-canvas

As of December 2012, node-canvas does not parse named CSS colors unless the names are all lowercase. This means that "Blue" may not parse correctly, but "blue" will.