@unovis/ts 1.3.2-beta.1 → 1.3.2-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/chord-diagram/config.d.ts +6 -6
- package/components/chord-diagram/config.js.map +1 -1
- package/components/chord-diagram/index.d.ts +2 -3
- package/components/chord-diagram/index.js +43 -122
- package/components/chord-diagram/index.js.map +1 -1
- package/components/chord-diagram/modules/layout.d.ts +6 -0
- package/components/chord-diagram/modules/layout.js +86 -0
- package/components/chord-diagram/modules/layout.js.map +1 -0
- package/components/chord-diagram/modules/link.js +10 -11
- package/components/chord-diagram/modules/link.js.map +1 -1
- package/components/chord-diagram/modules/node.js +1 -1
- package/components/chord-diagram/modules/node.js.map +1 -1
- package/components/chord-diagram/style.d.ts +1 -0
- package/components/chord-diagram/style.js +8 -3
- package/components/chord-diagram/style.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,10 @@ import { ComponentConfigInterface } from "../../core/component/config";
|
|
|
2
2
|
import { ColorAccessor, GenericAccessor, NumericAccessor, StringAccessor } from "../../types/accessor";
|
|
3
3
|
import { ChordInputLink, ChordInputNode, ChordLabelAlignment, ChordLinkDatum, ChordNodeDatum } from './types';
|
|
4
4
|
export interface ChordDiagramConfigInterface<N extends ChordInputNode, L extends ChordInputLink> extends ComponentConfigInterface {
|
|
5
|
+
/** Angular range of the diagram. Default: `[0, 2 * Math.PI]` */
|
|
6
|
+
angleRange?: [number, number];
|
|
7
|
+
/** Corner radius constant value or accessor function. Default: `2` */
|
|
8
|
+
cornerRadius?: NumericAccessor<ChordNodeDatum<N>>;
|
|
5
9
|
/** Node id or index to highlight. Overrides default hover behavior if supplied. Default: `undefined` */
|
|
6
10
|
highlightedNodeId?: number | string;
|
|
7
11
|
/** Link ids or index values to highlight. Overrides default hover behavior if supplied. Default: [] */
|
|
@@ -22,12 +26,8 @@ export interface ChordDiagramConfigInterface<N extends ChordInputNode, L extends
|
|
|
22
26
|
nodeLabelColor?: StringAccessor<ChordNodeDatum<N>>;
|
|
23
27
|
/** Node label alignment. Default: `ChordLabelAlignment.Along` */
|
|
24
28
|
nodeLabelAlignment?: GenericAccessor<ChordLabelAlignment | string, ChordNodeDatum<N>>;
|
|
25
|
-
/** Pad angle in radians.
|
|
26
|
-
padAngle?:
|
|
27
|
-
/** Corner radius constant value or accessor function. Default: `2` */
|
|
28
|
-
cornerRadius?: NumericAccessor<ChordNodeDatum<N>>;
|
|
29
|
-
/** Angular range of the diagram. Default: `[0, 2 * Math.PI]` */
|
|
30
|
-
angleRange?: [number, number];
|
|
29
|
+
/** Pad angle in radians. Default: `0.02` */
|
|
30
|
+
padAngle?: number;
|
|
31
31
|
/** The exponent property of the radius scale. Default: `2` */
|
|
32
32
|
radiusScaleExponent?: number;
|
|
33
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sources":["../../../src/components/chord-diagram/config.ts"],"sourcesContent":["// Core\nimport { ComponentConfigInterface, ComponentDefaultConfig } from 'core/component/config'\n\n// Types\nimport { ColorAccessor, GenericAccessor, NumericAccessor, StringAccessor } from 'types/accessor'\n\n// Local Types\nimport { ChordInputLink, ChordInputNode, ChordLabelAlignment, ChordLinkDatum, ChordNodeDatum } from './types'\n\nexport interface ChordDiagramConfigInterface<N extends ChordInputNode, L extends ChordInputLink> extends ComponentConfigInterface {\n /** Node id or index to highlight. Overrides default hover behavior if supplied. Default: `undefined` */\n highlightedNodeId?: number | string;\n /** Link ids or index values to highlight. Overrides default hover behavior if supplied. Default: [] */\n highlightedLinkIds?: (number | string)[];\n /** Link color accessor function. Default: `var(--vis-chord-diagram-link-fill-color)` */\n linkColor?: ColorAccessor<ChordLinkDatum<N, L>>;\n /** Link value accessor function. Default: `l => l.value` */\n linkValue?: NumericAccessor<ChordLinkDatum<N, L>>;\n /** Array of node hierarchy levels. Data records are supposed to have corresponding properties, e.g. ['level1', 'level2']. Default: `[]` */\n nodeLevels?: string[];\n /** Node width in pixels. Default: `15` */\n nodeWidth?: number;\n /** Node color accessor function ot constant value. Default: `d => d.color` */\n nodeColor?: ColorAccessor<ChordNodeDatum<N>>;\n /** Node label accessor function. Default: `d => d.label ?? d.key` */\n nodeLabel?: StringAccessor<ChordNodeDatum<N>>;\n /** Node label color accessor function. Default: `undefined` */\n nodeLabelColor?: StringAccessor<ChordNodeDatum<N>>;\n /** Node label alignment. Default: `ChordLabelAlignment.Along` */\n nodeLabelAlignment?: GenericAccessor<ChordLabelAlignment | string, ChordNodeDatum<N>>;\n /** Pad angle in radians.
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../../src/components/chord-diagram/config.ts"],"sourcesContent":["// Core\nimport { ComponentConfigInterface, ComponentDefaultConfig } from 'core/component/config'\n\n// Types\nimport { ColorAccessor, GenericAccessor, NumericAccessor, StringAccessor } from 'types/accessor'\n\n// Local Types\nimport { ChordInputLink, ChordInputNode, ChordLabelAlignment, ChordLinkDatum, ChordNodeDatum } from './types'\n\nexport interface ChordDiagramConfigInterface<N extends ChordInputNode, L extends ChordInputLink> extends ComponentConfigInterface {\n /** Angular range of the diagram. Default: `[0, 2 * Math.PI]` */\n angleRange?: [number, number];\n /** Corner radius constant value or accessor function. Default: `2` */\n cornerRadius?: NumericAccessor<ChordNodeDatum<N>>;\n /** Node id or index to highlight. Overrides default hover behavior if supplied. Default: `undefined` */\n highlightedNodeId?: number | string;\n /** Link ids or index values to highlight. Overrides default hover behavior if supplied. Default: [] */\n highlightedLinkIds?: (number | string)[];\n /** Link color accessor function. Default: `var(--vis-chord-diagram-link-fill-color)` */\n linkColor?: ColorAccessor<ChordLinkDatum<N, L>>;\n /** Link value accessor function. Default: `l => l.value` */\n linkValue?: NumericAccessor<ChordLinkDatum<N, L>>;\n /** Array of node hierarchy levels. Data records are supposed to have corresponding properties, e.g. ['level1', 'level2']. Default: `[]` */\n nodeLevels?: string[];\n /** Node width in pixels. Default: `15` */\n nodeWidth?: number;\n /** Node color accessor function ot constant value. Default: `d => d.color` */\n nodeColor?: ColorAccessor<ChordNodeDatum<N>>;\n /** Node label accessor function. Default: `d => d.label ?? d.key` */\n nodeLabel?: StringAccessor<ChordNodeDatum<N>>;\n /** Node label color accessor function. Default: `undefined` */\n nodeLabelColor?: StringAccessor<ChordNodeDatum<N>>;\n /** Node label alignment. Default: `ChordLabelAlignment.Along` */\n nodeLabelAlignment?: GenericAccessor<ChordLabelAlignment | string, ChordNodeDatum<N>>;\n /** Pad angle in radians. Default: `0.02` */\n padAngle?: number;\n /** The exponent property of the radius scale. Default: `2` */\n radiusScaleExponent?: number;\n}\n\nexport const ChordDiagramDefaultConfig: ChordDiagramConfigInterface<ChordInputNode, ChordInputLink> = {\n ...ComponentDefaultConfig,\n duration: 800,\n highlightedNodeId: undefined,\n highlightedLinkIds: [],\n linkColor: undefined,\n linkValue: (d: ChordInputNode): number => (d as { value: number }).value,\n nodeLevels: [],\n nodeWidth: 15,\n nodeColor: (d: unknown): string => (d as { color: string }).color,\n nodeLabel: (d: unknown): string => (d as { label: string }).label ?? (d as { key: string }).key,\n nodeLabelColor: undefined,\n nodeLabelAlignment: ChordLabelAlignment.Along,\n padAngle: 0.02,\n cornerRadius: 2,\n angleRange: [0, 2 * Math.PI],\n radiusScaleExponent: 2,\n}\n"],"names":[],"mappings":";;;AAAA;MAwCa,yBAAyB,GAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,EAAA,EACjC,sBAAsB,CACzB,EAAA,EAAA,QAAQ,EAAE,GAAG,EACb,iBAAiB,EAAE,SAAS,EAC5B,kBAAkB,EAAE,EAAE,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,CAAiB,KAAc,CAAuB,CAAC,KAAK,EACxE,UAAU,EAAE,EAAE,EACd,SAAS,EAAE,EAAE,EACb,SAAS,EAAE,CAAC,CAAU,KAAc,CAAuB,CAAC,KAAK,EACjE,SAAS,EAAE,CAAC,CAAU,eAAa,OAAA,CAAA,EAAA,GAAC,CAAuB,CAAC,KAAK,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAK,CAAqB,CAAC,GAAG,CAAA,EAAA,EAC/F,cAAc,EAAE,SAAS,EACzB,kBAAkB,EAAE,mBAAmB,CAAC,KAAK,EAC7C,QAAQ,EAAE,IAAI,EACd,YAAY,EAAE,CAAC,EACf,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,EAC5B,mBAAmB,EAAE,CAAC,EAAA;;;;"}
|
|
@@ -11,6 +11,7 @@ export declare class ChordDiagram<N extends ChordInputNode, L extends ChordInput
|
|
|
11
11
|
protected _defaultConfig: ChordDiagramConfigInterface<N, L>;
|
|
12
12
|
config: ChordDiagramConfigInterface<N, L>;
|
|
13
13
|
datamodel: GraphDataModel<N, L>;
|
|
14
|
+
background: Selection<SVGRectElement, unknown, SVGGElement, unknown>;
|
|
14
15
|
nodeGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>;
|
|
15
16
|
linkGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>;
|
|
16
17
|
labelGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>;
|
|
@@ -33,10 +34,8 @@ export declare class ChordDiagram<N extends ChordInputNode, L extends ChordInput
|
|
|
33
34
|
get bleed(): Spacing;
|
|
34
35
|
setSize(width: number, height: number, containerWidth: number, containerHeight: number): void;
|
|
35
36
|
setData(data: GraphData<N, L>): void;
|
|
37
|
+
_layoutData(): void;
|
|
36
38
|
_render(customDuration?: number): void;
|
|
37
|
-
private _getHierarchyNodes;
|
|
38
|
-
private _getRibbons;
|
|
39
|
-
private _calculateRadialPosition;
|
|
40
39
|
private _onNodeMouseOver;
|
|
41
40
|
private _onNodeMouseOut;
|
|
42
41
|
private _onLinkMouseOver;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { max } from 'd3-array';
|
|
2
|
-
import {
|
|
3
|
-
import { partition, hierarchy } from 'd3-hierarchy';
|
|
2
|
+
import { partition } from 'd3-hierarchy';
|
|
4
3
|
import { scalePow } from 'd3-scale';
|
|
5
4
|
import { arc } from 'd3-shape';
|
|
6
5
|
import { ComponentCore } from '../../core/component/index.js';
|
|
7
6
|
import { GraphDataModel } from '../../data-models/graph.js';
|
|
8
|
-
import { getValue, getString, getNumber, isNumber
|
|
7
|
+
import { getValue, getString, getNumber, isNumber } from '../../utils/data.js';
|
|
9
8
|
import { estimateStringPixelLength } from '../../utils/text.js';
|
|
10
9
|
import { ChordLabelAlignment } from './types.js';
|
|
11
10
|
import { ChordDiagramDefaultConfig } from './config.js';
|
|
12
11
|
import { createNode, updateNode, removeNode } from './modules/node.js';
|
|
13
12
|
import { LABEL_PADDING, createLabel, updateLabel, removeLabel } from './modules/label.js';
|
|
13
|
+
import { getHierarchyNodes, positionChildren, getRibbons } from './modules/layout.js';
|
|
14
14
|
import { createLink, updateLink, removeLink } from './modules/link.js';
|
|
15
15
|
import * as style from './style.js';
|
|
16
|
-
import { links, nodes, labels, transparent, link, highlightedLink, node, highlightedNode, label, labelExit } from './style.js';
|
|
16
|
+
import { background, links, nodes, labels, transparent, link, highlightedLink, node, highlightedNode, label, labelExit } from './style.js';
|
|
17
17
|
|
|
18
18
|
class ChordDiagram extends ComponentCore {
|
|
19
19
|
constructor(config) {
|
|
@@ -41,6 +41,7 @@ class ChordDiagram extends ComponentCore {
|
|
|
41
41
|
};
|
|
42
42
|
if (config)
|
|
43
43
|
this.setConfig(config);
|
|
44
|
+
this.background = this.g.append('rect').attr('class', background);
|
|
44
45
|
this.linkGroup = this.g.append('g').attr('class', links);
|
|
45
46
|
this.nodeGroup = this.g.append('g').attr('class', nodes);
|
|
46
47
|
this.labelGroup = this.g.append('g').attr('class', labels);
|
|
@@ -87,46 +88,55 @@ class ChordDiagram extends ComponentCore {
|
|
|
87
88
|
}
|
|
88
89
|
setData(data) {
|
|
89
90
|
super.setData(data);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
91
|
+
this._layoutData();
|
|
92
|
+
}
|
|
93
|
+
_layoutData() {
|
|
94
|
+
const { nodes, links } = this.datamodel;
|
|
95
|
+
const { padAngle, linkValue, nodeLevels } = this.config;
|
|
96
|
+
nodes.forEach(n => { delete n._state.value; });
|
|
97
|
+
links.forEach(l => {
|
|
98
|
+
delete l._state.points;
|
|
99
|
+
l._state.value = getNumber(l, linkValue);
|
|
100
|
+
l.source._state.value = (l.source._state.value || 0) + getNumber(l, linkValue);
|
|
101
|
+
l.target._state.value = (l.target._state.value || 0) + getNumber(l, linkValue);
|
|
102
|
+
});
|
|
103
|
+
const root = getHierarchyNodes(nodes, d => { var _a; return (_a = d._state) === null || _a === void 0 ? void 0 : _a.value; }, nodeLevels);
|
|
104
|
+
const partitionData = partition().size([this.config.angleRange[1], 1])(root);
|
|
105
|
+
partitionData.each((n, i) => {
|
|
106
|
+
positionChildren(n, padAngle);
|
|
107
|
+
n.uid = `${this.uid.substr(0, 4)}-${i}`;
|
|
108
|
+
n.x0 = Number.isNaN(n.x0) ? 0 : n.x0;
|
|
109
|
+
n.x1 = Number.isNaN(n.x1) ? 0 : n.x1;
|
|
110
|
+
n._state = {};
|
|
108
111
|
});
|
|
109
112
|
const partitionDataWithRoot = partitionData.descendants();
|
|
110
113
|
this._rootNode = partitionDataWithRoot.find(d => d.depth === 0);
|
|
111
114
|
this._nodes = partitionDataWithRoot.filter(d => d.depth !== 0); // Filter out the root node
|
|
112
|
-
this._links =
|
|
115
|
+
this._links = getRibbons(partitionData, links, padAngle);
|
|
113
116
|
}
|
|
114
117
|
_render(customDuration) {
|
|
115
118
|
super._render(customDuration);
|
|
116
119
|
const { config, bleed } = this;
|
|
120
|
+
this._layoutData();
|
|
117
121
|
const duration = isNumber(customDuration) ? customDuration : config.duration;
|
|
118
122
|
const size = Math.min(this._width, this._height);
|
|
119
123
|
const radius = size / 2 - max([bleed.top, bleed.bottom, bleed.left, bleed.right]);
|
|
120
|
-
this.radiusScale.range([0, radius]);
|
|
124
|
+
this.radiusScale.range([0, radius - config.nodeWidth]);
|
|
121
125
|
this.arcGen
|
|
122
|
-
.startAngle(d => d.x0)
|
|
123
|
-
.endAngle(d => d.x1)
|
|
126
|
+
.startAngle(d => d.x0 + config.padAngle / 2 - (d.value ? 0 : Math.PI / 360))
|
|
127
|
+
.endAngle(d => d.x1 - config.padAngle / 2 + (d.value ? 0 : Math.PI / 360))
|
|
124
128
|
.cornerRadius(d => getNumber(d.data, config.cornerRadius))
|
|
125
|
-
.innerRadius(d => this.radiusScale(d.y1)
|
|
126
|
-
.outerRadius(d => this.radiusScale(d.y1));
|
|
127
|
-
// Center the view
|
|
128
|
-
this.g.attr('transform', `translate(${this._width / 2},${this._height / 2})`);
|
|
129
|
+
.innerRadius(d => this.radiusScale(d.y1))
|
|
130
|
+
.outerRadius(d => this.radiusScale(d.y1) + -getNumber(d, config.nodeWidth));
|
|
129
131
|
this.g.classed(transparent, this._forceHighlight);
|
|
132
|
+
this.background
|
|
133
|
+
.attr('width', this._width)
|
|
134
|
+
.attr('height', this._height)
|
|
135
|
+
.style('opacity', 0);
|
|
136
|
+
// Center the view
|
|
137
|
+
this.nodeGroup.attr('transform', `translate(${this._width / 2},${this._height / 2})`);
|
|
138
|
+
this.labelGroup.attr('transform', `translate(${this._width / 2},${this._height / 2})`);
|
|
139
|
+
this.linkGroup.attr('transform', `translate(${this._width / 2},${this._height / 2})`);
|
|
130
140
|
// Links
|
|
131
141
|
const linksSelection = this.linkGroup
|
|
132
142
|
.selectAll(`.${link}`)
|
|
@@ -169,98 +179,6 @@ class ChordDiagram extends ComponentCore {
|
|
|
169
179
|
.attr('class', labelExit)
|
|
170
180
|
.call(removeLabel, duration);
|
|
171
181
|
}
|
|
172
|
-
_getHierarchyNodes() {
|
|
173
|
-
const { config, datamodel: { nodes, links } } = this;
|
|
174
|
-
nodes.forEach(n => { delete n._state.value; });
|
|
175
|
-
links.forEach(l => {
|
|
176
|
-
delete l._state.points;
|
|
177
|
-
l.source._state.value = (l.source._state.value || 0) + getNumber(l, config.linkValue);
|
|
178
|
-
l.target._state.value = (l.target._state.value || 0) + getNumber(l, config.linkValue);
|
|
179
|
-
});
|
|
180
|
-
// TODO: Replace with d3-group
|
|
181
|
-
const nestGen = nest();
|
|
182
|
-
config.nodeLevels.forEach(levelAccessor => {
|
|
183
|
-
nestGen.key((d) => d[levelAccessor]);
|
|
184
|
-
});
|
|
185
|
-
const root = { key: 'root', values: nestGen.entries(nodes) };
|
|
186
|
-
const hierarchyNodes = hierarchy(root, d => d.values)
|
|
187
|
-
.sum((d) => { var _a; return (_a = d._state) === null || _a === void 0 ? void 0 : _a.value; });
|
|
188
|
-
return hierarchyNodes;
|
|
189
|
-
}
|
|
190
|
-
_getRibbons(partitionData) {
|
|
191
|
-
const { config, datamodel: { links } } = this;
|
|
192
|
-
const findNode = (nodes, id) => nodes.find(n => n.data._id === id);
|
|
193
|
-
const leafNodes = partitionData.leaves();
|
|
194
|
-
const groupedBySource = groupBy(links, d => d.source._id);
|
|
195
|
-
const groupedByTarget = groupBy(links, d => d.target._id);
|
|
196
|
-
const getNodesInRibbon = (source, target, partitionHeight, nodes = []) => {
|
|
197
|
-
nodes[source.height] = source;
|
|
198
|
-
nodes[partitionHeight * 2 - target.height] = target;
|
|
199
|
-
if (source.parent && target.parent)
|
|
200
|
-
getNodesInRibbon(source.parent, target.parent, partitionHeight, nodes);
|
|
201
|
-
return nodes;
|
|
202
|
-
};
|
|
203
|
-
const calculatePoints = (links, type, depth) => {
|
|
204
|
-
links.forEach(link => {
|
|
205
|
-
var _a;
|
|
206
|
-
if (!link._state.points)
|
|
207
|
-
link._state.points = [];
|
|
208
|
-
const sourceLeaf = findNode(leafNodes, link.source._id);
|
|
209
|
-
const targetLeaf = findNode(leafNodes, link.target._id);
|
|
210
|
-
const nodesInRibbon = getNodesInRibbon(type === 'out' ? sourceLeaf : targetLeaf, type === 'out' ? targetLeaf : sourceLeaf, partitionData.height);
|
|
211
|
-
const currNode = nodesInRibbon[depth];
|
|
212
|
-
const len = currNode.x1 - currNode.x0;
|
|
213
|
-
const x0 = (_a = currNode._prevX1) !== null && _a !== void 0 ? _a : currNode.x0;
|
|
214
|
-
const x1 = x0 + len * getNumber(link, config.linkValue) / currNode.value;
|
|
215
|
-
currNode._prevX1 = x1;
|
|
216
|
-
const pointIdx = type === 'out' ? depth : partitionData.height * 2 - 1 - depth;
|
|
217
|
-
link._state.points[pointIdx] = {
|
|
218
|
-
a0: Math.min(x0, x1),
|
|
219
|
-
a1: Math.max(x0, x1),
|
|
220
|
-
r: currNode.y1,
|
|
221
|
-
};
|
|
222
|
-
});
|
|
223
|
-
};
|
|
224
|
-
leafNodes.forEach(leafNode => {
|
|
225
|
-
const outLinks = groupedBySource[leafNode.data._id] || [];
|
|
226
|
-
const inLinks = groupedByTarget[leafNode.data._id] || [];
|
|
227
|
-
for (let depth = 0; depth < partitionData.height; depth += 1) {
|
|
228
|
-
calculatePoints(outLinks, 'out', depth);
|
|
229
|
-
calculatePoints(inLinks, 'in', depth);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
const ribbons = links.map(l => {
|
|
233
|
-
const sourceNode = findNode(leafNodes, l.source._id);
|
|
234
|
-
const targetNode = findNode(leafNodes, l.target._id);
|
|
235
|
-
return {
|
|
236
|
-
source: sourceNode,
|
|
237
|
-
target: targetNode,
|
|
238
|
-
data: l,
|
|
239
|
-
points: l._state.points,
|
|
240
|
-
_state: {},
|
|
241
|
-
};
|
|
242
|
-
});
|
|
243
|
-
return ribbons;
|
|
244
|
-
}
|
|
245
|
-
_calculateRadialPosition(hierarchyNode, nodePadding = 0.02, scalingCoeff = 0.95) {
|
|
246
|
-
if (!hierarchyNode.children)
|
|
247
|
-
return;
|
|
248
|
-
// Calculate x0 and x1
|
|
249
|
-
const nodeLength = (hierarchyNode.x1 - hierarchyNode.x0);
|
|
250
|
-
const scaledNodeLength = nodeLength * scalingCoeff;
|
|
251
|
-
const delta = nodeLength - scaledNodeLength;
|
|
252
|
-
let x0 = hierarchyNode.x0 + delta / 2;
|
|
253
|
-
for (const node of hierarchyNode.children) {
|
|
254
|
-
const childX0 = x0;
|
|
255
|
-
const childX1 = x0 + (node.value / hierarchyNode.value) * scaledNodeLength - nodePadding / 2;
|
|
256
|
-
const childNodeLength = childX1 - childX0;
|
|
257
|
-
const scaledChildNodeLength = childNodeLength * scalingCoeff;
|
|
258
|
-
const childDelta = childNodeLength - scaledChildNodeLength;
|
|
259
|
-
node.x0 = childX0 + childDelta / 2;
|
|
260
|
-
node.x1 = node.x0 + scaledChildNodeLength;
|
|
261
|
-
x0 = childX1 + nodePadding / 2 + childDelta / 2;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
182
|
_onNodeMouseOver(d) {
|
|
265
183
|
let ribbons;
|
|
266
184
|
if (d.children) {
|
|
@@ -271,6 +189,9 @@ class ChordDiagram extends ComponentCore {
|
|
|
271
189
|
const leaf = d;
|
|
272
190
|
ribbons = this._links.filter(l => l.source.data.id === leaf.data.id || l.target.data.id === leaf.data.id);
|
|
273
191
|
}
|
|
192
|
+
// Nodes without links should still be highlighted
|
|
193
|
+
if (!ribbons.length)
|
|
194
|
+
d._state.hovered = true;
|
|
274
195
|
this._highlightOnHover(ribbons);
|
|
275
196
|
}
|
|
276
197
|
_onNodeMouseOut() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/components/chord-diagram/index.ts"],"sourcesContent":["import { max } from 'd3-array'\nimport { nest } from 'd3-collection'\nimport { HierarchyNode, hierarchy, partition } from 'd3-hierarchy'\nimport { Selection } from 'd3-selection'\nimport { scalePow, ScalePower } from 'd3-scale'\nimport { arc } from 'd3-shape'\n\n// Core\nimport { ComponentCore } from 'core/component'\nimport { GraphData, GraphDataModel } from 'data-models/graph'\n\n// Utils\nimport { getNumber, isNumber, groupBy, getString, getValue } from 'utils/data'\nimport { estimateStringPixelLength } from 'utils/text'\n\n// Types\nimport { GraphNodeCore } from 'types/graph'\nimport { Spacing } from 'types/spacing'\n\n// Local Types\nimport {\n ChordInputNode,\n ChordInputLink,\n ChordDiagramData,\n ChordHierarchyNode,\n ChordNode,\n ChordRibbon,\n ChordLabelAlignment,\n ChordLeafNode,\n} from './types'\n\n// Config\nimport { ChordDiagramDefaultConfig, ChordDiagramConfigInterface } from './config'\n\n// Modules\nimport { createNode, updateNode, removeNode } from './modules/node'\nimport { createLabel, updateLabel, removeLabel, LABEL_PADDING } from './modules/label'\nimport { createLink, updateLink, removeLink } from './modules/link'\n\n// Styles\nimport * as s from './style'\n\nexport class ChordDiagram<\n N extends ChordInputNode,\n L extends ChordInputLink,\n> extends ComponentCore<\n ChordDiagramData<N, L>,\n ChordDiagramConfigInterface<N, L>\n > {\n static selectors = s\n protected _defaultConfig = ChordDiagramDefaultConfig as ChordDiagramConfigInterface<N, L>\n public config: ChordDiagramConfigInterface<N, L> = this._defaultConfig\n datamodel: GraphDataModel<N, L> = new GraphDataModel()\n\n nodeGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>\n linkGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>\n labelGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>\n arcGen = arc<ChordNode<N>>()\n radiusScale: ScalePower<number, number> = scalePow()\n\n private _nodes: ChordNode<N>[] = []\n private _links: ChordRibbon<N>[] = []\n private _rootNode: ChordNode<N>\n\n events = {\n [ChordDiagram.selectors.node]: {\n mouseover: this._onNodeMouseOver.bind(this),\n mouseout: this._onNodeMouseOut.bind(this),\n },\n [ChordDiagram.selectors.link]: {\n mouseover: this._onLinkMouseOver.bind(this),\n mouseout: this._onLinkMouseOut.bind(this),\n },\n [ChordDiagram.selectors.label]: {\n mouseover: this._onNodeMouseOver.bind(this),\n mouseout: this._onNodeMouseOut.bind(this),\n },\n }\n\n private get _forceHighlight (): boolean {\n return this.config.highlightedNodeId !== undefined || this.config.highlightedLinkIds?.length > 0\n }\n\n constructor (config?: ChordDiagramConfigInterface<N, L>) {\n super()\n if (config) this.setConfig(config)\n this.linkGroup = this.g.append('g').attr('class', s.links)\n this.nodeGroup = this.g.append('g').attr('class', s.nodes)\n this.labelGroup = this.g.append('g').attr('class', s.labels)\n }\n\n get bleed (): Spacing {\n const { config } = this\n const padding = 4 + LABEL_PADDING * 2\n let top = 0; let bottom = 0; let right = 0; let left = 0\n this._nodes.forEach(n => {\n const nodeLabelAlignment = getValue(n.data, config.nodeLabelAlignment)\n if (n.height === 0 && nodeLabelAlignment === ChordLabelAlignment.Perpendicular) {\n const labelWidth = estimateStringPixelLength(getString(n.data as N, config.nodeLabel) ?? '', 16)\n const [x, y] = this.arcGen.centroid(n)\n\n if (x < 0) left = Math.max(left, labelWidth)\n else right = Math.max(right, labelWidth)\n\n if (y < 0) top = Math.max(top, labelWidth)\n else bottom = Math.max(bottom, labelWidth)\n }\n })\n left += padding\n right += padding\n bottom += padding\n top += padding\n return { top, bottom, left, right }\n }\n\n setSize (width: number, height: number, containerWidth: number, containerHeight: number): void {\n super.setSize(width, height, containerWidth, containerHeight)\n\n // Setting radius for initial bleed calculation. This ensures the correct radius is set when render is called\n this.radiusScale\n .exponent(this.config.radiusScaleExponent)\n .range([0, Math.min(width, height) / 2])\n }\n\n setData (data: GraphData<N, L>): void {\n super.setData(data)\n const hierarchyData = this._getHierarchyNodes()\n\n const partitionData = partition<N | ChordHierarchyNode<N>>()\n .size([this.config.angleRange[1], 1])(hierarchyData) as ChordNode<N>\n\n partitionData.each((node, i) => {\n this._calculateRadialPosition(node, getNumber(node.data, this.config.padAngle))\n\n // Add hierarchy data for non leaf nodes\n if (node.children) {\n node.data = Object.assign(node.data, {\n depth: node.depth,\n height: node.height,\n value: node.value,\n ancestors: node.ancestors().map(d => (d.data as ChordHierarchyNode<N>).key),\n })\n }\n node.x0 = Number.isNaN(node.x0) ? 0 : node.x0\n node.x1 = Number.isNaN(node.x1) ? 0 : node.x1\n node.uid = `${this.uid}-n${i}`\n node._state = {}\n })\n\n const partitionDataWithRoot = partitionData.descendants()\n this._rootNode = partitionDataWithRoot.find(d => d.depth === 0)\n this._nodes = partitionDataWithRoot.filter(d => d.depth !== 0) // Filter out the root node\n this._links = this._getRibbons(partitionData)\n }\n\n _render (customDuration?: number): void {\n super._render(customDuration)\n const { config, bleed } = this\n\n const duration = isNumber(customDuration) ? customDuration : config.duration\n const size = Math.min(this._width, this._height)\n const radius = size / 2 - max([bleed.top, bleed.bottom, bleed.left, bleed.right])\n\n this.radiusScale.range([0, radius])\n\n this.arcGen\n .startAngle(d => d.x0)\n .endAngle(d => d.x1)\n .cornerRadius(d => getNumber(d.data, config.cornerRadius))\n .innerRadius(d => this.radiusScale(d.y1) - getNumber(d, config.nodeWidth))\n .outerRadius(d => this.radiusScale(d.y1))\n\n // Center the view\n this.g.attr('transform', `translate(${this._width / 2},${this._height / 2})`)\n this.g.classed(s.transparent, this._forceHighlight)\n\n // Links\n const linksSelection = this.linkGroup\n .selectAll<SVGPathElement, ChordRibbon<N>>(`.${s.link}`)\n .data(this._links, d => String(d.data._id))\n .classed(s.highlightedLink, l => {\n const linkId = l.data.id ?? l.data._indexGlobal\n return config.highlightedLinkIds?.includes(linkId)\n })\n\n const linksEnter = linksSelection.enter().append('path')\n .attr('class', s.link)\n .call(createLink, this.radiusScale)\n\n const linksMerged = linksSelection.merge(linksEnter)\n linksMerged.call(updateLink, config, this.radiusScale, duration)\n\n linksSelection.exit()\n .call(removeLink, duration)\n\n // Nodes\n const nodesSelection = this.nodeGroup\n .selectAll<SVGPathElement, ChordNode<N>>(`.${s.node}`)\n .data(this._nodes, d => String(d.uid))\n .classed(s.highlightedNode, d => config.highlightedNodeId === d.data._id)\n\n const nodesEnter = nodesSelection.enter().append('path')\n .attr('class', s.node)\n .call(createNode, config)\n\n const nodesMerged = nodesSelection.merge(nodesEnter)\n nodesMerged.call(updateNode, config, this.arcGen, duration, this.bleed)\n\n nodesSelection.exit()\n .call(removeNode, duration)\n\n // Labels\n const labelWidth = size - radius - config.nodeWidth\n const labels = this.labelGroup\n .selectAll<SVGGElement, ChordNode<N>>(`.${s.label}`)\n .data(this._nodes, d => String(d.uid))\n\n const labelEnter = labels.enter().append('g')\n .attr('class', s.label)\n .call(createLabel, config, this.radiusScale)\n\n const labelsMerged = labels.merge(labelEnter)\n labelsMerged.call(updateLabel, config, labelWidth, this.radiusScale, duration)\n\n labels.exit()\n .attr('class', s.labelExit)\n .call(removeLabel, duration)\n }\n\n private _getHierarchyNodes (): HierarchyNode<ChordHierarchyNode<N>> {\n const { config, datamodel: { nodes, links } } = this\n nodes.forEach(n => { delete n._state.value })\n links.forEach(l => {\n delete l._state.points\n l.source._state.value = (l.source._state.value || 0) + getNumber(l, config.linkValue)\n l.target._state.value = (l.target._state.value || 0) + getNumber(l, config.linkValue)\n })\n\n // TODO: Replace with d3-group\n const nestGen = nest<N>()\n config.nodeLevels.forEach(levelAccessor => {\n nestGen.key((d) => (d as unknown as Record<string, string>)[levelAccessor])\n })\n const root = { key: 'root', values: nestGen.entries(nodes) }\n const hierarchyNodes = hierarchy(root, d => d.values)\n .sum((d) => (d as unknown as GraphNodeCore<N, L>)._state?.value)\n\n return hierarchyNodes\n }\n\n private _getRibbons (partitionData: ChordNode<N>): ChordRibbon<N>[] {\n const { config, datamodel: { links } } = this\n const findNode = (\n nodes: ChordLeafNode<N>[],\n id: string\n ): ChordLeafNode<N> => nodes.find(n => n.data._id === id)\n const leafNodes = partitionData.leaves() as ChordLeafNode<N>[]\n\n type LinksArrayType = typeof links\n const groupedBySource: Record<string, LinksArrayType> = groupBy(links, d => d.source._id)\n const groupedByTarget: Record<string, LinksArrayType> = groupBy(links, d => d.target._id)\n\n const getNodesInRibbon = (\n source: ChordLeafNode<N>,\n target: ChordLeafNode<N>,\n partitionHeight: number,\n nodes: ChordLeafNode<N>[] = []\n ): ChordNode<N>[] => {\n nodes[source.height] = source\n nodes[partitionHeight * 2 - target.height] = target\n if (source.parent && target.parent) getNodesInRibbon(source.parent, target.parent, partitionHeight, nodes)\n return nodes\n }\n\n const calculatePoints = (\n links: LinksArrayType,\n type: 'in' | 'out',\n depth: number\n ): void => {\n links.forEach(link => {\n if (!link._state.points) link._state.points = []\n const sourceLeaf = findNode(leafNodes, link.source._id)\n const targetLeaf = findNode(leafNodes, link.target._id)\n const nodesInRibbon = getNodesInRibbon(\n type === 'out' ? sourceLeaf : targetLeaf,\n type === 'out' ? targetLeaf : sourceLeaf,\n partitionData.height)\n const currNode = nodesInRibbon[depth]\n const len = currNode.x1 - currNode.x0\n const x0 = currNode._prevX1 ?? currNode.x0\n const x1 = x0 + len * getNumber(link, config.linkValue) / currNode.value\n currNode._prevX1 = x1\n\n const pointIdx = type === 'out' ? depth : partitionData.height * 2 - 1 - depth\n link._state.points[pointIdx] = {\n a0: Math.min(x0, x1), // - Math.PI / 2,\n a1: Math.max(x0, x1), // - Math.PI / 2,\n r: currNode.y1,\n }\n })\n }\n\n leafNodes.forEach(leafNode => {\n const outLinks = groupedBySource[leafNode.data._id] || []\n const inLinks = groupedByTarget[leafNode.data._id] || []\n for (let depth = 0; depth < partitionData.height; depth += 1) {\n calculatePoints(outLinks, 'out', depth)\n calculatePoints(inLinks, 'in', depth)\n }\n })\n\n const ribbons = links.map(l => {\n const sourceNode = findNode(leafNodes, l.source._id)\n const targetNode = findNode(leafNodes, l.target._id)\n\n return {\n source: sourceNode,\n target: targetNode,\n data: l,\n points: l._state.points,\n _state: {},\n }\n })\n\n return ribbons\n }\n\n private _calculateRadialPosition (\n hierarchyNode: ChordNode<N>,\n nodePadding = 0.02,\n scalingCoeff = 0.95\n ): void {\n if (!hierarchyNode.children) return\n\n // Calculate x0 and x1\n const nodeLength = (hierarchyNode.x1 - hierarchyNode.x0)\n const scaledNodeLength = nodeLength * scalingCoeff\n const delta = nodeLength - scaledNodeLength\n let x0 = hierarchyNode.x0 + delta / 2\n for (const node of hierarchyNode.children) {\n const childX0 = x0\n const childX1 = x0 + (node.value / hierarchyNode.value) * scaledNodeLength - nodePadding / 2\n const childNodeLength = childX1 - childX0\n const scaledChildNodeLength = childNodeLength * scalingCoeff\n const childDelta = childNodeLength - scaledChildNodeLength\n node.x0 = childX0 + childDelta / 2\n node.x1 = node.x0 + scaledChildNodeLength\n x0 = childX1 + nodePadding / 2 + childDelta / 2\n }\n }\n\n private _onNodeMouseOver (d: ChordNode<N>): void {\n let ribbons: ChordRibbon<N>[]\n if (d.children) {\n const leaves = d.leaves() as ChordLeafNode<N>[]\n ribbons = this._links.filter(l =>\n leaves.find(leaf => l.source.data.id === leaf.data.id || l.target.data.id === leaf.data.id)\n )\n } else {\n const leaf = d as ChordLeafNode<N>\n ribbons = this._links.filter(l => l.source.data.id === leaf.data.id || l.target.data.id === leaf.data.id)\n }\n this._highlightOnHover(ribbons)\n }\n\n private _onNodeMouseOut (): void {\n this._highlightOnHover()\n }\n\n private _onLinkMouseOver (d: ChordRibbon<N>): void {\n this._highlightOnHover([d])\n }\n\n private _onLinkMouseOut (): void {\n this._highlightOnHover()\n }\n\n private _highlightOnHover (links?: ChordRibbon<N>[]): void {\n if (this._forceHighlight) return\n if (links) {\n links.forEach(l => {\n l._state.hovered = true\n const sourcePath = (l.source as ChordNode<N>).path(this._rootNode)\n const targetPath = (l.target as ChordNode<N>).path(this._rootNode)\n sourcePath.forEach(n => { if (n.depth) n._state.hovered = true })\n targetPath.forEach(n => { if (n.depth) n._state.hovered = true })\n })\n } else {\n this._nodes.forEach(n => { delete n._state.hovered })\n this._links.forEach(l => { delete l._state.hovered })\n }\n\n this.nodeGroup.selectAll<SVGPathElement, ChordNode<N>>(`.${s.node}`)\n .classed(s.highlightedNode, d => d._state.hovered)\n this.linkGroup.selectAll<SVGPathElement, ChordRibbon<N>>(`.${s.link}`)\n .classed(s.highlightedLink, d => d._state.hovered)\n\n this.g.classed(s.transparent, !!links)\n }\n}\n"],"names":["s.links","s.nodes","s.labels","s.transparent","s.link","s.highlightedLink","s.node","s.highlightedNode","s.label","s.labelExit","s"],"mappings":";;;;;;;;;;;;;;;;;AA0CM,MAAO,YAGX,SAAQ,aAGP,CAAA;AAmCD,IAAA,WAAA,CAAa,MAA0C,EAAA;AACrD,QAAA,KAAK,EAAE,CAAA;QAlCC,IAAc,CAAA,cAAA,GAAG,yBAA8D,CAAA;AAClF,QAAA,IAAA,CAAA,MAAM,GAAsC,IAAI,CAAC,cAAc,CAAA;AACtE,QAAA,IAAA,CAAA,SAAS,GAAyB,IAAI,cAAc,EAAE,CAAA;QAKtD,IAAM,CAAA,MAAA,GAAG,GAAG,EAAgB,CAAA;QAC5B,IAAW,CAAA,WAAA,GAA+B,QAAQ,EAAE,CAAA;QAE5C,IAAM,CAAA,MAAA,GAAmB,EAAE,CAAA;QAC3B,IAAM,CAAA,MAAA,GAAqB,EAAE,CAAA;AAGrC,QAAA,IAAA,CAAA,MAAM,GAAG;AACP,YAAA,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,GAAG;gBAC7B,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC3C,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;AAC1C,aAAA;AACD,YAAA,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,GAAG;gBAC7B,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC3C,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;AAC1C,aAAA;AACD,YAAA,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,GAAG;gBAC9B,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC3C,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;AAC1C,aAAA;SACF,CAAA;AAQC,QAAA,IAAI,MAAM;AAAE,YAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QAClC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAEA,KAAO,CAAC,CAAA;QAC1D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAEC,KAAO,CAAC,CAAA;QAC1D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAEC,MAAQ,CAAC,CAAA;KAC7D;AAVD,IAAA,IAAY,eAAe,GAAA;;AACzB,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,iBAAiB,KAAK,SAAS,IAAI,CAAA,MAAA,IAAI,CAAC,MAAM,CAAC,kBAAkB,0CAAE,MAAM,IAAG,CAAC,CAAA;KACjG;AAUD,IAAA,IAAI,KAAK,GAAA;AACP,QAAA,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;AACvB,QAAA,MAAM,OAAO,GAAG,CAAC,GAAG,aAAa,GAAG,CAAC,CAAA;QACrC,IAAI,GAAG,GAAG,CAAC,CAAC;QAAC,IAAI,MAAM,GAAG,CAAC,CAAC;QAAC,IAAI,KAAK,GAAG,CAAC,CAAC;QAAC,IAAI,IAAI,GAAG,CAAC,CAAA;AACxD,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAG;;AACtB,YAAA,MAAM,kBAAkB,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAA;YACtE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,kBAAkB,KAAK,mBAAmB,CAAC,aAAa,EAAE;gBAC9E,MAAM,UAAU,GAAG,yBAAyB,CAAC,MAAA,SAAS,CAAC,CAAC,CAAC,IAAS,EAAE,MAAM,CAAC,SAAS,CAAC,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,EAAE,EAAE,EAAE,CAAC,CAAA;AAChG,gBAAA,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;gBAEtC,IAAI,CAAC,GAAG,CAAC;oBAAE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;;oBACvC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA;gBAExC,IAAI,CAAC,GAAG,CAAC;oBAAE,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;;oBACrC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;AAC3C,aAAA;AACH,SAAC,CAAC,CAAA;QACF,IAAI,IAAI,OAAO,CAAA;QACf,KAAK,IAAI,OAAO,CAAA;QAChB,MAAM,IAAI,OAAO,CAAA;QACjB,GAAG,IAAI,OAAO,CAAA;QACd,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;KACpC;AAED,IAAA,OAAO,CAAE,KAAa,EAAE,MAAc,EAAE,cAAsB,EAAE,eAAuB,EAAA;QACrF,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,CAAC,CAAA;;AAG7D,QAAA,IAAI,CAAC,WAAW;AACb,aAAA,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC;AACzC,aAAA,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;KAC3C;AAED,IAAA,OAAO,CAAE,IAAqB,EAAA;AAC5B,QAAA,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AACnB,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAE/C,MAAM,aAAa,GAAG,SAAS,EAA6B;AACzD,aAAA,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAiB,CAAA;QAEtE,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,KAAI;AAC7B,YAAA,IAAI,CAAC,wBAAwB,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;;YAG/E,IAAI,IAAI,CAAC,QAAQ,EAAE;gBACjB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE;oBACnC,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;AACjB,oBAAA,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,IAAK,CAAC,CAAC,IAA8B,CAAC,GAAG,CAAC;AAC5E,iBAAA,CAAC,CAAA;AACH,aAAA;YACD,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAA;YAC7C,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAA;YAC7C,IAAI,CAAC,GAAG,GAAG,CAAG,EAAA,IAAI,CAAC,GAAG,CAAA,EAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AAC9B,YAAA,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;AAClB,SAAC,CAAC,CAAA;AAEF,QAAA,MAAM,qBAAqB,GAAG,aAAa,CAAC,WAAW,EAAE,CAAA;AACzD,QAAA,IAAI,CAAC,SAAS,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAA;AAC/D,QAAA,IAAI,CAAC,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAA;QAC9D,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAA;KAC9C;AAED,IAAA,OAAO,CAAE,cAAuB,EAAA;AAC9B,QAAA,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;AAC7B,QAAA,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;AAE9B,QAAA,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,GAAG,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAA;AAC5E,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAChD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;QAEjF,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;AAEnC,QAAA,IAAI,CAAC,MAAM;aACR,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;aACrB,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;AACnB,aAAA,YAAY,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;aACzD,WAAW,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;AACzE,aAAA,WAAW,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;;QAG3C,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAG,CAAA,CAAA,CAAC,CAAA;AAC7E,QAAA,IAAI,CAAC,CAAC,CAAC,OAAO,CAACC,WAAa,EAAE,IAAI,CAAC,eAAe,CAAC,CAAA;;AAGnD,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS;AAClC,aAAA,SAAS,CAAiC,CAAI,CAAA,EAAAC,IAAM,EAAE,CAAC;AACvD,aAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1C,aAAA,OAAO,CAACC,eAAiB,EAAE,CAAC,IAAG;;AAC9B,YAAA,MAAM,MAAM,GAAG,CAAA,EAAA,GAAA,CAAC,CAAC,IAAI,CAAC,EAAE,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAA;YAC/C,OAAO,CAAA,EAAA,GAAA,MAAM,CAAC,kBAAkB,0CAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;AACpD,SAAC,CAAC,CAAA;QAEJ,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;AACrD,aAAA,IAAI,CAAC,OAAO,EAAED,IAAM,CAAC;AACrB,aAAA,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QAErC,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AACpD,QAAA,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QAEhE,cAAc,CAAC,IAAI,EAAE;AAClB,aAAA,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;;AAG7B,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS;AAClC,aAAA,SAAS,CAA+B,CAAI,CAAA,EAAAE,IAAM,EAAE,CAAC;AACrD,aAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACrC,aAAA,OAAO,CAACC,eAAiB,EAAE,CAAC,IAAI,MAAM,CAAC,iBAAiB,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAE3E,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;AACrD,aAAA,IAAI,CAAC,OAAO,EAAED,IAAM,CAAC;AACrB,aAAA,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;QAE3B,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AACpD,QAAA,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAEvE,cAAc,CAAC,IAAI,EAAE;AAClB,aAAA,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;;QAG7B,MAAM,UAAU,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC,SAAS,CAAA;AACnD,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU;AAC3B,aAAA,SAAS,CAA4B,CAAI,CAAA,EAAAE,KAAO,EAAE,CAAC;AACnD,aAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAExC,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC;AAC1C,aAAA,IAAI,CAAC,OAAO,EAAEA,KAAO,CAAC;aACtB,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QAE9C,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;AAC7C,QAAA,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QAE9E,MAAM,CAAC,IAAI,EAAE;AACV,aAAA,IAAI,CAAC,OAAO,EAAEC,SAAW,CAAC;AAC1B,aAAA,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;KAC/B;IAEO,kBAAkB,GAAA;AACxB,QAAA,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,IAAI,CAAA;AACpD,QAAA,KAAK,CAAC,OAAO,CAAC,CAAC,IAAM,EAAA,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA,EAAE,CAAC,CAAA;AAC7C,QAAA,KAAK,CAAC,OAAO,CAAC,CAAC,IAAG;AAChB,YAAA,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,CAAA;YACtB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;YACrF,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;AACvF,SAAC,CAAC,CAAA;;AAGF,QAAA,MAAM,OAAO,GAAG,IAAI,EAAK,CAAA;AACzB,QAAA,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,IAAG;AACxC,YAAA,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAM,CAAuC,CAAC,aAAa,CAAC,CAAC,CAAA;AAC7E,SAAC,CAAC,CAAA;AACF,QAAA,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAA;AAC5D,QAAA,MAAM,cAAc,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAClD,aAAA,GAAG,CAAC,CAAC,CAAC,eAAK,OAAA,CAAA,EAAA,GAAC,CAAoC,CAAC,MAAM,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,KAAK,CAAA,EAAA,CAAC,CAAA;AAElE,QAAA,OAAO,cAAc,CAAA;KACtB;AAEO,IAAA,WAAW,CAAE,aAA2B,EAAA;QAC9C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,IAAI,CAAA;QAC7C,MAAM,QAAQ,GAAG,CACf,KAAyB,EACzB,EAAU,KACW,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,CAAA;AACzD,QAAA,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,EAAwB,CAAA;AAG9D,QAAA,MAAM,eAAe,GAAmC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACzF,QAAA,MAAM,eAAe,GAAmC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AAEzF,QAAA,MAAM,gBAAgB,GAAG,CACvB,MAAwB,EACxB,MAAwB,EACxB,eAAuB,EACvB,KAAA,GAA4B,EAAE,KACZ;AAClB,YAAA,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;YAC7B,KAAK,CAAC,eAAe,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;AACnD,YAAA,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;AAAE,gBAAA,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,CAAA;AAC1G,YAAA,OAAO,KAAK,CAAA;AACd,SAAC,CAAA;QAED,MAAM,eAAe,GAAG,CACtB,KAAqB,EACrB,IAAkB,EAClB,KAAa,KACL;AACR,YAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAG;;AACnB,gBAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;AAAE,oBAAA,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAA;AAChD,gBAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACvD,gBAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACvD,gBAAA,MAAM,aAAa,GAAG,gBAAgB,CACpC,IAAI,KAAK,KAAK,GAAG,UAAU,GAAG,UAAU,EACxC,IAAI,KAAK,KAAK,GAAG,UAAU,GAAG,UAAU,EACxC,aAAa,CAAC,MAAM,CAAC,CAAA;AACvB,gBAAA,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;gBACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAA;gBACrC,MAAM,EAAE,GAAG,CAAA,EAAA,GAAA,QAAQ,CAAC,OAAO,MAAI,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAA,QAAQ,CAAC,EAAE,CAAA;AAC1C,gBAAA,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAA;AACxE,gBAAA,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAA;gBAErB,MAAM,QAAQ,GAAG,IAAI,KAAK,KAAK,GAAG,KAAK,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAC9E,gBAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG;oBAC7B,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC;oBACpB,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC;oBACpB,CAAC,EAAE,QAAQ,CAAC,EAAE;iBACf,CAAA;AACH,aAAC,CAAC,CAAA;AACJ,SAAC,CAAA;AAED,QAAA,SAAS,CAAC,OAAO,CAAC,QAAQ,IAAG;AAC3B,YAAA,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;AACzD,YAAA,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;AACxD,YAAA,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,aAAa,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE;AAC5D,gBAAA,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;AACvC,gBAAA,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AACtC,aAAA;AACH,SAAC,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAG;AAC5B,YAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACpD,YAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAEpD,OAAO;AACL,gBAAA,MAAM,EAAE,UAAU;AAClB,gBAAA,MAAM,EAAE,UAAU;AAClB,gBAAA,IAAI,EAAE,CAAC;AACP,gBAAA,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;AACvB,gBAAA,MAAM,EAAE,EAAE;aACX,CAAA;AACH,SAAC,CAAC,CAAA;AAEF,QAAA,OAAO,OAAO,CAAA;KACf;IAEO,wBAAwB,CAC9B,aAA2B,EAC3B,WAAW,GAAG,IAAI,EAClB,YAAY,GAAG,IAAI,EAAA;QAEnB,IAAI,CAAC,aAAa,CAAC,QAAQ;YAAE,OAAM;;QAGnC,MAAM,UAAU,IAAI,aAAa,CAAC,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;AACxD,QAAA,MAAM,gBAAgB,GAAG,UAAU,GAAG,YAAY,CAAA;AAClD,QAAA,MAAM,KAAK,GAAG,UAAU,GAAG,gBAAgB,CAAA;QAC3C,IAAI,EAAE,GAAG,aAAa,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAA;AACrC,QAAA,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,QAAQ,EAAE;YACzC,MAAM,OAAO,GAAG,EAAE,CAAA;AAClB,YAAA,MAAM,OAAO,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,aAAa,CAAC,KAAK,IAAI,gBAAgB,GAAG,WAAW,GAAG,CAAC,CAAA;AAC5F,YAAA,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,CAAA;AACzC,YAAA,MAAM,qBAAqB,GAAG,eAAe,GAAG,YAAY,CAAA;AAC5D,YAAA,MAAM,UAAU,GAAG,eAAe,GAAG,qBAAqB,CAAA;YAC1D,IAAI,CAAC,EAAE,GAAG,OAAO,GAAG,UAAU,GAAG,CAAC,CAAA;YAClC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,qBAAqB,CAAA;YACzC,EAAE,GAAG,OAAO,GAAG,WAAW,GAAG,CAAC,GAAG,UAAU,GAAG,CAAC,CAAA;AAChD,SAAA;KACF;AAEO,IAAA,gBAAgB,CAAE,CAAe,EAAA;AACvC,QAAA,IAAI,OAAyB,CAAA;QAC7B,IAAI,CAAC,CAAC,QAAQ,EAAE;AACd,YAAA,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAwB,CAAA;YAC/C,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAC5B,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAC5F,CAAA;AACF,SAAA;AAAM,aAAA;YACL,MAAM,IAAI,GAAG,CAAqB,CAAA;AAClC,YAAA,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC1G,SAAA;AACD,QAAA,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAA;KAChC;IAEO,eAAe,GAAA;QACrB,IAAI,CAAC,iBAAiB,EAAE,CAAA;KACzB;AAEO,IAAA,gBAAgB,CAAE,CAAiB,EAAA;AACzC,QAAA,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAC5B;IAEO,eAAe,GAAA;QACrB,IAAI,CAAC,iBAAiB,EAAE,CAAA;KACzB;AAEO,IAAA,iBAAiB,CAAE,KAAwB,EAAA;QACjD,IAAI,IAAI,CAAC,eAAe;YAAE,OAAM;AAChC,QAAA,IAAI,KAAK,EAAE;AACT,YAAA,KAAK,CAAC,OAAO,CAAC,CAAC,IAAG;AAChB,gBAAA,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;AACvB,gBAAA,MAAM,UAAU,GAAI,CAAC,CAAC,MAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;AAClE,gBAAA,MAAM,UAAU,GAAI,CAAC,CAAC,MAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;gBAClE,UAAU,CAAC,OAAO,CAAC,CAAC,IAAM,EAAA,IAAI,CAAC,CAAC,KAAK;oBAAE,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA,EAAE,CAAC,CAAA;gBACjE,UAAU,CAAC,OAAO,CAAC,CAAC,IAAM,EAAA,IAAI,CAAC,CAAC,KAAK;oBAAE,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA,EAAE,CAAC,CAAA;AACnE,aAAC,CAAC,CAAA;AACH,SAAA;AAAM,aAAA;AACL,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAG,EAAG,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAA,EAAE,CAAC,CAAA;AACrD,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAG,EAAG,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAA,EAAE,CAAC,CAAA;AACtD,SAAA;QAED,IAAI,CAAC,SAAS,CAAC,SAAS,CAA+B,IAAIH,IAAM,CAAA,CAAE,CAAC;AACjE,aAAA,OAAO,CAACC,eAAiB,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACpD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAiC,IAAIH,IAAM,CAAA,CAAE,CAAC;AACnE,aAAA,OAAO,CAACC,eAAiB,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AAEpD,QAAA,IAAI,CAAC,CAAC,CAAC,OAAO,CAACF,WAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAA;KACvC;;AA7VM,YAAS,CAAA,SAAA,GAAGO,KAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/components/chord-diagram/index.ts"],"sourcesContent":["import { max } from 'd3-array'\nimport { partition } from 'd3-hierarchy'\nimport { Selection } from 'd3-selection'\nimport { scalePow, ScalePower } from 'd3-scale'\nimport { arc } from 'd3-shape'\n\n// Core\nimport { ComponentCore } from 'core/component'\nimport { GraphData, GraphDataModel } from 'data-models/graph'\n\n// Utils\nimport { getNumber, isNumber, getString, getValue } from 'utils/data'\nimport { estimateStringPixelLength } from 'utils/text'\n\n// Types\nimport { Spacing } from 'types/spacing'\n\n// Local Types\nimport { ChordInputNode, ChordInputLink, ChordDiagramData, ChordNode, ChordRibbon, ChordLabelAlignment, ChordLeafNode } from './types'\n\n// Config\nimport { ChordDiagramDefaultConfig, ChordDiagramConfigInterface } from './config'\n\n// Modules\nimport { createNode, updateNode, removeNode } from './modules/node'\nimport { createLabel, updateLabel, removeLabel, LABEL_PADDING } from './modules/label'\nimport { getHierarchyNodes, getRibbons, positionChildren } from './modules/layout'\nimport { createLink, updateLink, removeLink } from './modules/link'\n\n// Styles\nimport * as s from './style'\n\nexport class ChordDiagram<\n N extends ChordInputNode,\n L extends ChordInputLink,\n> extends ComponentCore<\n ChordDiagramData<N, L>,\n ChordDiagramConfigInterface<N, L>\n > {\n static selectors = s\n protected _defaultConfig = ChordDiagramDefaultConfig as ChordDiagramConfigInterface<N, L>\n public config: ChordDiagramConfigInterface<N, L> = this._defaultConfig\n datamodel: GraphDataModel<N, L> = new GraphDataModel()\n\n background: Selection<SVGRectElement, unknown, SVGGElement, unknown>\n nodeGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>\n linkGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>\n labelGroup: Selection<SVGGElement, unknown, SVGGElement, unknown>\n\n arcGen = arc<ChordNode<N>>()\n radiusScale: ScalePower<number, number> = scalePow()\n\n private _nodes: ChordNode<N>[] = []\n private _links: ChordRibbon<N>[] = []\n private _rootNode: ChordNode<N>\n\n events = {\n [ChordDiagram.selectors.node]: {\n mouseover: this._onNodeMouseOver.bind(this),\n mouseout: this._onNodeMouseOut.bind(this),\n },\n [ChordDiagram.selectors.link]: {\n mouseover: this._onLinkMouseOver.bind(this),\n mouseout: this._onLinkMouseOut.bind(this),\n },\n [ChordDiagram.selectors.label]: {\n mouseover: this._onNodeMouseOver.bind(this),\n mouseout: this._onNodeMouseOut.bind(this),\n },\n }\n\n private get _forceHighlight (): boolean {\n return this.config.highlightedNodeId !== undefined || this.config.highlightedLinkIds?.length > 0\n }\n\n constructor (config?: ChordDiagramConfigInterface<N, L>) {\n super()\n if (config) this.setConfig(config)\n this.background = this.g.append('rect').attr('class', s.background)\n this.linkGroup = this.g.append('g').attr('class', s.links)\n this.nodeGroup = this.g.append('g').attr('class', s.nodes)\n this.labelGroup = this.g.append('g').attr('class', s.labels)\n }\n\n get bleed (): Spacing {\n const { config } = this\n const padding = 4 + LABEL_PADDING * 2\n let top = 0; let bottom = 0; let right = 0; let left = 0\n this._nodes.forEach(n => {\n const nodeLabelAlignment = getValue(n.data, config.nodeLabelAlignment)\n if (n.height === 0 && nodeLabelAlignment === ChordLabelAlignment.Perpendicular) {\n const labelWidth = estimateStringPixelLength(getString(n.data as N, config.nodeLabel) ?? '', 16)\n const [x, y] = this.arcGen.centroid(n)\n\n if (x < 0) left = Math.max(left, labelWidth)\n else right = Math.max(right, labelWidth)\n\n if (y < 0) top = Math.max(top, labelWidth)\n else bottom = Math.max(bottom, labelWidth)\n }\n })\n left += padding\n right += padding\n bottom += padding\n top += padding\n return { top, bottom, left, right }\n }\n\n setSize (width: number, height: number, containerWidth: number, containerHeight: number): void {\n super.setSize(width, height, containerWidth, containerHeight)\n\n // Setting radius for initial bleed calculation. This ensures the correct radius is set when render is called\n this.radiusScale\n .exponent(this.config.radiusScaleExponent)\n .range([0, Math.min(width, height) / 2])\n }\n\n setData (data: GraphData<N, L>): void {\n super.setData(data)\n this._layoutData()\n }\n\n _layoutData (): void {\n const { nodes, links } = this.datamodel\n const { padAngle, linkValue, nodeLevels } = this.config\n nodes.forEach(n => { delete n._state.value })\n links.forEach(l => {\n delete l._state.points\n l._state.value = getNumber(l, linkValue)\n l.source._state.value = (l.source._state.value || 0) + getNumber(l, linkValue)\n l.target._state.value = (l.target._state.value || 0) + getNumber(l, linkValue)\n })\n\n const root = getHierarchyNodes(nodes, d => d._state?.value, nodeLevels)\n\n const partitionData = partition().size([this.config.angleRange[1], 1])(root) as ChordNode<N>\n partitionData.each((n, i) => {\n positionChildren(n, padAngle)\n n.uid = `${this.uid.substr(0, 4)}-${i}`\n n.x0 = Number.isNaN(n.x0) ? 0 : n.x0\n n.x1 = Number.isNaN(n.x1) ? 0 : n.x1\n n._state = {}\n })\n\n const partitionDataWithRoot = partitionData.descendants()\n this._rootNode = partitionDataWithRoot.find(d => d.depth === 0)\n this._nodes = partitionDataWithRoot.filter(d => d.depth !== 0) // Filter out the root node\n this._links = getRibbons<N>(partitionData, links, padAngle)\n }\n\n _render (customDuration?: number): void {\n super._render(customDuration)\n const { config, bleed } = this\n\n this._layoutData()\n const duration = isNumber(customDuration) ? customDuration : config.duration\n const size = Math.min(this._width, this._height)\n const radius = size / 2 - max([bleed.top, bleed.bottom, bleed.left, bleed.right])\n\n this.radiusScale.range([0, radius - config.nodeWidth])\n\n this.arcGen\n .startAngle(d => d.x0 + config.padAngle / 2 - (d.value ? 0 : Math.PI / 360))\n .endAngle(d => d.x1 - config.padAngle / 2 + (d.value ? 0 : Math.PI / 360))\n .cornerRadius(d => getNumber(d.data, config.cornerRadius))\n .innerRadius(d => this.radiusScale(d.y1))\n .outerRadius(d => this.radiusScale(d.y1) + -getNumber(d, config.nodeWidth))\n\n this.g.classed(s.transparent, this._forceHighlight)\n this.background\n .attr('width', this._width)\n .attr('height', this._height)\n .style('opacity', 0)\n\n // Center the view\n this.nodeGroup.attr('transform', `translate(${this._width / 2},${this._height / 2})`)\n this.labelGroup.attr('transform', `translate(${this._width / 2},${this._height / 2})`)\n this.linkGroup.attr('transform', `translate(${this._width / 2},${this._height / 2})`)\n\n // Links\n const linksSelection = this.linkGroup\n .selectAll<SVGPathElement, ChordRibbon<N>>(`.${s.link}`)\n .data(this._links, d => String(d.data._id))\n .classed(s.highlightedLink, l => {\n const linkId = l.data.id ?? l.data._indexGlobal\n return config.highlightedLinkIds?.includes(linkId)\n })\n\n const linksEnter = linksSelection.enter().append('path')\n .attr('class', s.link)\n .call(createLink, this.radiusScale)\n\n const linksMerged = linksSelection.merge(linksEnter)\n linksMerged.call(updateLink, config, this.radiusScale, duration)\n\n linksSelection.exit()\n .call(removeLink, duration)\n\n // Nodes\n const nodesSelection = this.nodeGroup\n .selectAll<SVGPathElement, ChordNode<N>>(`.${s.node}`)\n .data(this._nodes, d => String(d.uid))\n .classed(s.highlightedNode, d => config.highlightedNodeId === d.data._id)\n\n const nodesEnter = nodesSelection.enter().append('path')\n .attr('class', s.node)\n .call(createNode, config)\n\n const nodesMerged = nodesSelection.merge(nodesEnter)\n nodesMerged.call(updateNode, config, this.arcGen, duration, this.bleed)\n\n nodesSelection.exit()\n .call(removeNode, duration)\n\n // Labels\n const labelWidth = size - radius - config.nodeWidth\n const labels = this.labelGroup\n .selectAll<SVGGElement, ChordNode<N>>(`.${s.label}`)\n .data(this._nodes, d => String(d.uid))\n\n const labelEnter = labels.enter().append('g')\n .attr('class', s.label)\n .call(createLabel, config, this.radiusScale)\n\n const labelsMerged = labels.merge(labelEnter)\n labelsMerged.call(updateLabel, config, labelWidth, this.radiusScale, duration)\n\n labels.exit()\n .attr('class', s.labelExit)\n .call(removeLabel, duration)\n }\n\n private _onNodeMouseOver (d: ChordNode<N>): void {\n let ribbons: ChordRibbon<N>[]\n if (d.children) {\n const leaves = d.leaves() as ChordLeafNode<N>[]\n ribbons = this._links.filter(l =>\n leaves.find(leaf => l.source.data.id === leaf.data.id || l.target.data.id === leaf.data.id)\n )\n } else {\n const leaf = d as ChordLeafNode<N>\n ribbons = this._links.filter(l => l.source.data.id === leaf.data.id || l.target.data.id === leaf.data.id)\n }\n\n // Nodes without links should still be highlighted\n if (!ribbons.length) d._state.hovered = true\n this._highlightOnHover(ribbons)\n }\n\n private _onNodeMouseOut (): void {\n this._highlightOnHover()\n }\n\n private _onLinkMouseOver (d: ChordRibbon<N>): void {\n this._highlightOnHover([d])\n }\n\n private _onLinkMouseOut (): void {\n this._highlightOnHover()\n }\n\n private _highlightOnHover (links?: ChordRibbon<N>[]): void {\n if (this._forceHighlight) return\n if (links) {\n links.forEach(l => {\n l._state.hovered = true\n const sourcePath = (l.source as ChordNode<N>).path(this._rootNode)\n const targetPath = (l.target as ChordNode<N>).path(this._rootNode)\n sourcePath.forEach(n => { if (n.depth) n._state.hovered = true })\n targetPath.forEach(n => { if (n.depth) n._state.hovered = true })\n })\n } else {\n this._nodes.forEach(n => { delete n._state.hovered })\n this._links.forEach(l => { delete l._state.hovered })\n }\n\n this.nodeGroup.selectAll<SVGPathElement, ChordNode<N>>(`.${s.node}`)\n .classed(s.highlightedNode, d => d._state.hovered)\n this.linkGroup.selectAll<SVGPathElement, ChordRibbon<N>>(`.${s.link}`)\n .classed(s.highlightedLink, d => d._state.hovered)\n\n this.g.classed(s.transparent, !!links)\n }\n}\n"],"names":["s.background","s.links","s.nodes","s.labels","s.transparent","s.link","s.highlightedLink","s.node","s.highlightedNode","s.label","s.labelExit","s"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { HierarchyNode } from 'd3-hierarchy';
|
|
2
|
+
import { NumericAccessor } from "../../../types/accessor";
|
|
3
|
+
import { ChordNode, ChordRibbon, ChordLinkDatum, ChordHierarchyNode } from '../types';
|
|
4
|
+
export declare function getHierarchyNodes<N>(data: N[], value: NumericAccessor<N>, levels?: (keyof N)[]): HierarchyNode<ChordHierarchyNode<N>>;
|
|
5
|
+
export declare function positionChildren<N>(node: ChordNode<N>, padding: number, scalingCoeff?: number): void;
|
|
6
|
+
export declare function getRibbons<N>(data: ChordNode<N>, links: ChordLinkDatum<N>[], padding: number): ChordRibbon<N>[];
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { hierarchy } from 'd3-hierarchy';
|
|
2
|
+
import { pie } from 'd3-shape';
|
|
3
|
+
import { group, index } from 'd3-array';
|
|
4
|
+
import { getNumber, groupBy } from '../../../utils/data.js';
|
|
5
|
+
|
|
6
|
+
function transformData(node) {
|
|
7
|
+
const { height, depth } = node;
|
|
8
|
+
if (height > 0) {
|
|
9
|
+
const d = node.data;
|
|
10
|
+
const n = node;
|
|
11
|
+
n.data = { key: d[0], values: d[1], depth, height, ancestors: n.ancestors().map(d => d.data.key) };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function getHierarchyNodes(data, value, levels = []) {
|
|
15
|
+
const nodeLevels = levels.map(level => (d) => d[level]);
|
|
16
|
+
const nestedData = levels.length ? group(data, ...nodeLevels) : { key: 'root', children: data };
|
|
17
|
+
const root = hierarchy(nestedData)
|
|
18
|
+
.sum(d => getNumber(d, value))
|
|
19
|
+
.each(transformData);
|
|
20
|
+
return root;
|
|
21
|
+
}
|
|
22
|
+
function positionChildren(node, padding, scalingCoeff = 0.95) {
|
|
23
|
+
if (!node.children)
|
|
24
|
+
return;
|
|
25
|
+
const length = node.x1 - node.x0;
|
|
26
|
+
const scaledLength = length * (node.depth === 0 ? 1 : scalingCoeff);
|
|
27
|
+
const delta = length - scaledLength;
|
|
28
|
+
const positions = pie()
|
|
29
|
+
.startAngle(node.x0 + delta / 2)
|
|
30
|
+
.endAngle(node.x1 - delta / 2)
|
|
31
|
+
.padAngle(padding)
|
|
32
|
+
.value(d => d.value)
|
|
33
|
+
.sort((a, b) => node.children.indexOf(a) - node.children.indexOf(b))(node.children);
|
|
34
|
+
node.children.forEach((child, i) => {
|
|
35
|
+
child.x0 = positions[i].startAngle;
|
|
36
|
+
child.x1 = positions[i].endAngle;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function getRibbons(data, links, padding) {
|
|
40
|
+
const groupedBySource = groupBy(links, d => d.source._id);
|
|
41
|
+
const groupedByTarget = groupBy(links, d => d.target._id);
|
|
42
|
+
const leafNodes = data.leaves();
|
|
43
|
+
const leafNodesById = index(leafNodes, d => d.data._id);
|
|
44
|
+
const getNodesInRibbon = (source, target, partitionHeight, nodes = []) => {
|
|
45
|
+
nodes[source.height] = source;
|
|
46
|
+
nodes[partitionHeight * 2 - target.height] = target;
|
|
47
|
+
if (source.parent && target.parent)
|
|
48
|
+
getNodesInRibbon(source.parent, target.parent, partitionHeight, nodes);
|
|
49
|
+
return nodes;
|
|
50
|
+
};
|
|
51
|
+
const calculatePoints = (links, type, depth, maxDepth) => {
|
|
52
|
+
links.forEach(link => {
|
|
53
|
+
var _a;
|
|
54
|
+
if (!link._state.points)
|
|
55
|
+
link._state.points = [];
|
|
56
|
+
const sourceLeaf = leafNodesById.get(link.source._id);
|
|
57
|
+
const targetLeaf = leafNodesById.get(link.target._id);
|
|
58
|
+
const nodesInRibbon = getNodesInRibbon(type === 'out' ? sourceLeaf : targetLeaf, type === 'out' ? targetLeaf : sourceLeaf, maxDepth);
|
|
59
|
+
const currNode = nodesInRibbon[depth];
|
|
60
|
+
const len = currNode.x1 - currNode.x0 - padding;
|
|
61
|
+
const x0 = (_a = currNode._prevX1) !== null && _a !== void 0 ? _a : (currNode.x0 + padding / 2);
|
|
62
|
+
const x1 = x0 + len * link._state.value / currNode.value;
|
|
63
|
+
currNode._prevX1 = x1;
|
|
64
|
+
const pointIdx = type === 'out' ? depth : maxDepth * 2 - 1 - depth;
|
|
65
|
+
link._state.points[pointIdx] = { a0: x0, a1: x1, r: currNode.y1 };
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
leafNodes.forEach(leafNode => {
|
|
69
|
+
const outLinks = groupedBySource[leafNode.data._id] || [];
|
|
70
|
+
const inLinks = groupedByTarget[leafNode.data._id] || [];
|
|
71
|
+
for (let depth = 0; depth < leafNode.depth; depth += 1) {
|
|
72
|
+
calculatePoints(outLinks, 'out', depth, leafNode.depth);
|
|
73
|
+
calculatePoints(inLinks, 'in', depth, leafNode.depth);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return links.map(l => ({
|
|
77
|
+
source: leafNodesById.get(l.source._id),
|
|
78
|
+
target: leafNodesById.get(l.target._id),
|
|
79
|
+
data: l,
|
|
80
|
+
points: l._state.points,
|
|
81
|
+
_state: {},
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { getHierarchyNodes, getRibbons, positionChildren };
|
|
86
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sources":["../../../../src/components/chord-diagram/modules/layout.ts"],"sourcesContent":["import { HierarchyNode, hierarchy } from 'd3-hierarchy'\nimport { pie } from 'd3-shape'\nimport { group, index } from 'd3-array'\n\n// Utils\nimport { getNumber, groupBy } from 'utils/data'\n\n// Types\nimport { NumericAccessor } from 'types/accessor'\n\n// Local Types\nimport { ChordNode, ChordRibbon, ChordLinkDatum, ChordHierarchyNode, ChordLeafNode } from '../types'\n\nfunction transformData <T> (node: HierarchyNode<T>): void {\n const { height, depth } = node\n if (height > 0) {\n const d = node.data as unknown as [string, T[]]\n const n = node as unknown as HierarchyNode<ChordHierarchyNode<T>>\n n.data = { key: d[0], values: d[1], depth, height, ancestors: n.ancestors().map(d => d.data.key) }\n }\n}\n\nexport function getHierarchyNodes<N> (\n data: N[],\n value: NumericAccessor<N>,\n levels: (keyof N)[] = []\n): HierarchyNode<ChordHierarchyNode<N>> {\n const nodeLevels = levels.map(level => (d: N) => d[level]) as unknown as [(d: N) => string]\n const nestedData = levels.length ? group<N, string>(data, ...nodeLevels) : { key: 'root', children: data }\n\n const root = hierarchy(nestedData)\n .sum(d => getNumber(d as unknown as N, value))\n .each(transformData)\n\n return root as unknown as HierarchyNode<ChordHierarchyNode<N>>\n}\n\nexport function positionChildren<N> (node: ChordNode<N>, padding: number, scalingCoeff = 0.95): void {\n if (!node.children) return\n\n const length = node.x1 - node.x0\n const scaledLength = length * (node.depth === 0 ? 1 : scalingCoeff)\n const delta = length - scaledLength\n\n const positions = pie<ChordNode<N>>()\n .startAngle(node.x0 + delta / 2)\n .endAngle(node.x1 - delta / 2)\n .padAngle(padding)\n .value(d => d.value)\n .sort((a, b) => node.children.indexOf(a) - node.children.indexOf(b))(node.children)\n\n node.children.forEach((child, i) => {\n child.x0 = positions[i].startAngle\n child.x1 = positions[i].endAngle\n })\n}\n\nexport function getRibbons<N> (data: ChordNode<N>, links: ChordLinkDatum<N>[], padding: number): ChordRibbon<N>[] {\n type LinksArrayType = typeof links\n const groupedBySource: Record<string, LinksArrayType> = groupBy(links, d => d.source._id)\n const groupedByTarget: Record<string, LinksArrayType> = groupBy(links, d => d.target._id)\n\n const leafNodes = data.leaves() as ChordLeafNode<N>[]\n const leafNodesById: Map<string, ChordLeafNode<N>> = index(leafNodes, d => d.data._id)\n\n const getNodesInRibbon = (\n source: ChordLeafNode<N>,\n target: ChordLeafNode<N>,\n partitionHeight: number,\n nodes: ChordNode<N>[] = []\n ): ChordNode<N>[] => {\n nodes[source.height] = source\n nodes[partitionHeight * 2 - target.height] = target\n if (source.parent && target.parent) getNodesInRibbon(source.parent, target.parent, partitionHeight, nodes)\n return nodes\n }\n const calculatePoints = (links: LinksArrayType, type: 'in' | 'out', depth: number, maxDepth: number): void => {\n links.forEach(link => {\n if (!link._state.points) link._state.points = []\n\n const sourceLeaf = leafNodesById.get(link.source._id)\n const targetLeaf = leafNodesById.get(link.target._id)\n const nodesInRibbon = getNodesInRibbon(\n type === 'out' ? sourceLeaf : targetLeaf,\n type === 'out' ? targetLeaf : sourceLeaf,\n maxDepth\n )\n const currNode = nodesInRibbon[depth]\n const len = currNode.x1 - currNode.x0 - padding\n const x0 = currNode._prevX1 ?? (currNode.x0 + padding / 2)\n const x1 = x0 + len * link._state.value / currNode.value\n currNode._prevX1 = x1\n\n const pointIdx = type === 'out' ? depth : maxDepth * 2 - 1 - depth\n link._state.points[pointIdx] = { a0: x0, a1: x1, r: currNode.y1 }\n })\n }\n\n leafNodes.forEach(leafNode => {\n const outLinks = groupedBySource[leafNode.data._id] || []\n const inLinks = groupedByTarget[leafNode.data._id] || []\n for (let depth = 0; depth < leafNode.depth; depth += 1) {\n calculatePoints(outLinks, 'out', depth, leafNode.depth)\n calculatePoints(inLinks, 'in', depth, leafNode.depth)\n }\n })\n\n return links.map(l => ({\n source: leafNodesById.get(l.source._id),\n target: leafNodesById.get(l.target._id),\n data: l,\n points: l._state.points,\n _state: {},\n }))\n}\n"],"names":[],"mappings":";;;;;AAaA,SAAS,aAAa,CAAM,IAAsB,EAAA;AAChD,IAAA,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;IAC9B,IAAI,MAAM,GAAG,CAAC,EAAE;AACd,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,IAAgC,CAAA;QAC/C,MAAM,CAAC,GAAG,IAAuD,CAAA;AACjE,QAAA,CAAC,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;AACnG,KAAA;AACH,CAAC;AAEK,SAAU,iBAAiB,CAC/B,IAAS,EACT,KAAyB,EACzB,SAAsB,EAAE,EAAA;IAExB,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAI,KAAK,CAAC,CAAC,KAAK,CAAC,CAAkC,CAAA;IAC3F,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,CAAY,IAAI,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;AAE1G,IAAA,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC;SAC/B,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC,CAAiB,EAAE,KAAK,CAAC,CAAC;SAC7C,IAAI,CAAC,aAAa,CAAC,CAAA;AAEtB,IAAA,OAAO,IAAuD,CAAA;AAChE,CAAC;AAEK,SAAU,gBAAgB,CAAK,IAAkB,EAAE,OAAe,EAAE,YAAY,GAAG,IAAI,EAAA;IAC3F,IAAI,CAAC,IAAI,CAAC,QAAQ;QAAE,OAAM;IAE1B,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAA;AAChC,IAAA,MAAM,YAAY,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,CAAA;AACnE,IAAA,MAAM,KAAK,GAAG,MAAM,GAAG,YAAY,CAAA;IAEnC,MAAM,SAAS,GAAG,GAAG,EAAgB;SAClC,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;SAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;SAC7B,QAAQ,CAAC,OAAO,CAAC;SACjB,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;AACnB,SAAA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAErF,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,KAAI;QACjC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAA;QAClC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;AAClC,KAAC,CAAC,CAAA;AACJ,CAAC;SAEe,UAAU,CAAK,IAAkB,EAAE,KAA0B,EAAE,OAAe,EAAA;AAE5F,IAAA,MAAM,eAAe,GAAmC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACzF,IAAA,MAAM,eAAe,GAAmC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AAEzF,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAwB,CAAA;AACrD,IAAA,MAAM,aAAa,GAAkC,KAAK,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAEtF,IAAA,MAAM,gBAAgB,GAAG,CACvB,MAAwB,EACxB,MAAwB,EACxB,eAAuB,EACvB,KAAA,GAAwB,EAAE,KACR;AAClB,QAAA,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;QAC7B,KAAK,CAAC,eAAe,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;AACnD,QAAA,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;AAAE,YAAA,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,CAAA;AAC1G,QAAA,OAAO,KAAK,CAAA;AACd,KAAC,CAAA;IACD,MAAM,eAAe,GAAG,CAAC,KAAqB,EAAE,IAAkB,EAAE,KAAa,EAAE,QAAgB,KAAU;AAC3G,QAAA,KAAK,CAAC,OAAO,CAAC,IAAI,IAAG;;AACnB,YAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;AAAE,gBAAA,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAA;AAEhD,YAAA,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACrD,YAAA,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AACrD,YAAA,MAAM,aAAa,GAAG,gBAAgB,CACpC,IAAI,KAAK,KAAK,GAAG,UAAU,GAAG,UAAU,EACxC,IAAI,KAAK,KAAK,GAAG,UAAU,GAAG,UAAU,EACxC,QAAQ,CACT,CAAA;AACD,YAAA,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;YACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,EAAE,GAAG,OAAO,CAAA;AAC/C,YAAA,MAAM,EAAE,GAAG,CAAA,EAAA,GAAA,QAAQ,CAAC,OAAO,MAAI,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,IAAC,QAAQ,CAAC,EAAE,GAAG,OAAO,GAAG,CAAC,CAAC,CAAA;AAC1D,YAAA,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAA;AACxD,YAAA,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAA;AAErB,YAAA,MAAM,QAAQ,GAAG,IAAI,KAAK,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;YAClE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAA;AACnE,SAAC,CAAC,CAAA;AACJ,KAAC,CAAA;AAED,IAAA,SAAS,CAAC,OAAO,CAAC,QAAQ,IAAG;AAC3B,QAAA,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;AACzD,QAAA,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;AACxD,QAAA,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE;YACtD,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;YACvD,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;AACtD,SAAA;AACH,KAAC,CAAC,CAAA;IAEF,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK;QACrB,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QACvC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;AACvC,QAAA,IAAI,EAAE,CAAC;AACP,QAAA,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;AACvB,QAAA,MAAM,EAAE,EAAE;AACX,KAAA,CAAC,CAAC,CAAA;AACL;;;;"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { select } from 'd3-selection';
|
|
2
2
|
import { ribbon } from 'd3-chord';
|
|
3
|
-
import { path } from 'd3-path';
|
|
4
3
|
import { areaRadial } from 'd3-shape';
|
|
5
4
|
import { interpolatePath } from 'd3-interpolate-path';
|
|
6
5
|
import { Curve } from '../../../types/curve.js';
|
|
@@ -24,18 +23,18 @@ const areaGen = areaRadial()
|
|
|
24
23
|
.endAngle((d, i, points) => i < points.length / 2 ? d.a0 : d.a1);
|
|
25
24
|
// Creates a path from set of points
|
|
26
25
|
function linkGen(points, radiusScale) {
|
|
26
|
+
var _a;
|
|
27
27
|
const link = (points.length === 2 ? ribbonGen : areaGen);
|
|
28
28
|
link.radius(d => radiusScale(d.r));
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return convertLineToArc(p, radius);
|
|
29
|
+
const linkPath = link(points);
|
|
30
|
+
if (points.length === 2)
|
|
31
|
+
return linkPath;
|
|
32
|
+
// Replace closePath with line to starting point
|
|
33
|
+
const area = linkPath.slice(0, -1);
|
|
34
|
+
const path = area.concat(`L${(_a = area.match(/M-?\d*\.?\d*[,\s*]-?\d*\.?\d*/)) === null || _a === void 0 ? void 0 : _a[0].slice(1)}`);
|
|
35
|
+
// Convert line edges to arcs
|
|
36
|
+
const radius = Math.max(radiusScale(points[0].r), 0);
|
|
37
|
+
return convertLineToArc(path, radius);
|
|
39
38
|
}
|
|
40
39
|
function createLink(selection, radiusScale) {
|
|
41
40
|
selection
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.js","sources":["../../../../src/components/chord-diagram/modules/link.ts"],"sourcesContent":["import { Selection, select } from 'd3-selection'\nimport { ribbon } from 'd3-chord'\nimport {
|
|
1
|
+
{"version":3,"file":"link.js","sources":["../../../../src/components/chord-diagram/modules/link.ts"],"sourcesContent":["import { Selection, select } from 'd3-selection'\nimport { ribbon } from 'd3-chord'\nimport { ScalePower } from 'd3-scale'\nimport { areaRadial } from 'd3-shape'\nimport { Transition } from 'd3-transition'\nimport { interpolatePath } from 'd3-interpolate-path'\n\n// Types\nimport { Curve } from 'types/curve'\n\n// Utils\nimport { getColor } from 'utils/color'\nimport { smartTransition } from 'utils/d3'\nimport { convertLineToArc } from 'utils/path'\n\n// Local Types\nimport { ChordInputLink, ChordInputNode, ChordRibbon, ChordRibbonPoint } from '../types'\nimport { ChordDiagramConfigInterface } from '../config'\n\n// Generators\nexport function emptyPath (): string {\n return 'M0,0 L0,0'\n}\n\n// Generators\nconst ribbonGen = ribbon<ChordRibbonPoint[], ChordRibbonPoint>()\n .source(d => d[0])\n .target(d => d[d.length - 1])\n .startAngle(d => d.a0)\n .endAngle(d => d.a1)\n\nconst areaGen = areaRadial<ChordRibbonPoint>()\n .curve(Curve.catmullRom.alpha(0.5))\n .startAngle((d, i, points) => i < points.length / 2 ? d.a1 : d.a0)\n .endAngle((d, i, points) => i < points.length / 2 ? d.a0 : d.a1)\n\n\n// Creates a path from set of points\nfunction linkGen (points: ChordRibbonPoint[], radiusScale: ScalePower<number, number>): string {\n const link = (points.length === 2 ? ribbonGen : areaGen)\n link.radius(d => radiusScale(d.r))\n\n const linkPath = link(points) as string\n\n if (points.length === 2) return linkPath\n\n // Replace closePath with line to starting point\n const area = linkPath.slice(0, -1)\n const path = area.concat(`L${area.match(/M-?\\d*\\.?\\d*[,\\s*]-?\\d*\\.?\\d*/)?.[0].slice(1)}`)\n\n // Convert line edges to arcs\n const radius = Math.max(radiusScale(points[0].r), 0)\n return convertLineToArc(path, radius)\n}\n\nexport function createLink<N extends ChordInputNode> (\n selection: Selection<SVGPathElement, ChordRibbon<N>, SVGGElement, unknown>,\n radiusScale: ScalePower<number, number>\n): void {\n selection\n .attr('d', d => linkGen(d.points, radiusScale) || emptyPath())\n .style('opacity', 0)\n}\n\nexport function updateLink<N extends ChordInputNode, L extends ChordInputLink> (\n selection: Selection<SVGPathElement, ChordRibbon<N, L>, SVGGElement, unknown>,\n config: ChordDiagramConfigInterface<N, L>,\n radiusScale: ScalePower<number, number>,\n duration: number\n): void {\n selection\n .style('transition', `fill-opacity: ${duration}ms`)\n .style('fill', d => getColor(d.data, config.linkColor))\n .style('stroke', d => getColor(d.data, config.linkColor))\n\n const transition = smartTransition(selection, duration)\n .style('opacity', 1) as Transition<SVGPathElement, ChordRibbon<N, L>, SVGGElement, unknown>\n\n if (duration) {\n transition.attrTween('d', (d, i, el) => {\n const previous = select(el[i]).attr('d')\n const next = linkGen(d.points, radiusScale) || emptyPath()\n return interpolatePath(previous, next)\n })\n } else {\n transition.attr('d', d => linkGen(d.points, radiusScale) || emptyPath())\n }\n}\n\nexport function removeLink (\n selection: Selection<SVGPathElement, unknown, SVGGElement, unknown>,\n duration: number\n): void {\n smartTransition(selection, duration)\n .style('opacity', 0)\n .remove()\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ function createNode(selection) {
|
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
function updateNode(selection, config, arcGen, duration) {
|
|
21
|
-
const nodeColor = (d) => getColor(d.data, config.nodeColor
|
|
21
|
+
const nodeColor = (d) => getColor(d.data, config.nodeColor);
|
|
22
22
|
selection
|
|
23
23
|
.attr('id', d => d.uid)
|
|
24
24
|
.style('transition', `fill ${duration}ms`) // Animate color with CSS because we're using CSS-variables
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sources":["../../../../src/components/chord-diagram/modules/node.ts"],"sourcesContent":["import { Selection } from 'd3-selection'\nimport { Transition } from 'd3-transition'\nimport { interpolate } from 'd3-interpolate'\nimport { Arc } from 'd3-shape'\n\n// Utils\nimport { getColor } from 'utils/color'\nimport { smartTransition } from 'utils/d3'\n\n// Local Types\nimport { ChordInputNode, ChordInputLink, ChordNode } from '../types'\n\n// Config\nimport { ChordDiagramConfigInterface } from '../config'\n\ntype AnimState = { x0: number; x1: number; y0: number; y1: number }\nexport interface ArcNode extends SVGElement {\n _animState?: AnimState;\n}\n\nexport function createNode<N extends ChordInputNode, L extends ChordInputLink> (\n selection: Selection<SVGPathElement, ChordNode<N>, SVGGElement, unknown>\n): void {\n selection\n .style('opacity', 0)\n .each((d, i, els) => {\n const arcNode: ArcNode = els[i]\n const angleCenter = (d.x0 + d.x1) / 2\n const angleHalfWidth = (d.x1 - d.x0) / 2\n arcNode._animState = {\n x0: angleCenter - angleHalfWidth * 0.8,\n x1: angleCenter + angleHalfWidth * 0.8,\n y0: d.y0,\n y1: d.y1,\n }\n })\n}\n\nexport function updateNode<N extends ChordInputNode, L extends ChordInputLink> (\n selection: Selection<SVGPathElement, ChordNode<N>, SVGGElement, unknown>,\n config: ChordDiagramConfigInterface<N, L>,\n arcGen: Arc<unknown, AnimState>,\n duration: number\n): void {\n const nodeColor = (d: ChordNode<N>): string => getColor(d.data, config.nodeColor
|
|
1
|
+
{"version":3,"file":"node.js","sources":["../../../../src/components/chord-diagram/modules/node.ts"],"sourcesContent":["import { Selection } from 'd3-selection'\nimport { Transition } from 'd3-transition'\nimport { interpolate } from 'd3-interpolate'\nimport { Arc } from 'd3-shape'\n\n// Utils\nimport { getColor } from 'utils/color'\nimport { smartTransition } from 'utils/d3'\n\n// Local Types\nimport { ChordInputNode, ChordInputLink, ChordNode } from '../types'\n\n// Config\nimport { ChordDiagramConfigInterface } from '../config'\n\ntype AnimState = { x0: number; x1: number; y0: number; y1: number }\nexport interface ArcNode extends SVGElement {\n _animState?: AnimState;\n}\n\nexport function createNode<N extends ChordInputNode, L extends ChordInputLink> (\n selection: Selection<SVGPathElement, ChordNode<N>, SVGGElement, unknown>\n): void {\n selection\n .style('opacity', 0)\n .each((d, i, els) => {\n const arcNode: ArcNode = els[i]\n const angleCenter = (d.x0 + d.x1) / 2\n const angleHalfWidth = (d.x1 - d.x0) / 2\n arcNode._animState = {\n x0: angleCenter - angleHalfWidth * 0.8,\n x1: angleCenter + angleHalfWidth * 0.8,\n y0: d.y0,\n y1: d.y1,\n }\n })\n}\n\nexport function updateNode<N extends ChordInputNode, L extends ChordInputLink> (\n selection: Selection<SVGPathElement, ChordNode<N>, SVGGElement, unknown>,\n config: ChordDiagramConfigInterface<N, L>,\n arcGen: Arc<unknown, AnimState>,\n duration: number\n): void {\n const nodeColor = (d: ChordNode<N>): string => getColor(d.data, config.nodeColor)\n\n selection\n .attr('id', d => d.uid)\n .style('transition', `fill ${duration}ms`) // Animate color with CSS because we're using CSS-variables\n .style('fill', nodeColor)\n .style('stroke', nodeColor)\n\n if (duration) {\n const transition = smartTransition(selection, duration)\n .style('opacity', 1) as Transition<SVGPathElement, ChordNode<N>, SVGGElement, ChordNode<N>>\n\n transition.attrTween('d', (d, i, els) => {\n const arcNode: ArcNode = els[i]\n const nextAnimState = { x0: d.x0, x1: d.x1, y0: d.y0, y1: d.y1 }\n const datum = interpolate(arcNode._animState, nextAnimState)\n\n return (t: number): string => {\n arcNode._animState = datum(t)\n return arcGen(arcNode._animState)\n }\n })\n } else {\n selection.attr('d', d => arcGen(d))\n .style('opacity', 1)\n }\n}\n\nexport function removeNode<N extends ChordInputNode> (\n selection: Selection<SVGPathElement, unknown, SVGGElement, unknown>,\n duration: number\n): void {\n smartTransition(selection, duration)\n .style('opacity', 0)\n .remove()\n}\n"],"names":[],"mappings":";;;;AAoBM,SAAU,UAAU,CACxB,SAAwE,EAAA;IAExE,SAAS;AACN,SAAA,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;SACnB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAI;AAClB,QAAA,MAAM,OAAO,GAAY,GAAG,CAAC,CAAC,CAAC,CAAA;AAC/B,QAAA,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;AACrC,QAAA,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QACxC,OAAO,CAAC,UAAU,GAAG;AACnB,YAAA,EAAE,EAAE,WAAW,GAAG,cAAc,GAAG,GAAG;AACtC,YAAA,EAAE,EAAE,WAAW,GAAG,cAAc,GAAG,GAAG;YACtC,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,EAAE,EAAE,CAAC,CAAC,EAAE;SACT,CAAA;AACH,KAAC,CAAC,CAAA;AACN,CAAC;AAEK,SAAU,UAAU,CACxB,SAAwE,EACxE,MAAyC,EACzC,MAA+B,EAC/B,QAAgB,EAAA;AAEhB,IAAA,MAAM,SAAS,GAAG,CAAC,CAAe,KAAa,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IAEjF,SAAS;SACN,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;SACtB,KAAK,CAAC,YAAY,EAAE,CAAA,KAAA,EAAQ,QAAQ,CAAI,EAAA,CAAA,CAAC;AACzC,SAAA,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC;AACxB,SAAA,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;AAE7B,IAAA,IAAI,QAAQ,EAAE;AACZ,QAAA,MAAM,UAAU,GAAG,eAAe,CAAC,SAAS,EAAE,QAAQ,CAAC;AACpD,aAAA,KAAK,CAAC,SAAS,EAAE,CAAC,CAAwE,CAAA;AAE7F,QAAA,UAAU,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAI;AACtC,YAAA,MAAM,OAAO,GAAY,GAAG,CAAC,CAAC,CAAC,CAAA;YAC/B,MAAM,aAAa,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAA;YAChE,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,UAAU,EAAE,aAAa,CAAC,CAAA;YAE5D,OAAO,CAAC,CAAS,KAAY;AAC3B,gBAAA,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;AAC7B,gBAAA,OAAO,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;AACnC,aAAC,CAAA;AACH,SAAC,CAAC,CAAA;AACH,KAAA;AAAM,SAAA;AACL,QAAA,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;AAChC,aAAA,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;AACvB,KAAA;AACH,CAAC;AAEe,SAAA,UAAU,CACxB,SAAmE,EACnE,QAAgB,EAAA;AAEhB,IAAA,eAAe,CAAC,SAAS,EAAE,QAAQ,CAAC;AACjC,SAAA,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;AACnB,SAAA,MAAM,EAAE,CAAA;AACb;;;;"}
|
|
@@ -17,6 +17,7 @@ const variables = injectGlobal `
|
|
|
17
17
|
|
|
18
18
|
--vis-chord-diagram-label-text-fill-color-bright: #ffffff;
|
|
19
19
|
--vis-chord-diagram-label-text-fill-color-dark: #a5abb2;
|
|
20
|
+
--vis-chord-diagram-label-text-font-size: 16px;
|
|
20
21
|
|
|
21
22
|
--vis-dark-chord-diagram-link-fill-color: #575c65;
|
|
22
23
|
}
|
|
@@ -25,6 +26,9 @@ const variables = injectGlobal `
|
|
|
25
26
|
--vis-chord-diagram-link-fill-color: var(--vis-dark-chord-diagram-link-fill-color);
|
|
26
27
|
}
|
|
27
28
|
`;
|
|
29
|
+
const background = css `
|
|
30
|
+
label: background;
|
|
31
|
+
`;
|
|
28
32
|
const nodes = css `
|
|
29
33
|
label: nodes;
|
|
30
34
|
`;
|
|
@@ -50,11 +54,12 @@ const label = css `
|
|
|
50
54
|
label: label;
|
|
51
55
|
`;
|
|
52
56
|
const labelText = css `
|
|
53
|
-
label: label-text
|
|
57
|
+
label: label-text;
|
|
54
58
|
|
|
55
59
|
dominant-baseline: middle;
|
|
56
60
|
user-select: none;
|
|
57
|
-
|
|
61
|
+
font-size: var(--vis-chord-diagram-label-text-font-size);
|
|
62
|
+
|
|
58
63
|
> textPath {
|
|
59
64
|
dominant-baseline: central;
|
|
60
65
|
}
|
|
@@ -87,5 +92,5 @@ const transparent = css `
|
|
|
87
92
|
}
|
|
88
93
|
`;
|
|
89
94
|
|
|
90
|
-
export { highlightedLink, highlightedNode, label, labelExit, labelText, labels, link, links, node, nodes, root, transparent, variables };
|
|
95
|
+
export { background, highlightedLink, highlightedNode, label, labelExit, labelText, labels, link, links, node, nodes, root, transparent, variables };
|
|
91
96
|
//# sourceMappingURL=style.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","sources":["../../../src/components/chord-diagram/style.ts"],"sourcesContent":["import { css, injectGlobal } from '@emotion/css'\n\nexport const root = css`\n label: chord-diagram-component;\n`\n\nexport const variables = injectGlobal`\n :root {\n --vis-chord-diagram-link-fill-color: #cad5f6;\n --vis-chord-diagram-link-stroke-color: #777777;\n --vis-chord-diagram-link-opacity: 0.5;\n --vis-chord-diagram-link-stroke-opacity: 0.15;\n --vis-chord-diagram-link-highlighted-opacity: 0.9;\n --vis-chord-diagram-link-dimmed-opacity: 0.25;\n\n --vis-chord-diagram-node-highlighted-opacity: 0.9;\n --vis-chord-diagram-node-dimmed-opacity: 0.25;\n\n --vis-chord-diagram-label-text-fill-color-bright: #ffffff;\n --vis-chord-diagram-label-text-fill-color-dark: #a5abb2;\n\n --vis-dark-chord-diagram-link-fill-color: #575c65;\n }\n\n body.theme-dark ${`.${root}`} {\n --vis-chord-diagram-link-fill-color: var(--vis-dark-chord-diagram-link-fill-color);\n }\n`\n\nexport const nodes = css`\n label: nodes;\n`\n\nexport const links = css`\n label: links;\n`\n\nexport const labels = css`\n label: labels;\n`\n\nexport const node = css`\n label: node;\n stroke-width: 0;\n fill: var(--vis-color-main);\n stroke: var(--vis-color-main);\n transition: .1s fill-opacity;\n`\n\nexport const highlightedNode = css`\n label: highlighted;\n fill-opacity: var(--vis-chord-diagram-node-highlighted-opacity);\n stroke-width: 1.5;\n`\n\nexport const label = css`\n label: label;\n`\n\nexport const labelText = css`\n label: label-text
|
|
1
|
+
{"version":3,"file":"style.js","sources":["../../../src/components/chord-diagram/style.ts"],"sourcesContent":["import { css, injectGlobal } from '@emotion/css'\n\nexport const root = css`\n label: chord-diagram-component;\n`\n\nexport const variables = injectGlobal`\n :root {\n --vis-chord-diagram-link-fill-color: #cad5f6;\n --vis-chord-diagram-link-stroke-color: #777777;\n --vis-chord-diagram-link-opacity: 0.5;\n --vis-chord-diagram-link-stroke-opacity: 0.15;\n --vis-chord-diagram-link-highlighted-opacity: 0.9;\n --vis-chord-diagram-link-dimmed-opacity: 0.25;\n\n --vis-chord-diagram-node-highlighted-opacity: 0.9;\n --vis-chord-diagram-node-dimmed-opacity: 0.25;\n\n --vis-chord-diagram-label-text-fill-color-bright: #ffffff;\n --vis-chord-diagram-label-text-fill-color-dark: #a5abb2;\n --vis-chord-diagram-label-text-font-size: 16px;\n\n --vis-dark-chord-diagram-link-fill-color: #575c65;\n }\n\n body.theme-dark ${`.${root}`} {\n --vis-chord-diagram-link-fill-color: var(--vis-dark-chord-diagram-link-fill-color);\n }\n`\n\nexport const background = css`\n label: background;\n`\n\nexport const nodes = css`\n label: nodes;\n`\n\nexport const links = css`\n label: links;\n`\n\nexport const labels = css`\n label: labels;\n`\n\nexport const node = css`\n label: node;\n stroke-width: 0;\n fill: var(--vis-color-main);\n stroke: var(--vis-color-main);\n transition: .1s fill-opacity;\n`\n\nexport const highlightedNode = css`\n label: highlighted;\n fill-opacity: var(--vis-chord-diagram-node-highlighted-opacity);\n stroke-width: 1.5;\n`\n\nexport const label = css`\n label: label;\n`\n\nexport const labelText = css`\n label: label-text;\n\n dominant-baseline: middle;\n user-select: none;\n font-size: var(--vis-chord-diagram-label-text-font-size);\n \n > textPath {\n dominant-baseline: central;\n }\n`\n\nexport const labelExit = css`\n label: label-exit;\n`\n\nexport const link = css`\n label: link;\n\n fill: var(--vis-chord-diagram-link-fill-color);\n fill-opacity: var(--vis-chord-diagram-link-opacity);\n stroke: var(--vis-chord-diagram-link-stroke-color);\n stroke-opacity: var(--vis-chord-diagram-link-stroke-opacity);\n transition: .1s fill-opacity;\n`\nexport const highlightedLink = css`\n label: highlighted;\n fill-opacity: var(--vis-chord-diagram-link-highlighted-opacity);\n`\n\nexport const transparent = css`\n label: transparent;\n\n ${`.${link}`}:not(${`.${highlightedLink}`}) {\n fill-opacity: var(--vis-chord-diagram-link-dimmed-opacity);\n }\n\n ${`.${node}`}:not(${`.${highlightedNode}`}) {\n fill-opacity: var(--vis-chord-diagram-node-dimmed-opacity);\n }\n`\n"],"names":[],"mappings":";;AAEO,MAAM,IAAI,GAAG,GAAG,CAAA,CAAA;;EAEtB;AAEM,MAAM,SAAS,GAAG,YAAY,CAAA,CAAA;;;;;;;;;;;;;;;;;;;AAmBjB,kBAAA,EAAA,CAAA,CAAA,EAAI,IAAI,CAAE,CAAA,CAAA;;;EAG7B;AAEM,MAAM,UAAU,GAAG,GAAG,CAAA,CAAA;;EAE5B;AAEM,MAAM,KAAK,GAAG,GAAG,CAAA,CAAA;;EAEvB;AAEM,MAAM,KAAK,GAAG,GAAG,CAAA,CAAA;;EAEvB;AAEM,MAAM,MAAM,GAAG,GAAG,CAAA,CAAA;;EAExB;AAEM,MAAM,IAAI,GAAG,GAAG,CAAA,CAAA;;;;;;EAMtB;AAEM,MAAM,eAAe,GAAG,GAAG,CAAA,CAAA;;;;EAIjC;AAEM,MAAM,KAAK,GAAG,GAAG,CAAA,CAAA;;EAEvB;AAEM,MAAM,SAAS,GAAG,GAAG,CAAA,CAAA;;;;;;;;;;EAU3B;AAEM,MAAM,SAAS,GAAG,GAAG,CAAA,CAAA;;EAE3B;AAEM,MAAM,IAAI,GAAG,GAAG,CAAA,CAAA;;;;;;;;EAQtB;AACM,MAAM,eAAe,GAAG,GAAG,CAAA,CAAA;;;EAGjC;AAEM,MAAM,WAAW,GAAG,GAAG,CAAA,CAAA;;;AAG1B,EAAA,EAAA,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAQ,KAAA,EAAA,CAAA,CAAA,EAAI,eAAe,CAAE,CAAA,CAAA;;;;AAIvC,EAAA,EAAA,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAQ,KAAA,EAAA,CAAA,CAAA,EAAI,eAAe,CAAE,CAAA,CAAA;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unovis/ts",
|
|
3
3
|
"description": "Modular data visualization framework for React, Angular, Svelte, and vanilla TypeScript or JavaScript",
|
|
4
|
-
"version": "1.3.2-beta.
|
|
4
|
+
"version": "1.3.2-beta.3",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/f5/unovis.git",
|