Skip to content

Свёртка групп ​

Свёртка складывает однотипных соседей в один групповой узел и переносит их рёбра на него. Например, четырнадцать контейнеров на одном гипервизоре превращаются в один узел со счётчиком вместо четырнадцати отдельных кругов.

ts
interface CollapseRule {
  threshold?: number
  groupBy?: (entity: AssetEntity) => string | null
  shouldCollapse?: (parentId: EntityId | null, children: readonly AssetEntity[]) => boolean
}

По умолчанию дети группируются по type, и ведро сворачивается в группу, когда в нём больше десяти.

vue
<AssetMap :entities="entities" :links="links" :collapse="{ threshold: 4 }" />

:collapse="false" выключает свёртку полностью.

Показать исходник
<script setup lang="ts">
import { ref } from 'vue'
import { AssetMap } from 'vue-asset-map'
import { useSiteTheme } from '../theme/useSiteTheme'
import { useSiteLocale } from '../theme/useSiteLocale'
import { entities, links, views, statusColors, kindIcons } from './fixture'

// The fixture holds 14 containers on one hypervisor; a threshold of 4 folds
// them into a single group node. Click it to expand.
const expanded = ref(new Set<string>())
const theme = useSiteTheme()
const locale = useSiteLocale()
</script>

<template>
  <AssetMap
    v-model:expanded="expanded"
    class="demo-map"
    view="physical"
    :entities="entities"
    :links="links"
    :views="views"
    :collapse="{ threshold: 4 }"
    :theme="theme"
    :locale="locale"
    :theme-config="{ statusColors, kindIcons }"
    :layout="{ engine: 'manual', options: { columns: 5 } }"
    auto-fit-view
  />
</template>

Гарантии свёртки ​

Свёртка выполняется до раскладки: позиции считаются по свёрнутому графу, иначе групповой узел встал бы на место, рассчитанное для отдельных узлов. Функция чистая и детерминированная: порядок групп, узлов и рёбер выводится из порядка входных массивов, поэтому одинаковый вход даёт одинаковую карту.

Остальные инварианты:

  • Группировка идёт под ближайшим видимым предком. Если проекция скрыла родителя, его дети группируются уровнем выше, а не под скрытым id.
  • Группы не вкладываются. Обход идёт сверху вниз, и в свёрнутый уровень он не заходит.
  • Раскрытие руками всегда сильнее. expandedIds проверяется раньше правила, поэтому побеждает и shouldCollapse, и порог.
  • Группа из одного узла не создаётся никогда. Она прячет узел за узлом и ничего не экономит; это ограничение сильнее shouldCollapse.
  • Настоящая кратность остаётся видимой. Параллельные рёбра агрегируются, только если хотя бы один конец — группа.
  • Рёбра внутри группы не рисуются. Они считаются в CollapsedGroup.internalLinkCount, поэтому группа может показать, сколько связей у неё внутренние.

Своя группировка ​

groupBy возвращает ключ ведра или null, чтобы вывести сущность из группировки вовсе:

ts
const collapse = {
  threshold: 6,
  // Группируем по подсети вместо типа и никогда не прячем критичные активы.
  groupBy: (entity) => (entity.meta?.severity === 'critical' ? null : (entity.meta?.subnet ?? entity.type)),
}

shouldCollapse полностью заменяет решение по порогу:

ts
const collapse = {
  shouldCollapse: (parentId, children) => parentId !== null && children.length > 3,
}

Управление состоянием ​

vue
<AssetMap v-model:expanded="expanded" :entities="entities" :links="links" />

expanded — это Set<string> из id групп. Компонент никогда не мутирует его на месте: наружу на каждое изменение уходит новый Set, потому что переданное множество может быть из стора, который мутации не отслеживает.

Id группы имеет вид group:<parentId>:<bucket>, и groupIdFor его собирает:

ts
import { groupIdFor } from 'vue-asset-map/core'

expanded.value = new Set([groupIdFor('pve-beelink', 'container')])

События ​

vue
<AssetMap
  :entities="entities"
  :links="links"
  @expand="({ groupId, group }) => console.log('раскрыта', groupId, group?.memberIds.length)"
  @collapse="({ groupId }) => console.log('свёрнута', groupId)"
/>

Отличие от свёртки поддерева ​

Кнопка на узле прячет его потомков, а сам узел остаётся на карте. Свёртка групп прячет соседей за синтетическим узлом. Эти два механизма сочетаются: спрятанное кнопкой поддерево разрешается раньше любых решений о группировке, поэтому его потомки не группируются и не доходят до списка узлов.

Состояние свёртки поддеревьев — это v-model:collapsedNodes, множество id, поэтому его можно восстановить или задать снаружи. showNodeToggle: false убирает кнопку, и тогда эта привязка остаётся единственным входом — ровно то, что нужно оформлению без кнопки.

MIT licensed