Introduction

This quick start guide shows how to create a simple application with a KeyLines chart.

Note that if you store KeyLines in your source control, you must ensure it's not publicly available. Read more about the Obfuscation Requirements before deploying your application.

Step 1: Create and serve an app

If you already have an existing project up and running, you can skip this step and continue adding KeyLines from Step 2, replacing my-keylines-app with the name of your project's root directory and integrating the example code into your application code.

If you don't have an existing project, you can create one with Vite. Follow the Vite Getting Started guide for your preferred package manager.

Alternatively, you can use one of these quick start commands to create a Javascript Vite app:

npm create vite@latest my-keylines-app -- --template vanilla
yarn create vite my-keylines-app --template vanilla
pnpm create vite my-keylines-app --template vanilla

Once the process has finished, start a development server:

cd my-keylines-app
npm install
npm run dev
cd my-keylines-app
yarn
yarn dev
cd my-keylines-app
pnpm install
pnpm run dev

By default, Vite runs a dev server at http://localhost:5173.

Step 2: Create a chart

Download the KeyLines package from the link below and move it to the my-keylines-app directory.

Request a trial (Required to Download)

In the terminal from my-keylines-app, add KeyLines as a package dependency:

npm install file:./keylines-8.6.0-11643712880.tgz
yarn add ./keylines-8.6.0-11643712880.tgz
pnpm install file:./keylines-8.6.0-11643712880.tgz

First we will define the div for KeyLines chart in my-keylines-app/index.html. Replace the existing div with a new div:

<div id="kl" style="width: 100vw; height: 100vh;" ></div>

Next, open my-keylines-app/src/main.js.

This file will serve as a controller for the KeyLines component and will contain the logic controlling your chart. In this tutorial, this file will also contain our data and data management, although in a real-world application, these would typically be separate from the controller.

At the top of the file, add an import statement for KeyLines to the list of statements:

import KeyLines from 'keylines'

And then replace the rest of the code below the statements with a simple KeyLines chart:

let chart;

const data = {
  type: 'LinkChart',     // A KeyLines Chart type - must be 'LinkChart'
  items: [
    { 
      id: 'id1',
      type: 'node',
      c: '#43976C',      // node colour
      t: 'Hello World',  // node text label
      x: 150, y: 150     // node positions in world coordinates
    }
]};

async function startKeyLines() {      // async functions prevent long-running functions from blocking
  chart = await KeyLines.create({     // waits until chart is created before loading data
    type: 'chart',
    container: 'kl',    // references the div id from index.html
  });
  chart.load(data);
}

window.addEventListener('DOMContentLoaded', startKeyLines);

This application loads KeyLines as an ESM module. KeyLines is also available as a UMD module which declares KeyLines as a global variable.

As a best practice, we use async/await which makes sure long-running functions don't block other interactions. Read more about this in the Asynchronous JavaScript documentation.

When the page loads, we call KeyLines.create() to create a KeyLines chart in the div specified in the container option. Then we load the chart data.

The data object loads data in KeyLines JSON format - in this case, a node with a green colour (c property), a text label (t property), and position in world coordinates (x, y properties):

A single green node with Hello World label

Charts have a range of native options such as navigation to pan and zoom or overview window icon at the bottom right corner to toggle a chart overview.

Step 3: Add and parse the data

Replace the existing data object with this data:

const data = {
  person: [
    { name: 'Jenny', teamId: 1 },
    { name: 'Rosie', teamId: 0 },
    { name: 'Peter', teamId: 0 },
    { name: 'Sam', teamId: 1 },
  ],
  messages: [
    { from: 'Jenny', to: 'Sam', amount: 17 },
    { from: 'Sam', to: 'Jenny', amount: 12 },
    { from: 'Sam', to: 'Peter', amount: 1 },
    { from: 'Rosie', to: 'Jenny', amount: 2 },
    { from: 'Peter', to: 'Rosie', amount: 7 },
  ],
};

This dataset details messages between two teams of people.

KeyLines accepts a ChartData object, which defines an array of chart items and their attributes. This means that we will need to parse our raw data to a KeyLines chart object. This is how we've defined our data model:

  • People are represented by nodes. Nodes require a type: 'node' and a unique id. The default node colour is transparent, so we will also set the c property.
  • Messages between people are represented as links. Links require a type: 'link', a unique id, and id1 and id2 properties whose values are ids of nodes at each link end.

To parse the data, add this function to your code:

function convertDataToKeyLinesFormat(data) {
  const items = [];

  data.person.forEach(({ name }) => {     // defines people as nodes
    items.push({
      id: name,
      type: 'node',
      c: '#43976C',
    });
  });

  data.messages.forEach(({ from, to }) => {     // defines messages as links
    items.push({
      type: 'link',
      id: `link_${from}_${to}`,
      id1: from,
      id2: to,
    });
  });

  return items;
}

We need to update the chart.load() function to load our new items and to include the necessary type: 'LinkChart' that wasn't present in the raw data. The data also doesn't include positions, so we will call chart.layout() to perform a layout after loading the chart:

async function startKeyLines() {
  chart = await KeyLines.create({
    type: 'chart',
    container: 'kl',
  });
  await chart.load({ type: 'LinkChart', items: convertDataToKeyLinesFormat(data) });   // adds required 'LinkChart' type and loads data
  chart.layout();   // runs the default organic layout
}

This runs our default organic layout, which is a versatile force-directed layout algorithm that is especially great for large datasets and complex networks, but there are also other layouts you can explore.

The resulting network will look like this:

A chart with four identical green connected nodes

Our data model is now visualised as nodes and links, but it's difficult to distinguish the individual items on the chart. To address this, we will incorporate details as styling in the next step.

Step 4: Add details with styling

KeyLines offers a variety of styling options for nodes and links. In our chart, we will use node and link styling as a way of showing item metadata.

To style the nodes, we will:

  • Use the c property to set a different colour for each team
  • Use the t property to add a text label and style it

To do this, update the first part of the convertDataToKeyLinesFormat function where we have defined the people as nodes:

data.person.forEach(({ name, teamId }) => {
  items.push({
    id: name,
    type: 'node',
    c: [ '#43976C','#ff6f61' ][teamId],   // node colour by team
    t: { fbc: 'transparent', fs: 'auto', fc: 'white', t: name },    // white backgroundless text sized to fit the node
  });
});

To style the links, we will:

  • Use the w property to scale the link widths based on the number of messages sent
  • Use the a2 property to set a direction arrow that identifies the direction of the communication

To do this, update the second part of the convertDataToKeyLinesFormat function where we have defined the messages as links:

data.messages.forEach(({ from, to, amount }) => {
  items.push({
    type: 'link',
    id1: from,
    id2: to,
    id: `link_${from}_${to}`,
    a2: true,   // arrow pointing to the recipient
    w: Math.pow(amount, 0.8)   // link width scalable by amount to the power of 0.8
  });
});

The chart now reveals which individuals belong to a specific group (team) and the strength of the relationship between the individuals (the amount of communication).

A chart with four nodes with two different colours, unique labels, connected by links with different widths

Step 5: Customise the chart options

Now let's customise some chart options. The chart options APIs can be used to change styling, display and interaction defaults of the chart as an element that integrates into your application.

There are two ways of applying options - either by calling chart.options() function as a setter, or by using them in the KeyLines.create() function, which is the way that we follow in this tutorial.

Add an object with options to main.js:

const options = {
  selectedNode: { ha0: { c: "#f5bd1f", r: 37, w: 8 } },  // creates a halo around selected node 
  controlTheme: 'dark' ,  // turns navigation controls and overview window to dark mode
  backColour: '#1b2327',   // a background colour
};

And call the chart.options() function in the KeyLines.create() function once the chart is set:

chart = await KeyLines.create({
  type: 'chart',
  container: 'kl',
  options,    // calls the options
});

The resulting chart now looks like this when the 'Peter' node is selected:

A chart with dark background, dark mode navigation controls and a wide halo around the selected node

Step 6: Add event handling

In this step, let's add some code to respond when the user clicks an item on the chart.

KeyLines lets you respond to virtually any user event on the chart using chart events.

Add an event handler function to main.js:

function clickHandler({ id }) {
  console.log(`you clicked on ${id}`);
}

And then attach the click handler at the end of the startKeyLines() function:

chart.on('click', clickHandler);

Try clicking chart items, navigation controls or the chart background. In the developer tools console you'll see that a string containing the id of the clicked item or navigation control is passed to the click handler, or null if you click on the chart background.

Step 7: Add foregrounding on selection

Now let's set a foregrounding behaviour that highlights the user-selected item and its immediate neighbours, which is particularly helpful for large charts with densely connected nodes.

Add another event handler function:

function selectionHandler() {
  const itemIds = chart.selection();
  const selectedItems = chart.getItem(itemIds); // Ensure we have clicked on a link or node, not the navigation control
  if (selectedItems.length !== 0) {
    const neighbours = chart.graph().neighbours(itemIds); // Foreground the selected item and its neighbours
    chart.foreground(
      (item) => itemIds.includes(item.id) || neighbours.nodes.includes(item.id)
    );
  } else {
    // Clicked on background - restore all items to the foreground
    chart.foreground(() => true);
  }
}

And attach the selection-change handler at the end of the startKeyLines() function:

chart.on('selection-change', selectionHandler);

The new selectionHandler function uses chart.getItem() to check whether the clicked id belongs to a node or a link in the chart.

If it does, then we use chart.graph().neighbours() to find the nodes connected to the clicked item, and then call chart.foreground() to put them in the foreground, and other chart items in the background.

If the user clicked on something else, such as the chart background, then we foreground all the chart items.

A chart where only the selected node and its neighbours are foregrounded

Next steps

This is just the beginning of what KeyLines can offer.

You can continue reading about the features from this tutorial in Asynchronous JavaScript, Chart Basics, Layout Basics and Events Basics.

Have a look also at our Demos and our API Reference, or visit our blog for interesting articles about graph visualisation.

Here's a few suggestions on where to go next if you're interested in...