Свёртка групп
Свёртка складывает однотипных соседей в один групповой узел и переносит их рёбра на него. Например, четырнадцать контейнеров на одном гипервизоре превращаются в один узел со счётчиком вместо четырнадцати отдельных кругов.
interface CollapseRule {
threshold?: number
groupBy?: (entity: AssetEntity) => string | null
shouldCollapse?: (parentId: EntityId | null, children: readonly AssetEntity[]) => boolean
}По умолчанию дети группируются по type, и ведро сворачивается в группу, когда в нём больше десяти.
<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, чтобы вывести сущность из группировки вовсе:
const collapse = {
threshold: 6,
// Группируем по подсети вместо типа и никогда не прячем критичные активы.
groupBy: (entity) => (entity.meta?.severity === 'critical' ? null : (entity.meta?.subnet ?? entity.type)),
}shouldCollapse полностью заменяет решение по порогу:
const collapse = {
shouldCollapse: (parentId, children) => parentId !== null && children.length > 3,
}Управление состоянием
<AssetMap v-model:expanded="expanded" :entities="entities" :links="links" />expanded — это Set<string> из id групп. Компонент никогда не мутирует его на месте: наружу на каждое изменение уходит новый Set, потому что переданное множество может быть из стора, который мутации не отслеживает.
Id группы имеет вид group:<parentId>:<bucket>, и groupIdFor его собирает:
import { groupIdFor } from 'vue-asset-map/core'
expanded.value = new Set([groupIdFor('pve-beelink', 'container')])События
<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 убирает кнопку, и тогда эта привязка остаётся единственным входом — ровно то, что нужно оформлению без кнопки.