import { isDefined } from 'ts-is-present'; import { Edge } from '../types/Edge'; import { Link } from '../renderables/Link'; import { Labeller } from './Labeller'; type LabelPlacement = 'center' | 'join' | 'spread'; class LinkLabeller extends Labeller { private _linkMap: Map; private _placement: LabelPlacement; constructor () { super(); this._linkMap = new Map(); this._placement = 'spread'; } getPlacement (): LabelPlacement { return this._placement; } setLinkMap (links: Map) { this._linkMap = links; } setPlacement (placement: LabelPlacement): void { this._placement = placement; } update (): void { if (this._placement === 'center') this._buildCenterLabels(); if (this._placement === 'join') this._buildJoinLabels(); if (this._placement === 'spread') this._buildSpreadLabels(); } _bezierBounds (np: number): [number, number] { if (np < 1) return [0.5, 0]; const dt = Math.min(0.8 / (np - 1), 0.1); const size = Math.min(dt * (np - 1), 0.8); const b = 0.5 - size / 2; return [b, dt]; } _buildCenterLabels (): void { this._linkMap.forEach((edges: Edge[], link: Link) => { link.labels = edges .filter(edge => isDefined(edge.label)) .map(edge => ({ t: 0.5, text: edge.label! })); }) } _buildJoinLabels (): void { this._linkMap.forEach((edges: Edge[], link: Link) => { link.labels = [{ text: buildCombinedLabel(edges), t: 0.5 }]; }); } _buildSpreadLabels (): void { this._linkMap.forEach((edges: Edge[], link: Link) => { if (edges.length) { const [b, dt] = this._bezierBounds(edges.length); link.labels = edges .filter(edge => isDefined(edge.label)) .map((edge, index) => ({ t: b + index * dt, text: edge.label! })); } }); } } function buildCombinedLabel (edges: Edge[]): string { return edges .map(edge => edge.label) .filter(isDefined) .join(', '); } export { LabelPlacement, LinkLabeller }