Introduction

In charts, nodes can represent various concrete or abstract entities such as people, locations, servers or accounts, and can carry various levels of detail and information.

KeyLines supports a wide range of styling options that let you customise the way nodes look and display information.

For quick but impactful changes, you can for example change a node's colour, fill it with an image or a font icon, or add a contrasting border, glyph or a halo. Click the image or head to the Node Styles demo for more examples:

a selection of nodes from the KeyLines Node Styles demo

You can find the full list of available APIs in the Node API Reference.

More advanced styling in KeyLines isn't advanced in the difficulty of implementation, but rather in the complex issues it can help you solve, such as:

  • Large amounts of information or many types of information on a node
  • Dynamically changing data (such as names or numbers in varying length)
  • A need for interactive elements on nodes (such as buttons or editable fields)
  • A specific design language of your application

Using the available node styling APIs, you can create custom and high-precision styling for your nodes to tackle any issues. Read on for more details or explore some of our examples in the Advanced Node Styles demo.

three styled rectangular nodes showing examples of items and sub-items

Node shapes and sizes

By default, KeyLines creates scalable, circular nodes with a diameter of 54. You can also create fixed-size nodes by specifying both their width (w) and height (h) properties.

Scalable nodes

Create scalable nodes by setting the shape (sh) property, and then scale them using the e property, which also automatically adjusts any labels, node styling and node decorations.

For example, to create a scalable square node, with a default height and width of 54 points, set sh to 'box'. You can then double its dimensions by setting e to 2.

Sized nodes

Create a sized rectangular node by setting the node's width (w) and height (h) properties. You can the resize it by updating w and h, but the e property, if set, is ignored.

Sized nodes can be set to adjust automatically to any number or length of labels inside them by setting either, or both, of the w and h properties to 'auto'. This is especially useful when nodes contain multiple stacked labels or when the data inside labels comes in variable lengths. To make sure automatically sized nodes don't get too small, you can also set minWidth and/or minHeight.

Rounded corners

To make one or multiple corners of your square or rectangular nodes rounded, set the borderRadius option. See examples of this in our Impact Analysis or Detail on Zoom demos.

Advanced label styling

Advanced label styling enables you to create highly customised and informative nodes. A label can contain text, an icon or an image, or remain empty to be used as a styling element. You can also add multiple labels to a node and combine them to achieve beautifully styled and information-rich nodes.

Labels can be thought of as containers holding label content:

  • The label content refers to the text string, font icon, or image inside a label object.
  • The label container is the shape holding the content. The styling options for the container depend on the type of content inside.

There are two main types of labels: text-based labels, containing text or font icons, and image labels, that just contain an image. Each type can be styled in different ways.

As well as accepting strings, the node t property also (currently in beta) accepts:

  • A single node label object, which can contain additional label styling.
  • An array of node label objects, which can be used to add multiple labels to a node, each styled individually.

Explore further by looking at our Advanced Node Styles demo.

Styling that is not set on a node label object is inherited from the node styles specified for the node.

Styling by content

Text-based labels

A text-based label has its content specified using text (t) or a font icon (fi):

Image labels

Create an image label by specifying the url of the image, u, and style it:

  • Set the image's size by specifying both maxHeight and maxWidth.
  • Align the image label within the node using position and margin. Note that padding is ignored for images.
  • You can also create a border around the image by specifying its colour(b), radius (borderRadius), and width (bw). The border is drawn around the outside of the image so the whole image remains visible and unobscured.

Empty labels

An empty label has no content specified (no text, font icon or image). Empty labels can be useful when using multiple labels, for example to create irregularly-shaped nodes or bands of colour across a node.

t: [
  {                       // An empty label
    fbc: 'lightgrey',     // Provides a grey background
    minWidth: 'stretch',  // Stretches the label across the node
    minHeight: 60,        // The height of the empty label
  },
]

Label size and content

The way in which KeyLines sizes labels depends on their content:

  • Image labels can be sized by setting both the maxWidth and maxHeight properties.
  • Text-based labels are sized by default to fit their content.

You can set the size of text-based labels explicitly using the minWidth and minHeight properties, or by setting either of them to 'stretch' to fill the whole width/height of the node.

If the label is larger than its content, the content is aligned in the middle and centre by default. To change this, set the horizontal and/or vertical options inside the textAlignment object.

Whether a text-based label is sized by default or not, you can control the content inside to offer the best possible readability at any content length, label size or zoom level:

  • Set font size (fs) to 'auto' to scale the font to any label size and zoom level. You can also set maxWidth and maxHeight to set maximum width and height of the label.
  • Set textWrap to 'normal' to wrap the content on whitespace. You can also set maxWidth to set the maximum label width allowed before a line break.
t:[
    { t: 'Default size label' },
    {
      t: 'Custom size and text alignment',
      minWidth: 300,
      minHeight: 40,
      fbc: green,
      textAlignment: { horizontal: 'right', vertical: 'bottom' },
    },
    {
      t: 'Automatic font sizing',
      fs: 'auto',
    },
    {
      t: 'Minimum width stretched',
      minWidth: 'stretch',
    },
    {
      t: 'Maximum width, text wrapping and auto font sizing',
      textWrap: 'normal',
      fs: 'auto',
      maxWidth: 100,
    },
],
screenshot of a playground showing different sizing options

Label positioning

Labels can be anchored to nodes from the outside or from the inside.

By default, a label is located inside the node in its centre. To control the exact location of the label on the node, you can use the position property:

  • To set the anchor point inside, use the vertical and horizontal options to set the position to any world coordinates or relative to the node's corners. When a label is positioned on an inside node edge, the inside of the label border is aligned with the node edge by default.
  • To set the anchor point outside, pass a string compass value ('n' for north, 'ne' for north east etc.) directly in the position property.

Note that if there are multiple labels with completely or partially overlapping positions, the label listed later in the array will be drawn over the label listed earlier.

t: [
    {
      t: 'top and left',
      position: { vertical: 'top', horizontal: 'left' }   // inside in the top left corner
    },
    { 
      t: '50px and 50px', 
      position: { vertical: 50, horizontal: 50 }   // inside at given world coordinates
    },
    { 
      t: 'north',
      position: 'n'  // outside in the north position
    },
],
screenshot of a playground showing different label positioning

Multiple inline labels

If you add multiple labels to a node, using an array of node label objects, the labels are stacked vertically downwards by default, in the order they're listed in the label array. See also Label positioning.

If you want to place multiple labels on the same line, there are two ways to do it:

  • If a label has no vertical position, any other labels with vertical: inherit position are placed inline to the previous label.
  • If multiple labels, listed consecutively in the label array, have the same vertical position, they are all placed inline.
t: [
    { t: 'no position' },
    {
      position: { vertical: 'inherit' },   // inline by setting vertical: 'inherit'
      t: 'inline by inherit',
    },
    {
      position: { vertical: 'bottom' },
      t: 'vertical position',
    },
    {
      position: { vertical: 'bottom' },   // inline by setting the same vertical position
      t: 'inline by vertical position',
    },
]
screenshot of a playground showing vertical inheritance of label position

Margins, padding and borders

KeyLines APIs for padding and margins are similar to how padding and margin properties work in CSS.

The padding API in KeyLines sets the distance between the content edge and the edge of the label (or the inside edge of its border if it has one). This doesn't apply to image labels because the image always fills the label.

The margin API in KeyLines sets the distance between:

  • the label edge (or the outside edge of its border) and another label edge (or the outside edge of its border)
  • the label edge (or the outside edge of its border) and the edge of its node (or the inside edge of its border)

Both can be defined in any of the traditional CSS formats:

  • A single number - same value applied all around.
  • An array of two, three or four numbers separated by commas.
  • A string of two, three or four numbers separated by spaces as shorthand properties - see W3C CSS margin and W3C CSS padding for details.
  • An object containing individual properties, e.g. margin: { top: 30, bottom: 20 }.
t: [
    {
      t: 'label 1', 
      b: 'rgba(88,167,115,0.4)',   // green border drawn equally inside and outside the label
      bw: 30,                      // border width
      padding: 40,                 // padding between border edge and text
      position: {
        vertical: 'top',           // inside of label border aligned to node edge
        horizontal: 'left' 
    }},
    {
      t: 'label 2',
      position: { vertical: 'inherit' },  // 'inherit' aligns label with top of label 1 border
      margin: '30 0 0 100',               // top, right, bottom, left
    },
  ]
screenshot of a playground showing label margin and padding

Advanced combo styling

Many of the advanced styling features described in this documentation are also available for combos.

Closed combos look and behave just like regular nodes, which means that they also have the same styling options including all of the features above.

Open combos display all of their child nodes arranged within a combo border, and can be customised in a number of ways including:

Note that this feature is currently in beta.

For more details about combos, see the Styling for combos documentation.

a styled open rectangular combo showing examples of labels, rounded corners, and font icons

By default, open combo labels are drawn outside and below the combo. When adding labels inside open combos, you may need to consider how they fit in with the combo contents.

There are simple rules, based on the position property, that describe the positioning rules between open combo labels and combo contents:

an open combo with a label positioned above combo nodes

Label above or below the content:

  • When a label has position: { vertical: 'top' }
  • When a label has position: { vertical: 'bottom' }
an open combo with a label positioned to the left of combo nodes

Label to the left or right of the content:

  • When a label has position: { horizontal: 'left' }
  • When a label has position: { horizontal: 'right' }
an open combo with two labels positioned to the left of combo nodes

Multiple inline labels to the left or right of the content:

  • When a label has position.horizontal set to 'left' or 'right' and position.vertical set to 'middle' or 'inherit'
an open combo with a label positioned in the background behind the combo nodes

Label behind the content:

  • When a label is set to position: { vertical: 'middle', horizontal: 'centre' }
  • When a label has minWidth and minHeight set to 'stretch'
  • When either vertical or horizontal options are set to numbers
  • When a label that stretches across the combo's centre, for example position: { horizontal: 'left'}, minWidth: 'stretch'
an open combo with two labels, each positioned to the left and to the right of combo nodes

Labels on both sides of the content:

  • When labels are set to position: { horizontal: 'left' } and position: { horizontal: 'right', vertical: 'inherit' }