Skip to content

bohnacker/Treemap.js

Repository files navigation

Treemap.js

Cover

A treemap is a type of data diagram which shows a (hierarchical) list of values as nested rectangles. The original version of this class is also part of the Generative Design Library. For this standalone version I added some functionality and renamed/restructured things.

This is work in process!

I decided to publish it here as a seperate library to have it as a pure, independent, tiny and single-purpose class. It might be the right thing for you, if you want to generate and draw a treemap without having all the great but distractive stuff in big libraries like D3.js.


Quick start

A treemap is one good way of visualizing the sizes of a list of values. It works on plain lists, just like a bar chart does. But the real strength of a treemap is to show relative sizes in hierarchical data. This library helps with parsing or building this hierarchical data and calculating the rectangles. There is no graphics engine attached. But this way you can easiliy use it with every drawing method (plain html, p5.js, snap.svg, paper.js, ...). Have a look at the examples, there I try to show every implemented feature. For the full reference just scroll down to the reference section.

To create a treemap you need these steps:

1. Create an instance of the class

let treemap = new Treemap(20, 20, 400, 300, {
  order: 'sort',
  direction: 'both',
  padding: 4,
});

This will create a treemap at position (x = 20, y = 20) as the upper left corner, with a width of 400 and a height of 300. You can give some options, how to calculate the rectangles. order could be set to sort or shuffle. Default is sort, which will sort all the items from largest to smallest. From a data visualization point of view that's the best. direction might be both, horizontal or vertical. A value bigger than 0 for padding makes every nested item smaller than the containing one. You have to be aware that in fact this produces a "wrong" visualization, because the sizes of the rectangles are not proportional to the values in the data any more. Still, this might be insignificant, if you do not have many values in your data and padding is small compared to the size of the whole treemap.

2. Add data to the treemap

You can provide data in several ways. If you already have hierarchical data as a (nested) array of values, just do it like this:

let data = [1, 2, 3, 4, [2, 3, 4, 1, 1], 6, [4, 1, 1], [2, 3, 4, [1, 1, 2, 2]], 9, 10, 7, 12];

treemap.addData(data);

The values of a (nested) array might also be objects. In this case you need to specify which value to use for sizing the rectangles.

let data = [
  {name:'John', weight:'80'}, 
  {name:'Mary', weight:'65'}, 
  {name:'Carl', weight:'75'}, 
  ...
];

treemap.addData(data, {value: 'weight'});

If you have a JSON-like structure like the following it works almost the same. You just have to specify, where to find the children.

let data = {
  "name": "02_M",
  "files": [{
    "name": "M_2_2_01",
    "files": [{
        "name": "index.html",
        "size": 1070
      }, {
        "name": "M_2_2_01.png",
        "size": 7390
      }, {
        "name": "sketch.js",
        "size": 4126
      }
    ]
  }, ... ]
} 

treemap.addData(data, {children: 'files', value: 'size'});

If you do not already have your data in the needed form you can use the function addItem() to help you with that. See examples 2_count-up.html or 4_json-table.html for how this is done.

3. Calculate the treemap

In most cases it will look like this:

treemap.calculate();

This produces x and y positions, width and height for all the rectangles in the treemap.

4. Drawing the treemap

Drawing is always done with a customized drawing function to keep this library independ of any library that helps with drawing stuff. In the following sample, the elements are drawn to the document as divs.

treemap.draw(function(item) {
  let div = document.createElement('div');

  div.style.left = item.x;
  div.style.top = item.y;
  div.style.width = item.w;
  div.style.height = item.h;

  document.body.appendChild(div);
});

The draw() function parses through all the items of the treemap. You could use a lot of information stored or calculated for that item:

  • item.x, item.y, item.w, item.h – Dimensions of the rect
  • item.minValue, item.maxValue - Smallest and largest item inside this item
  • item.level, item.depth - How deep is this item nested in the tree? The root node has level 0, an end node has depth 0
  • item.itemCount - Number of items inside this item, counted recursively
  • item.index - Index of this item inside the parents sorted items array

Reference

Table of Contents

Treemap

Creates a new empty Treemap with position (x, y), width and height. To specify drawing a bit more, you can give drawing options. See method setOptions() for more information. Content may be added using addData() or addItem().

Parameters

Returns Treemap – The new empty Treemap

x

X position of the rectangle.

y

Y position of the rectangle.

w

Width of the rectangle.

h

Height of the rectangle.

minValue

The minimum value of the items in the items array

maxValue

The maximum value of the items in the items array

level

Level of the item; the root node has level 0

depth

The depth of the branch; end nodes have depth 0

itemCount

The number of items in the complete branch

index

Index of the item in the sorted items array.

addData

Adds a data structure to the Treemap. You can provide an object or array of nested subitems. The optional second parameter defines what keys should be used to build the Treemap. This second parameter is in the form {children:"items", value:"size", data:"name"}. The key children defines, where to find the nested arrays. If you have a plain nested array, just leave this out. The key value defines, which value to map to the size of the rectangles of the Treemap. The key data defines, which data to store. If omitted, the complete object or array branch is stored. This might be the way to choose in most cases. That way you keep all the information accessible when drawing the treemap.

Parameters

  • data (String | Number | Object | Array) – The data element (e.g. a String)
  • keys Object? – Which keys should be used to build the Treemap: e.g. {children:"items", value:"size", data:"name"}. See the example for different ways how to use that.

Returns Boolean – Returns true, if adding succeeded

addItem

Adds one element to the treemap. If there is already an item which has this value as data, just increase the counter of that item. If not, create a new Treemap with that data and init the counter with 1.

Parameters

  • data (String | Number | Object | Array) – The data element (e.g. a String)
  • keys Array? – If keys is given, data has to be an object. It searches for the first key on the first level, for the second key on the second level, ...
  • value Number? – How much should this item add to the size. If not given, 1 is added.

Returns Treemap – Returns the treemap where the data was added

setOptions

Set options for next calculation of the treemap. Currently there are the following options you might set:

  • order: 'sort', 'shuffle' or 'keep'. Default is 'sort'. Attention: don't use 'keep' for the first calculation of the treemap.
  • direction: 'both, 'horizontal' or 'vertical'. Default is 'both'.
  • padding: 0 (default) or any positive number.

Parameters

  • options Object – Object in the form {order: 'keep', padding: 4}

calculate

Calculates the rectangles of each item. While doing this, all counters and ignore flags are updated. If you have multiple values stored in your treemap you must give a key to define which value to use for calculation.

Parameters

draw

A simple recursive drawing routine. You have to supply a function for drawing one item. This function gets the actual item as a parameter and has access to all the fields of that item, most important x, y, w, and h. level and depth tells you, how deep this item is nested in the tree. The root node has level 0, an end node has depth 0. itemCount gives you the number of items inside this item, counted recursively and the index of item inside the parents sorted items array. Example:

myTreemap.draw(function(item) { 
  let div = document.createElement('div');
  div.style.left = item.x;
  div.style.top = item.y;
  div.style.width = item.w;
  div.style.height = item.h;
  document.body.appendChild(div);
}); 

Parameters

  • drawItemFunction Function – A function that draws one item