yFiles AJAX Tutorials

The following yFiles AJAX tutorials are contained in this document:

Tutorial: Using yFiles AJAX

Using yFiles AJAX means writing a web application using yFiles AJAX servlets on the server side and yFiles AJAX JavaScript classes on the client side. The action framework that is part of the yFiles AJAX API simplifies adding server side functionality. The next tutorial provides details on using the action framework. The third tutorial describes how to use a custom servlet for extending the server side. In this tutorial, we start by just using the existing components for the client and the server side.

Information on writing web applications in general can be found in this tutorial. General information on using Dojo can be found in the documentation section of the Dojo website.

The source code for the demos and tutorials which ship with yFiles AJAX is included in the distribution:

Note that the sources are not available online, i.e. you cannot get them from live.yworks.com. The demo source code demonstrates some of the possibilities of yFiles AJAX. In the following, we describe how to use yFiles AJAX and how to extend it using simpler examples which are derived step by step in order to explain the basics.

The following describes the steps to set up a basic web application using yFiles AJAX as a tutorial. We want to achieve this result (opens in another window or tab).

  1. There is one GraphCanvas displaying a fixed graph.
  2. It supports panning, i.e., dragging the graph with the mouse.
  3. It supports zooming with the mouse wheel and provides additional zoom buttons.

We assume some basic knowledge on writing web applications. Modern IDEs like Eclipse or IDEA provide useful tools for doing this. See also the sections "Using an IDE" and "Creating an Eclipse project for the yFiles AJAX demo web application" of the readme file.

Step 1: Setting Up the Server Side

In step 2 of this tutorial we'll add the index.html file. The resulting directory structure of your web application should look like this.

Step 2: Creating a Dojo-Enabled Web Page

Create a new HTML page in the main directory of your web application. There is some basic JavaScript code which needs to be loaded into an HTML page in order to use Dojo with it. Add the following to the head of your HTML page.

  var dojoConfig = {
    isDebug: false,
    baseUrl: "../javascript/",
    tlmSiblingOfDojo: false,
    packages: [
      { name: "dojo", location: "dojo" },
      { name: "dijit", location: "dijit" },
      { name: "dojox", location: "dojox" },
      { name: "yfiles", location: "yfiles", main: "yfiles" },
      { name: "demos", location: "demos", main: "demos" }
<script data-dojo-config="async: true" src="../javascript/dojo/dojo.js"></script>

The src attribute describes the path to the basic Dojo JavaScript file in the directory structure as described in the last step. If you move your HTML page to another directory, the path has to be adapted.

Step 3: Adding the GraphCanvas

Now we add the layer (Dojo term for a packaged JavaScript source file, more information can be found in the yFiles AJAX Developer's Guide in this section), which contains the yFiles AJAX client side components. Therefore we load an additional JavaScript file by adding the following line below the line for adding Dojo itself.

<script src="javascript/dojo/yfiles-ajax.js"></script>

Now you can add the GraphCanvas to the body of the page. The GraphCanvas is a Dojo widget (reusable user interface element). It uses the space provided by its parent element in the HTML page. In this case we use a div with 400 pixels width and height as the frame for the graph canvas.

<div style="width: 400px; height: 400px; border: solid blue;">
  <div data-dojo-type="yfiles/client/tiles/widget/GraphCanvas" id="canvas" data-dojo-props="path:'computers.graphml'"></div>

The id attribute of the GraphCanvas is needed to identify the widget in custom JavaScript code. This will be used in the next step of this tutorial. The path attribute tells the canvas which graph to display. It is not mandatory, because there is also a function for setting the graph to be displayed any time after the widget was created.

To create the dojo widget from the <div> element, we need to invoke dojo's parser after the DOM and all required AMD modules have been loaded:

    [ "dojo/ready","dojo/parser"],
    function(ready, parser) {
      ready(function() {

Step 4: Adding the Zoom Buttons

Zooming with the mouse wheel and panning are default features of the graph canvas, thus there is no need for configuration or additional code to handle that. In order to demonstrate how to reference the graph canvas using custom JavaScript code we add two zoom buttons to the page.

  <button>Zoom In</button>
  <button>Zoom Out</button>

You can get a reference to a specific Dojo widget with a known id by using registry.byId() (provided by the dijit/registry module). The graph canvas has a readonly attribute zoom holding the current zoom factor and a function setZoom() for setting a new zoom factor. In addition, the canvas offers convenience functions to increase and decrease the zoom level: increaseZoom(factor) and decreaseZoom(factor). We will call these functions when the zoom buttons are clicked:

      [ "dojo/ready","dojo/parser","dojo/on","dojo/dom","dijit/registry","yfiles/client/tiles/widget/GraphCanvas"],
      function(ready, parser, on, dom, registry) {

        var init = function() {
          var canvas = registry.byId('canvas');
          on(dom.byId("zoomIn"),"click",function() { canvas.increaseZoom(2.0); } );
          on(dom.byId("zoomOut"),"click",function() { canvas.decreaseZoom(2.0); } );

        ready(function() {

This concludes the tutorial. The complete source code of the HTML page can be viewed by using the view source feature of your browser for this page. The file is also available at demos/web-content/html/basic.html in the yFiles AJAX distribution.

NOTE: The graph canvas has an additional parameter baseURL:'..' in the HTML page for this tutorial at the location in the yFiles AJAX distribution. The baseURL attribute is needed, if the HTML page does not reside in the main directory of the web application, because the server requests from the graph canvas always use relative URLs. The example resides in the subdirectory html. Thus the baseURL attribute has the value "..". Moreover, the paths for including the dojo.js file and the JavaScript files for yFiles AJAX in the header are adapted.

Tutorial: Treasure Hunt (Extending yFiles AJAX using the Action Framework)


You can extend yFiles AJAX both on the client and on the server side. On the client side, you can for example add new widgets which react to events provided by existing yFiles AJAX widgets. An example for this is the ViewPortMarker widget, which adds new functionality on the basis of two GraphCanvas instances.

Another example for a client side extension is the GraphInfo widget which displays information on the graph as a whole or on parts of it like a single node. It relies on information provided from the server side. This information is produced by the InfoServlet, which is an example of a server side extension. Using a custom servlet is part of the next tutorial.

In this tutorial we create a simple game: "Treasure Hunt": A graph is displayed and a treasure is hidden at one of its nodes. If the player clicks a node, it will either be the right one with the treasure, or it is another node without the treasure. If there is no treasure, the player gets a hint that the treasure is for example two nodes away.

There are of course several ways to implement this game. Just selecting a random node at the beginning and then checking whether it has been clicked can be done without any server call. Computing the distance to the node with the treasure would be rather complicated, since the graph structure (what are the neighbors of a node?) is not present at the client side.

yFiles for Java, which is available at the server side, does have access to the graph structure. Moreover, it offers an algorithm for computing the distance from one node to every other node in the graph. Let's just use that. We could wrap the call to the algorithm with a custom servlet. The next tutorial describes the approach of creating a custom servlet and calling it from the client side.

In this tutorial we'll use the action framework instead of writing a custom servlet. It simplifies adding custom server side behavior triggered by the client side to a web application with yFiles AJAX.

NOTE: This tutorial is based on the last tutorial. We assume that the HTML page is located in the main directory of the web application as in the last tutorial. If this is not the case some paths need to be adjusted.

Step 1: Change the Title and the Body of the Page

We want to display a graph and thus use a GraphCanvas as in the previous tutorial. We need a way to let the player pick a node. The graph canvas has some functions for mouse events related to nodes. They are called, if we tell the canvas that we are interested in node events. This can be done in the HTML markup of the canvas. We'll use a different graph this time and a larger canvas. Since we want to run some code after the graph has been loaded (computing the distances for the first time), we do not specify the graph in the markup for the canvas, but set the path for the graph in JavaScript code in order to be able to define a callback for the event that the graph was loaded. In the body of the page, we use the canvas adapted as mentioned above, and a placeholder for displaying hints for the player: an initially empty paragraph with the id hint.

<h1>Treasure Hunt</h1>

  There is a treasure hidden at one of the nodes!

<div style="width: 600px; height: 500px; border: solid blue;">
  <div data-dojo-type="yfiles/client/tiles/widget/GraphCanvas" id="canvas" data-dojo-props="nodeEvents:true"></div>

<p id="hint"></p>


We also change the title of the page by replacing the previous title line in the head of the page with the following one.

  <title>Treasure Hunt</title>

Step 2: Add the Action (Client Side)

The action framework contains one class for the client side: ServerAction. An instance of ServerAction wraps the call to the server triggering a server side action. It sends some information about the client state to the server and takes care of the server response. This means that you do not have to create a new protocol to talk to your server side code.

Initially and every time the player has found the treasure we hide a new treasure at a random node and compute all the distances from all nodes to the node with the treasure on the server side. If the player clicks a node, we use the distance information to decide whether the treasure was found or to display a hint with the distance to the treasure. The client side of the action for hiding the treasure, the hideTreasureAction, is created as follows in a new JavaScript block in the head of the page after the block with the require calls.


     function(ServerAction) {

        var canvas, hint, distances;
        var hideTreasureAction = new ServerAction({
          url :       '../yFilesAction',
          id :        'yworks.demos.actions.hideTreasure',
          graphName : 'treasure-islands.graphml',
          postRun :   function() {
            distances = JSON.parse(this.getCustomResponse());


The handler for the server side action is identified by the id yworks.demos.actions.hideTreasure. We tell the server side which graph to use by specifying the symbolic name of the graph. The graph file treasure-islands.graphml has to be added to the resources/graphs directory.

The function with the postRun key in the parameter object provided to the ServerAction constructor is called whenever a response from the server arrives (and no error occurred). The function is called without any parameters, but it is called in the scope of the calling ServerAction instance, so we can use this inside the postRun function to access the calling action. The postRun function of the hideTreasureAction uses the access to the calling action for getting the response from the server side code: this.getCustomResponse(). The custom response from the server, which is always a string, is expected to be in JSON format and a JavaScript object distances is constructed from it.

Step 3: Initialize the Client Side Behavior

The canvas has the following functions dealing with node events. Since we enabled node events in Step 1, these functions will be called with the id of the node as the argument, if the corresponding events happen.

In order to run the hide treasure action initially and to set up the event handling, we use a function init, which should be executed once after the page is loaded and the canvas is constructed. In the init function we first set the path to the graph. This triggers loading the graph on the server. When the graph is loaded, we run the hide treasure action for the first time and connect the onClickNode, onTapNode, and onMouseOutNode events of the graph canvas. The script block now looks like this:


  function(ready, parser, dom, on, aspect, JSON, lang, registry, GraphCanvas, ServerAction) {

    var canvas, hint, distances;
    var hideTreasureAction = new ServerAction({
      url :       '../yFilesAction',
      id :        'yworks.demos.actions.hideTreasure',
      graphName : 'treasure-islands.graphml',
      postRun :   function() {
        distances = JSON.parse(this.getCustomResponse());

    function init() {
      canvas = registry.byId('canvas');
      hint = dom.byId('hint');
      on(canvas, 'PathSet', onPathSet);

      // make zoomToPoint the default behaviour, for simple zoom hold the ctrl key
      canvas.zoomToPointRecognizer = function(evt) {
        return !evt.ctrlKey;

    function onPathSet() {
      on(canvas, 'ClickNode', feedback);
      on(canvas, 'TapNode', feedback);
      on(canvas, 'MouseOutNode', function() {
        hint.innerHTML = ' ';

    function feedback(id) {
      // TODO

    ready(function() {

The effect of a call like on(canvas, 'ClickNode', feedback); is that each time the onClickNode function of the canvas is called, the feedback function is called immediately afterwards with the same parameters. We'll define the feedback function in the next step. The parameter of the onClickNode function of the canvas is the id of the node which was clicked. We could also interpret the mouse enter event as searching for the treasure, but that would probably lead to too much accidental searching. We use the onMouseOut event to remove the hint again.

Step 4: Provide Feedback

For providing the feedback to the user, we use the feedback function in the JavaScript block in the header.

function feedback(nodeId) {
  if (!distances) {

  var distance = distances[nodeId];
  if (distance == 0) {
    // Hide another treasure.
    distances = null;

    // Congratulations!
    alert('Congratulations! You found the treasure!\n\nThere is yet another treasure...');
  } else {
    // Display hint.
    var distStr = distance == 1 ? "one node" : distance + " nodes";
    hint.innerHTML = 'No, there is no treasure here, but it is only ' +
      distStr + ' away. Keep on searching!';

We obtain the distance from the node where the user is searching to the treasure from the distances object. We assume that it looks like the following JavaScript object (we'll take care of that assumption on the server side).

    "n-0" : 1,
    "n-1" : 0,
    "n-2" : 1,
    "n-3" : 2

For each member, the key is the id of a node of the graph and the value is the length of the shortest path from this node to the treasure or, in other words, the distance to the treasure. If the distance is 0, the player found the treasure, congratulations and the game starts again. Otherwise we tell the player the current distance to the treasure by populating the hint placeholder in the page. The complete client side page looks like this (use the view source feature of your browser).

NOTE: The complete tutorial HTML page is located in the subdirectory html in the yFiles AJAX web application. Therefore, some paths have to be adjusted. This is relevant for including the JavaScript files for Dojo and yFiles AJAX in the header and for the calls to the server side made by the canvas and the server action instance. The canvas has a baseURL attribute for this purpose, which was already mentioned in the previous tutorial. The server action has an optional parameter url which specifies the relative URL of the generic ActionServlet on the server which takes care of dispatching requests made by ServerAction instances on the client.

Step 5: Add the Action (Server Side)

As already mentioned, you do not have to write your own servlet, if you use the action framework. You can write an action handler instead, which implements the ActionHandler interface. There is just one method to be implemented in the action handler interface: handleAction. It takes two parameters. The first parameter, an ActionContext instance, describes the client side environment for the action (e.g. the graph to be considered). The second parameter, a ClientControl instance, allows to control the client side post-processing. The client control also offers a method for setting the custom response.

Create a new class implementing the ActionHandler interface, e.g. tutorials.HideTreasureAction.

  package tutorials;

  import com.yworks.yfiles.server.tiles.servlet.action.ActionHandler;
  import com.yworks.yfiles.server.tiles.servlet.action.ActionContext;
  import com.yworks.yfiles.server.tiles.servlet.action.ClientControl;

  public class HideTreasureAction implements ActionHandler {
    public void handleAction(ActionContext context, ClientControl control) {

In the implementation of the handleAction method for the hide treasure action, we first need to find out for which graph to hide a treasure. The action context provides the actual graph instance for the symbolic graph name sent from the client.

  public void handleAction(ActionContext context, ClientControl control) {
    // Get the graph specified by the client request.
    Graph2D graph = context.getGraph();

Note that the graph could be null depending on the parameters of the client side ServerAction instance, but for the hide treasure action this should not happen. The next step is to select a node for hiding the treasure.

    // Select a treasure node.
    Node treasureNode = chooseTreasureNode(graph);

Then we compute the distances to the treasure node by means of an algorithm provided by the yFiles for Java ShortestPaths class.

    // Compute the distances.
    double[] distances = new double[graph.N()];
    ShortestPaths.uniform(graph, treasureNode, false, distances);

Finally, we return the distances as a JSON string.

    // Send the distances to the client.
    control.setCustomResponse(createJSONDistancesString(graph, distances));

Choosing a random node in the graph can be done by using a yFiles for Java node cursor and a random position in a separate private helper method of the HideTreasureAction.

  private Node chooseTreasureNode(Graph2D graph) {
    // Hide the treasure at a random node.
    Random random = new Random();
    int nodeCount = graph.N();
    int position = random.nextInt(nodeCount);
    int count = 0;
    for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
      if (count++ == position) {
        return nodeCursor.node();
    return null;

For creating the JSON string containing the distances from the treasure node to the other nodes we use the JSONStringBuilder class in another private helper method.

  private String createJSONDistancesString(Graph2D graph, double[] distances) {
    // Create a string in JSON format containing the distances to the treasure node.
    JSONStringBuilder builder = new JSONStringBuilder();
    for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
      Node node = nodeCursor.node();
      builder.addMember(BaseServlet.getId(graph, node), (int) distances[node.index()]);
    return builder.getJSONString();

Note that the index of a node is not an id, if the graph is allowed to change. The index is unique, but it changes, if the graph structure changes. In the treasure hunt game the graph does not change, but since yFiles AJAX also allows changing the graph, the index cannot be used as an id for a node. Instead, yFiles AJAX uses ids which can be retrieved by using public static methods of the BaseServlet.

Step 6: Register the Action

Requests from client side ServerAction instances are handled by by the generic ActionServlet which is part of yFiles AJAX. It uses the action id (e.g. yworks.demos.actions.hideTreasure), which is part of the request, to look up the right action handler. The action handler is registered with the ActionServlet by means of an initialization parameter in the web.xml file for the application. Add an entry for the ActionServlet and a corresponding servlet mapping to your web.xml file, if they are not already there (note that the entries in the web.xml file have to be ordered according to their types, e.g. mappings need to be declared after all servlet entries).

    <display-name>Action Servlet</display-name>
    <description>handles custom actions</description>


The name of the parameter is the id for the action (yworks.demos.actions.hideTreasure) and the value is the fully qualified class name of the class implementing the server side of the action (tutorials.HideTreasureAction). The name of the request is yFilesAction by default, but it can be configured in the client side ServerAction class and the web.xml file.

This concludes the second tutorial. The complete source code of the HideTreasureAction can be found in the demos/src folder in package com.yworks.yfiles.server.tiles.demos.

More information on the action framework is available in this section of the Developer's Guide for yFiles AJAX.

The Swimlanes demo application also uses the action framework.

Tutorial: Extending yFiles AJAX using a Custom Servlet

In this tutorial we want to extend the basic example developed in the first tutorial in order to be able to collapse and expand subtrees of a rooted tree, if the user clicks a node label showing either a + or a - sign depending on the collapsed/expanded state of the subtree rooted at that node. The graph resulting from an expand or collapse operation should be redrawn to display the additional nodes after an expand operation and to show a more compact drawing after a collapse operation, respectively. Initially, most nodes should be hidden.

For this tutorial, we want to use a different page layout. The graph canvas should use the whole page, and adapt it's size to page resize events.

From a high-level perspective, we have the following new requirements.

Step 1: Extend the Server Side

Unless the action framework (described in the previous tutorial) is used, extending the server side typically means adding new servlets and servlet mappings to the web application. In this case we add the TreeCollapserServlet to the server side.

Since this is not a tutorial on yFiles for Java, we will not go into all the details of the new servlet (the source code is commented, too), but just mention some important points.

Add the servlet and mappings for "initialize" and "toggleNode" to the web deployment descriptor.

  <display-name>Tree Collapser Servlet</display-name>
  <description>collapses and expands subtress of a tree</description>

Step 2: Writing a Controller for the Client Side

On the client side, it is possible to react to graph events by connecting to the graph events of interest. These events are fired by the graph canvas. As an example, please have a look at the sources of the TutorialGraphListener module, which connects to the onClickNodeLabel event. Copy the file TutorialGraphListener.js to a subdirectory tutorials of the javascript. The module can then be loaded as an AMD module from tutorials/TutorialGraphListener.

The TutorialGraphListener is defined using a dojo declare() call for creating classes. The declare is provided by the dojo/_base/declare AMD module:

    function(declare) {
      return declare(null, {
The constructor for a new instance is the constructor function. The TutorialGraphListener stores a reference to the canvas and calls _initializeGraph() in order to set up the initial graph. As a third step, it connects the onClickNodeLabel function of the canvas with its own onClickNodeLabel function. This causes the onClickNodeLabel function of the TutorialGraphListener to be called once after each call to onClickNodeLabel on the canvas, passing the same arguments. The first argument given to onClickNodeLabel is the id of the clicked node label.

In _initializeGraph() an "initialize" request is sent to the servlet defined in step 1. Additionally, the canvas is set to the graph created as a result of the "initialize" request. The second step depends on the first one. It can only succeed, if the graph is already cached. Note that dojo.xhrPost() is asynchronous by default. Calling setPath() as a separate statement after the dojo.xhrPost() call would thus fail sometimes. dojo.xhrPost() can be made synchronous, but that locks the browser GUI and thus is not advisable. If the server request initiated by dojo.xhrPost() succeeds, Dojo calls the "load" function from the anonymous parameter object supplied to the call. Using the load function is a nice possibility to synchronize code depending on the outcome of a former server call without using synchronous server calls.

We add our custom click behavior in the onClickNodeLabel() function of the TutorialGraphListener. If the user clicks a node label, we send a request to the new servlet, "toggleNode" in this case, and refresh the canvas once the server side operation has succeeded.

The response for the "toggleNode" request is an object encoded with JSON (JavaScript Object Notation), additionally surrounded by a comment. Dojo supports this encoding and returns the evaluated string as a JavaScript object to the load function as the first parameter. The JSON object is surrounded by a comment for security reasons.

The response of the "toggleNode" is an object with two attributes, bounds and shift. bounds contains the new graph bounds after the toggle node operation, and shift describes the displacement of the given node as a result of the server side operation (which includes redrawing the tree). There is a refresh function on the graph canvas which can be supplied with the bounds and the shift, such that the graph display is refreshed and the node which was clicked by the user remains at the same position. This helps the user to maintain his mental map of the graph after the expand/collapse operation.

Step 3: Adapting the HTML Page

As a final step we have to adapt the HTML page from the previous tutorial, such that the graph listener from step 2 is used. Copy your previous HTML file and remove everything in the body (between <body> and </body>). First, we change the requires section in the head of the page as follows.

<script type="text/javascript">
  dojo.registerModulePath("tutorials", "../tutorials");

Now we want to use the listener. We cannot create the listener in a script section in the head, because it depends on the canvas which might not have been created yet. We create the listener on page load using dojo.addOnLoad(). This way, we can be sure that the canvas widget is already constructed. To this end, we add a JavaScript section to the end of the body of the page which creates an instance of the listener.

<script type="text/javascript">
  dojo.addOnLoad(function() {
    var canvas = dijit.byId('canvas');
    new tutorials.TutorialGraphListener(canvas);

Next, we change the canvas such that it no longer loads the graph from the previous tutorial by removing the path attribute. Additionally, we enable reporting of node label events by setting nodeLabelEvents to true.

<div dojoType="yfiles.client.tiles.widget.GraphCanvas" id="canvas" nodeLabelEvents="true"></div>

Disabling scroll bars and allowing the canvas to use the whole visible area can be achieved by removing the div enclosing the graph canvas, and by adding the following style section to the head of the HTML page.

<style type="text/css">
  html, body, #canvas {
    width: 100%; /* fill the visible area */
    height: 100%;
    overflow: hidden; /* erase scrollbars */
    padding: 0 0 0 0;
    margin: 0 0 0 0;

That's it! The complete source code of the HTML page can be viewed by using the view source feature of your browser for this page. You will also find the sources in the distribition at demos/web-content/html/extended.html.

Copyright © 2006-2013 yWorks GmbH. All Rights Reserved.