6 Replies Latest reply on Jun 19, 2015 1:06 AM by sandy4you

    How to display a Binary Tree ?

    sandy4you

      Hi All,

      I have a JSON coming from External System, this JSON values are then converted to a Binary Tree and the same needs to be displayed on the GUI.

      The JSON is as shown below:

      {

        "name":   "Selection 1",

        "values": ["Value 1.a", "Value 1.b"],

        "trueNode": {

          "name":   "Selection 1.1",

          "values": ["Value 1.1.a"],

          "trueNode": {

              "name":   "E 1.1",

              "sms":    "TemplateSMS 1.1",

              "letter": "TemplateLetter 1.1"

          },

          "falseNode": {

            "name":   "Selection 1.2",

            "values": ["Value 1.2.a", "Value 1.2.b", "Value 1.2.c"],

            "falseNode": {

              "name":   "E 1.2",

              "email""TemplateEmail 1.2"

            }

          }

        },

        "falseNode": {

          "name":   "Selection 2",

          "values": ["Values 2.a", "Values 2.b"],

          "trueNode": {

            "name":   "Selection 2.1",

            "values": ["Values 2.1.a", "Values 2.1.b", "Values 2.1.c"],

            "trueNode": {

              "name":   "E 2.2"

            },

            "falseNode": {

              "name":   "Selection 2.2",

              "values": ["Values 2.2.a"]

            }

          },

          "falseNode": {

            "name":   "E 2.1",

            "sms":    "TemplateSMS 2.1",

            "email""TemplateEmail 2.1"

          }

        }

      }

       

      Graphical representation is as shown below:

      Selection.JPG

      Java Code snippet is as shown below:


      public interface SelectionNode extends Serializable {

          SelectionNode getTrueNode();

          void setTrueNode(SelectionNode trueNode);

          SelectionNode getFalseNode();

          void setFalseNode(SelectionNode falseNode);

          List<String> getValues();

          String getType();

          String getName();

          void setName(final String name);

          boolean isEndPoint();

      }

       

      In short any node constructed from the above JSON is an instance of SelectionNode .

       

      Now need help to display this SelectionNode on the UI using rich faces and JSF.

        • 1. Re: How to display a Binary Tree ?
          sandy4you

          Any guidance or direction on how to proceed will be helpful.

          • 2. Re: How to display a Binary Tree ?
            michpetrov

            I am not clear on what your problem is. Do you want to know how to hand the SelectionNode to a rich:tree?

            • 3. Re: How to display a Binary Tree ?
              sandy4you

              Yes Michal, thats right.

              Wanted to know if there is any way to display the above tree structure using in built jsf/richfaces component ?

              If not then I don't have any other option then to go for html with js and css.

              In short looks like for the above requirements currently jsf and richfaces are useless for me.

              • 4. Re: How to display a Binary Tree ?
                michpetrov

                You can make your class implement org.richfaces.model.TreeNode and then just put the root node as @value of the rich:tree. But you'll need CSS if you want the tree to look like that picture.

                • 5. Re: How to display a Binary Tree ?
                  sandy4you

                  Hi Michal,

                  Can I get some examples or code snippet to starts with.

                  I got your view from overall perspective but still looking from where to start.

                  • 6. Re: How to display a Binary Tree ?
                    sandy4you

                    Finally was able to get it right as per the diagram shown above using java script.

                     

                    /**

                    * Selection object provides the means to parse a selection defined in json and

                    * display it as a graph on the screen. This object relies heavily on JQuery to

                    * handle the DOM. The main methods of this object are:

                    * <ul>

                    * <li>buildGraph(json) - read in the provided json string and create the

                    * graphical display

                    * <li>tableDOM() - returns the DOM representation for the build graph.

                    * <li>debug() - provides a stirng representation of the graph logging it at

                    * the same time to the console object

                    * </ul>

                    */

                    var Selection = function() {

                      var rows = [];

                     

                     

                      /**

                      * Possible cell types

                      */

                      var NODE = "node"; // selection node

                      var LEAF = "leaf"; // end node

                      var EMPTY = "empty"; // empty cell

                      var TRUE_CON = "trueConnector"; // connection for true

                      var FALSE_CON = "falseConnector"; // connection for false

                      var ROOT = "root"; // root node

                     

                     

                      /**

                      * Values for node types in the json

                      */

                      var LEAF_NODE = "ResultingTemplate";

                      var ROOT_NODE = "RootNode";

                     

                     

                      /**

                      * Represents a cell in the layout table for the graph.

                      *

                      * @param domData -

                      *            the DOM data contained within the cell

                      * @param cellType -

                      *            the type of this cell. See the cell types constants.

                      */

                      var Cell = function(domData, cellType) {

                      var data = domData;

                      var type = cellType;

                     

                     

                      var toString = function() {

                      return 'Cell(' + data + ', ' + type + ')';

                      };

                     

                     

                      return {

                      "data" : data,

                      "type" : type,

                      "toString" : toString

                      };

                      };

                     

                     

                      /**

                      * Represents a row in the layout table for the graph. A row consists of a

                      * list of cells.

                      */

                      var Row = function() {

                      var cells = [];

                      var addCell = function(cell) {

                      cells.push(cell);

                      return this;

                      };

                     

                     

                      var peek = function() {

                      return cells[cells.length - 1];

                      };

                     

                     

                      var toString = function() {

                      return 'Row(size=' + cells.length + ')';

                      };

                     

                     

                      return {

                      "cells" : cells, // returns the cells contained within this row

                      "addCell" : addCell, // adds a cell to the end of the row

                      "peek" : peek, // looks at the last cell in the row

                      "toString" : toString

                      // returns a string representation of this row

                      };

                      };

                     

                     

                      /**

                      * Create the DOM data for a node from its json representation.

                      *

                      * @param jsonData -

                      *            the json representation of the node

                      * @param isTrueNode -

                      *            <code>true<code> when the node represents a node on the true connection path.

                      */

                      var createNode = function(jsonData, isTrueNode) {

                      var newNode;

                      var cellType;

                      if (jsonData.type === ROOT_NODE) {

                      cellType = ROOT;

                      newNode = $('#root-node div.node').clone();

                      newNode.children('.type').append(jsonData.name);

                      } else if (jsonData.type === LEAF_NODE) {

                      cellType = LEAF;

                      newNode = $('#leaf-node div.node').clone();

                      var typeTag = newNode.children('.type')

                      typeTag.children('.leaf-type').html(jsonData.type);

                      typeTag.children('.leaf-name').html(jsonData.name);

                     

                     

                      var contentTag = newNode.children('.content');

                      contentTag.find('.email-tmpl').html(jsonData.email ? jsonData.email : '');

                      contentTag.find('.sms-tmpl').html(jsonData.sms ? jsonData.sms : '');

                      contentTag.find('.letter-tmpl').html(jsonData.letter ? jsonData.letter : '');

                      if (isTrueNode)

                      newNode.addClass('true-node');

                      else

                      newNode.addClass('false-node');

                      } else {

                      cellType = NODE;

                      newNode = $('#selection-node div.node').clone();

                     

                     

                      var typeTag = newNode.children('.type');

                      typeTag.children('.leaf-type').html(jsonData.type);

                      typeTag.children('.leaf-name').html(jsonData.name);

                      if (jsonData.values) {

                      newNode.find('.selection-vals').html(jsonData.values.join(","));

                      }

                      }

                     

                     

                      return new Cell(newNode, cellType);

                      };

                     

                     

                      /**

                      * Creates a connector DOM element for the seleciton graph. A connector is

                      * represented by a div tag with an optional image of an arrow pointing in

                      * the direction of the connection.

                      *

                      * @param type

                      *            of the connector either <code>true</code> or

                      *            <code>false</code>

                      * @param withArrow

                      *            when <code>true</code> display a small error pointing in the

                      *            direction of the connector.

                      */

                      var createConnector = function(type, withArrow) {

                      var el;

                      if (type) {

                      el = new Cell($('<div class="true-connector"><div class="true-arrow" /></div>'), TRUE_CON);

                      } else {

                      var divTag = $('<div class="false-connector">');

                      if (withArrow) {

                      divTag.append('<div class="false-arrow" />');

                      }

                      el = new Cell(divTag, FALSE_CON);

                      }

                     

                     

                      return el

                      };

                     

                     

                      /**

                      * create an empty cell. An empty cell contains an empty div DOM element

                      * with the css class empty assigned.

                      */

                      var empty = function() {

                      return new Cell($('<div class="empty"></div>'), EMPTY);

                      };

                     

                     

                      /**

                      * Create the layout structure including DOM elements for a node and its

                      * corresponding true connector from the passed json representation. If the

                      * true node is at the bottom of the current layout table new rows are added

                      * if not then the appropriate cells are replaced with the newly created DOM

                      * elements.

                      *

                      * @param jsonData

                      *            the json element to create the DOM elements from.

                      * @param currRow

                      *            the row in the layout table where this true node is being

                      *            added.

                      * @param currCol

                      *            the column in the layout table where this true node is being

                      *            added.

                      */

                      var addTrueNode = function(jsonData, currRow, currCol) {

                      var row1, row2;

                      var con = createConnector(true);

                      var sel = createNode(jsonData, true)

                      if (currRow + 2 > rows.length) {

                      row1 = new Row();

                      row2 = new Row();

                      rows.push(row1);

                      rows.push(row2);

                      for (var i = 0; i < currCol; i++) {

                      row1.addCell(empty());

                      row2.addCell(empty());

                      }

                      row1.addCell(con);

                      row2.addCell(sel);

                      } else {

                      rows[currRow + 1].cells[currCol] = con;

                      rows[currRow + 2].cells[currCol] = sel;

                      }

                     

                     

                      };

                     

                     

                      /**

                      * Create the layout structure including DOM elements for a node and its

                      * corresponding false connector from the passed json representation. If the

                      * true node is at the bottom of the current layout table new rows are added

                      * if not then the appropriate cells are replaced with the newly created DOM

                      * elements.

                      *

                      * @param jsonData

                      *            the json element to create the DOM elements from.

                      * @param currRow

                      *            the row in the layout table where this true node is being

                      *            added.

                      * @param currCol

                      *            the column in the layout table where this true node is being

                      *            added.

                      */

                      var addFalseNode = function(jsonData, currRow, currCol) {

                      var el1, el2;

                      for (idx in rows) {

                      var row = rows[idx];

                      var leftCell = row.peek();

                      if (leftCell.type === NODE || leftCell.type === FALSE_CON) {

                      if (idx == currRow) {

                      el1 = createConnector(false, true);

                      el2 = createNode(jsonData, false)

                      } else {

                      el1 = createConnector(false);

                      el2 = createConnector(false);

                      }

                     

                     

                      if (currCol <= row.cells.length) {

                      row.addCell(el1);

                      row.addCell(el2);

                      } else {

                      row[currCol + 1] = el1;

                      row[currCol + 2] = el2;

                      }

                      } else {

                      if (currCol <= row.cells.length) {

                      row.addCell(empty());

                      row.addCell(empty());

                      } else {

                      row[currCol + 1] = empty();

                      row[currCol + 2] = empty();

                      }

                      }

                      }

                      };

                     

                     

                      /**

                      * Returns a string representation of the current build selection graph and

                      * logs it to the console. The output shows the root node as 'P', an empty

                      * cell as ' ', a true connector as '|', a false connector as '-', a

                      * selection node as '*', a leave note as 'o' and any other cell as 'E' for

                      * error.

                      *

                      * @returns <code>String</code> representing the graph.

                      */

                      var debug = function() {

                      var retVal = "";

                      retVal += "table\n";

                      for (idx in rows) {

                      var tableRow = rows[idx];

                      var output = "";

                      for (cIdx in tableRow.cells) {

                      var col = tableRow.cells[cIdx];

                      if (col.type === NODE)

                      output += '*';

                      else if (col.type === LEAF)

                      output += 'o';

                      else if (col.type === EMPTY)

                      output += ' ';

                      else if (col.type === TRUE_CON)

                      output += '|';

                      else if (col.type === FALSE_CON)

                      output += '-';

                      else if (col.type === ROOT)

                      output += 'P';

                      else

                      output += 'E';

                      }

                      retVal += output + '\n';

                      }

                      retVal += "/table\n";

                      console.log(retVal);

                      return retVal;

                      };

                     

                     

                      /**

                      * Returns the jquery DOM elements making up the graph.

                      */

                      var layoutDOM = function() {

                      var tableEl = $('<table class="selection-table">');

                      for (idx in rows) {

                      var row = rows[idx];

                      var rowEl = $('<tr class="selection-row">');

                      for (cIdx in row.cells) {

                      var col = row.cells[cIdx];

                      rowEl.append($('<td class="selection-cell">').append(col.data));

                      }

                      tableEl.append(rowEl);

                      }

                      return tableEl;

                      };

                     

                     

                      /**

                      * Build a graph from the passed in json. The layout table is created by

                      * walking the tree from the root to the leafs. First passing the true

                      * connection creating the connector and the node along the way. Secondly

                      * passing the false connections creating the nodes. This will result in the

                      * table being created from the top to the bottom by adding new rows to the

                      * end of the table as needed. When passing the false connections cells are

                      * added to each row as needed until the last leaf node has been passed.

                      * This spans open the layout table for displaying the graph.

                      *

                      * @param jsonRoot

                      *            the root of the json defining the seleciton.

                      */

                      var buildGraph = function(jsonRoot) {

                      function buildSubTree(jsonNode, currRow, currCol) {

                      addTrueNode(jsonNode.trueNode, currRow, currCol);

                      if (jsonNode.trueNode.type !== LEAF_NODE) {

                      currCol = buildSubTree(jsonNode.trueNode, currRow + 2, currCol);

                      }

                     

                     

                      if (jsonNode.type !== ROOT_NODE) {

                      addFalseNode(jsonNode.falseNode, currRow, currCol);

                      currCol += 2;

                      if (jsonNode.falseNode.type !== LEAF_NODE) {

                      currCol = buildSubTree(jsonNode.falseNode, currRow, currCol);

                      }

                      }

                      return currCol;

                      }

                      var row = new Row();

                      rows.push(row);

                      row.addCell(createNode(jsonRoot, true));

                      buildSubTree(jsonRoot, 0, 0);

                      return layoutDOM();

                      };

                     

                     

                      return {

                      "debug" : debug,

                      "buildGraph" : buildGraph

                      };

                    };

                     

                     

                    $(document).ready(function() {

                      var treeString = document.getElementById(":jsonTree").value;

                      var jsonTree = JSON.parse(treeString);

                      var selection = new Selection();

                      $('#tree').append(selection.buildGraph(jsonTree));

                    });