Skip to content

Treemap

Иерархические серии без осей. Данные — вложенные через children; значение узла — sizeField листа или сумма потомков.

Treemap

Squarify-раскладка: вложенные прямоугольники, группы с заголовками.

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Lines of code by module' },
    series: [{ type: 'treemap', labelField: 'label', sizeField: 'size' }],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    {
      label: 'Frontend',
      children: [
        { label: 'app', size: 420 },
        { label: 'widgets', size: 180 },
        { label: 'shared', size: 310 },
      ],
    },
    {
      label: 'Backend',
      children: [
        { label: 'api', size: 540 },
        { label: 'workers', size: 230 },
        { label: 'db', size: 160 },
      ],
    },
    {
      label: 'Infra',
      children: [
        { label: 'ci', size: 90 },
        { label: 'deploy', size: 140 },
      ],
    },
  ];
}

Подписи и зазоры плиток

Подпись плитки собирается так же, как подпись сектора круговой: имя узла и его величина — одна подпись из двух половин, у каждой свой шрифт и формат. label.value.enabled включает число, layout ставит его на отдельную строку (по умолчанию) или в ту же строку за разделителем, placement двигает весь блок по 9 позициям внутри плитки. Цвет подбирается автоконтрастом по плитке.

itemGap — зазор между соседними плитками, groupGap — между соседними группами. Только между ними: плитка на краю своей группы или всего графика этот край сохраняет, поэтому отступы области построения остаются отступами области построения. Без groupGap группы разделяет itemGap:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Tile labels and gaps' },
    series: [
      {
        type: 'treemap',
        labelField: 'label',
        sizeField: 'size',
        itemGap: 3,
        groupGap: 10,
        groupHeader: { height: 22, fontSize: 13 },
        label: {
          enabled: true,
          placement: 'top-left',
          layout: 'inline',
          fontSize: 12,
          fontWeight: 'bold',
          value: { enabled: true, fontWeight: 'normal' },
        },
      },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    {
      label: 'Frontend',
      children: [
        { label: 'App', size: 34 },
        { label: 'Widgets', size: 22 },
        { label: 'UI Kit', size: 18 },
        { label: 'Utils', size: 8 },
      ],
    },
    {
      label: 'Backend',
      children: [
        { label: 'API', size: 28 },
        { label: 'Jobs', size: 14 },
        { label: 'Auth', size: 9 },
      ],
    },
    {
      label: 'Infra',
      children: [
        { label: 'CI', size: 12 },
        { label: 'IaC', size: 10 },
      ],
    },
  ];
}

Заголовки групп читают те же две половины, всегда в одну строку, — группа называет свой итог так же, как плитки называют свой. Заголовок — это заглавие над группой: полоса не закрашена, пока фон не запрошен через groupHeader.background, а имя написано цветом самой группы — или автоконтрастом по фону, когда он задан. В groupHeader же лежат высота полосы и её шрифт, наследуемый от label. Подпись, не помещающаяся в плитку — как и заглавие, не помещающееся в полосу, — не рисуется; label.minShare решает раньше, какие узлы вообще стоит подписывать.

js
series: [
  {
    type: 'treemap',
    itemGap: 3,
    groupGap: 10,
    groupHeader: { height: 22, fontSize: 13, background: '#f2f0ed' },
  },
],

Опции

Общие опции всех серий (name, showInLegend, tooltip.renderer, …) — в разделе Общие опции серий.

ОпцияСерииПо умолчаниюОписание
groupHeader.heighttreemap18высота заголовка группы
groupHeader.backgroundtreemapнетфон под заглавием
groupHeader.fontSizetreemaplabel.fontSize, затем 11размер шрифта заглавия
groupHeader.fontWeighttreemaplabel.fontWeight, затем boldнасыщенность заглавия
groupHeader.fontFamilytreemaplabel.fontFamily, затем шрифт темыгарнитура заглавия
groupHeader.colortreemapцвет самой группы; автоконтраст по фонуцвет текста заглавия
fillsвсепалитрацвета ветвей/слоёв
itemGaptreemap2зазор между соседними плитками
groupGaptreemapitemGapзазор между соседними группами
labelFieldtreemaplabel/size/childrenключи иерархии
sizeFieldtreemaplabel/size/childrenключи иерархии
childrenFieldtreemaplabel/size/childrenключи иерархии
labelNameFormattable<PartNameParams>значение поля как естькак читается имя узла везде: легенда, подсказка, заголовок группы, подпись
label.enabledbooleantrueпоказать подписи значений
label.placementcenter, края и углы (9 позиций)'center'позиция подписи
label.layout'stacked' | 'inline''stacked'величина на своей строке или за разделителем
label.separatorstring' · 'между половинами подписи в одну строку
label.minShareFraction0доля от целого, начиная с которой узел подписывается
label.categorySwitchable & FontOptions & Formattableвключенаполовина с именем: свой шрифт и формат
label.valuePartValueLabelOptionsвыключенаполовина с величиной: type: 'percent' | 'value', format, formatter, свой шрифт
label.formatter({ datum, label, value, share }) => stringвся подпись целиком; побеждает category/value
label.fontSizePixels11размер шрифта подписи
label.fontWeightstring | numbernormalнасыщенность
label.fontFamilystringшрифт темыгарнитура
label.colorColorValueforeground; внутри — автоконтрастцвет текста

Подсказка и имя величины

Узел — не строка данных, а имя и то, во что оно складывается, поэтому tooltip.renderer получает NodeTooltipRendererParams: { datum?, label, value, share, color }. datum — строка, из которой прочитан узел; узел потока сложен из нескольких строк, и своей у него нет.

js
tooltip: { renderer: ({ label, value, share }) => `${label}: ${value} (${Math.round(share * 100)}%)` },

Без рендерера строка подсказки называется по ключу поля, откуда взята величина, — это имя колонки, а не имя меры. name у серии говорит, как её называть:

js
series: [{ type: 'treemap', sizeField: 'revenue', name: 'Выручка' }],