Skip to content
Tommy Groshong edited this page Feb 16, 2015 · 8 revisions

Here lies an explanation of the architecture of the PCNChart utility.

High Level

PCNChart exports a function which receives Data formatted according to the PCNSpec. That data may be a JavaScript object or a string that will be parsed (using JSON.parse) into an object. The return value of the function is an SVG string when run in Node.js or an SVG Element tree (SVGSVGElement) when run in the browser.

Once the input is received and in object form, it is run through the following steps to create the output:

  1. Linting with the PCNLint tool version 0.5*.
  2. Building a LayoutGraph object with a node for each PCN step and that node's X and Y position.
  3. Building an XML document of an SVG from the LayoutGraph.
  4. Conversion to String in Node.js, or parse to SVG Element in Browser

*Note: PCNLint version 0.5 is the latest that can be used because it throws exceptions when input is malformed. Later versions are meant to be used as a CLI tool and output their results to STDOUT.

Code Conventions

In general, the code takes a mixed paradigm approach of Object-Oriented + Functional when creating a Chart. Most of the functions are pure (without side-effects) and do not mutate their input data. PCNChart defines two object types: LayoutGraph and LayoutNode. The data that flows through the program is either (1) the original PCNSpec input data, (2) an instance of LayoutGraph containing instances of LayoutNodes, or (3) an XML builder object.

The entry to the module is index.js in the project root, which then calls functions in lib/ where the bulk of the logic lives. The lib/ directory has two domains, layout/ and builder/ for generating a LayoutGraph and building XML respectively.

Functions that mutate their inputs (cause side-effects) are placed in mutations/ directories and identified by their function and file names:

// lib/layout/mutations/mutate-adjust-layout-for-relations.js
function mutateAdjustLayoutForRelations(layoutGraph) {
  /* Mutation Logic */
}

In addition to mutations is a concept of generators: functions that receive input and use it to generate output from pre-defined templates. These functions are grouped together in generators/ directories. They are primarily used in SVG/XML building stage to generate elements.

Building the LayoutGraph

A LayoutGraph is a self-contained representation of the data that will be rendered by the builder later on. It receives PCNSpec data in its constructor function and then creates a store of LayoutNode's for each PCN Step. Once the nodes are created, the graph (and it's nodes) are mutated twice:

  1. Initial Layout: lib/layout/mutations/mutate-initial-layout.js
  2. Layout Adjustment for Relations: lib/layout/mutations/mutate-adjust-layout-for-relations.js

The Initial Layout organizes all node's into stacked columns in the order that they are specified in the PCNSpec data. After Initial Layout, the X position of Nodes does not change because each Node is in it's appropriate column.

The Layout Adjustment iterates over each Node, checks it's predecessor relationships to other nodes, and bumps the Y position of that Node so that it is equal or lower than it's predecessors.

Building the XML

Building the output data is a fairly straightforward process of setting up the skeleton chart and iterating through the LayoutGraph's nodes to place a Step Box and relationship lines to each predecessor. The shape of the Step Box is determined by the type of PCN Step, and the relationship lines receive an X,Y position for the start and end points (mid-point of the predecessor node side to the mid-point of a side of the current step).

One important thing to note is that depending on which environment PCNChart is executed in, either the DOM builder (lib/builder/dom/builder.js) or the XML builder (lib/builder/xml/builder.js) is exported. In practice, this does not matter much because the DOM builder just requires the XML builder and then runs the XML output string through a DOMParser before returning it. All the main logic is in the XML builder.

Clone this wiki locally