@graph-viz

@graph-viz

  • Guide
  • API
  • Help

›Guides

Getting Started

  • Installation
  • Quick Start

Guides

  • Creating your first graph viz
  • Adding interactions
  • Drawing hulls (Groups)
  • Creating custom layouts

Components

  • React

Creating custom layouts

The renderer from @graph-viz/core allows you to provide fixed locations for each node through the fields fx and fy on the node. This makes it possible for you to completely own the layouting process and create customized layouts such as trees, timelines etc.

Let's see how we can implement a custom timeline layout using d3.js.

Timeline Graph Layout

Let's start with a dataset where few nodes have say a timestamp value. We would ideally like to arrange all the nodes with a timestamp in a linear layout by time. For the purposes of this tutorial we will use d3's scaleLinear scale which will help us map the timestamp to the x coordinate of node.

const data = {
   nodes: [
     {id: '1', fill: 'coral'},
     {id: '2', fill: 'orange'},
     {id: '3', fill: 'blue'},
     {id: '4', fill: 'lightblue'},
     {id: '5', fill: 'orange'},
     {id: '6', fill: 'green'},
     {id: '7', fill: 'pink', timestamp: new Date(2019, 10, 10)},
     {id: '8', fill: 'pink', timestamp: new Date(2019, 10, 12)},
     {id: '9', fill: 'pink', timestamp: new Date(2019, 10, 18)},
     {id: '10', fill: 'pink', timestamp: new Date(2019, 10, 27)},
     {id: '11', fill: 'pink', timestamp: new Date(2019, 10, 30)},
   ],
   links: [
     {source: '7', target: '1', color: 'red'},
     {source: '8', target: '2'},
     {source: '9', target: '3'},
     {source: '11', target: '4'},
     {source: '11', target: '5'},
     {source: '7', target: '5'},
     {source: '8', target: '6'},
   ],
}

Before we pass this to our renderer, we should map the timestamp fields to fx and fy coordinates.

Mapping timestamps to pixels

const canvasWidth = 700 // the width of the canvas element 
const horizontalPadding = 40 // padding on the left and right
const totalWidth = canvasWidth - 2 * horizontalPadding

const allTimestamps = data.nodes
  .map(n => n.timestamp.getTime()) // map to UTC timestamp
  .sort((a, b) => a - b) // sort ascending

const extent = [allTimestamps[0], allTimestamps[allTimestamps.length - 1]]
 
const scale = d3
  .scaleTime()
  .domain(extent)
  .range([-totalWidth / 2, totalWidth / 2]) // because the graph viz library assumes that point (0,0) is at the center of the canvas

for (const node of data.nodes) {
  if (node.timestamp !== undefined) {
    node.x = scale(node.timestamp.getTime())
    node.y = 0 // center vertically
  }
}

This should set an x and y positions to all nodes that have a timestamp.

But what about the other nodes which did not have a timestamp? We still need to manually assign them locations with another layout algorithm. Let's try to do that using our force-directed simulation from the @graph-viz/layouts package.

However, if we pass all our nodes to the ForceSimulation package, it would overwrite the x and y coordinates we set on the timeline nodes. In such a situation we can set the fx and fy fixed coordinates on the timeline nodes instead of the x and y coordinates to prevent them from taking part in the force-directed layout computation.

Hybrid layout

Partially fixed and partially force-directed.

for (const node of data.nodes) {
  if (node.timestamp !== undefined) {
    node.fx = scale(node.timestamp.getTime())
    node.fy = 0 // center vertically
  }
}

After this step we can follow the steps from the "[Creating your first viz]" tutorial to first pass our timeline data to the ForceSimulation and then to our GraphVisualization renderer.

← Drawing hulls (Groups)React →
  • Timeline Graph Layout
    • Mapping timestamps to pixels
  • Hybrid layout
@graph-viz
Guides
InstallationCreating your first graph vizAPI Reference
More
GitHubStar
Copyright © 2020, Uplevel Technology