@unovis/ts 1.5.1-xplg.5 → 1.5.2
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/README.md +1 -1
- package/components/annotations/style.js.map +1 -1
- package/components/area/config.d.ts +0 -2
- package/components/area/config.js +1 -1
- package/components/area/config.js.map +1 -1
- package/components/area/index.js +3 -6
- package/components/area/index.js.map +1 -1
- package/components/area/style.js.map +1 -1
- package/components/axis/config.d.ts +1 -1
- package/components/axis/config.js.map +1 -1
- package/components/axis/index.d.ts +1 -0
- package/components/axis/index.js +10 -2
- package/components/axis/index.js.map +1 -1
- package/components/axis/style.js.map +1 -1
- package/components/brush/config.d.ts +1 -1
- package/components/brush/config.js.map +1 -1
- package/components/brush/style.js.map +1 -1
- package/components/bullet-legend/style.js.map +1 -1
- package/components/chord-diagram/index.js +3 -1
- package/components/chord-diagram/index.js.map +1 -1
- package/components/chord-diagram/style.js.map +1 -1
- package/components/crosshair/style.js.map +1 -1
- package/components/donut/style.js.map +1 -1
- package/components/flow-legend/style.js.map +1 -1
- package/components/free-brush/style.js.map +1 -1
- package/components/graph/index.js +3 -4
- package/components/graph/index.js.map +1 -1
- package/components/graph/modules/link/index.js +1 -2
- package/components/graph/modules/link/index.js.map +1 -1
- package/components/graph/modules/link/style.js.map +1 -1
- package/components/graph/modules/node/style.js.map +1 -1
- package/components/graph/modules/panel/style.js.map +1 -1
- package/components/graph/style.js.map +1 -1
- package/components/grouped-bar/style.js.map +1 -1
- package/components/leaflet-flow-map/config.js +0 -1
- package/components/leaflet-flow-map/config.js.map +1 -1
- package/components/leaflet-flow-map/shaders.js.map +1 -1
- package/components/leaflet-map/config.js +0 -1
- package/components/leaflet-map/config.js.map +1 -1
- package/components/leaflet-map/modules/map.js +3 -3
- package/components/leaflet-map/modules/map.js.map +1 -1
- package/components/leaflet-map/renderer/leaflet-maplibre-gl.js.map +1 -1
- package/components/leaflet-map/style.js.map +1 -1
- package/components/line/config.d.ts +5 -0
- package/components/line/config.js +1 -1
- package/components/line/config.js.map +1 -1
- package/components/line/index.js +41 -2
- package/components/line/index.js.map +1 -1
- package/components/line/style.d.ts +1 -0
- package/components/line/style.js +12 -1
- package/components/line/style.js.map +1 -1
- package/components/line/types.d.ts +1 -0
- package/components/nested-donut/config.d.ts +1 -1
- package/components/nested-donut/config.js.map +1 -1
- package/components/nested-donut/style.js.map +1 -1
- package/components/sankey/modules/label.js.map +1 -1
- package/components/sankey/modules/link.js.map +1 -1
- package/components/sankey/style.js.map +1 -1
- package/components/scatter/index.d.ts +1 -0
- package/components/scatter/index.js +11 -1
- package/components/scatter/index.js.map +1 -1
- package/components/scatter/style.js.map +1 -1
- package/components/stacked-bar/style.js.map +1 -1
- package/components/timeline/config.d.ts +14 -65
- package/components/timeline/config.js +1 -15
- package/components/timeline/config.js.map +1 -1
- package/components/timeline/index.d.ts +10 -21
- package/components/timeline/index.js +93 -379
- package/components/timeline/index.js.map +1 -1
- package/components/timeline/style.d.ts +0 -7
- package/components/timeline/style.js +1 -40
- package/components/timeline/style.js.map +1 -1
- package/components/tooltip/config.d.ts +6 -4
- package/components/tooltip/config.js +3 -1
- package/components/tooltip/config.js.map +1 -1
- package/components/tooltip/index.d.ts +7 -3
- package/components/tooltip/index.js +39 -9
- package/components/tooltip/index.js.map +1 -1
- package/components/tooltip/style.js.map +1 -1
- package/components/topojson-map/index.js.map +1 -1
- package/components/topojson-map/style.js.map +1 -1
- package/components/vis-controls/style.js.map +1 -1
- package/components/xy-labels/index.js +1 -1
- package/components/xy-labels/index.js.map +1 -1
- package/components/xy-labels/style.js.map +1 -1
- package/components.d.ts +0 -4
- package/components.js +0 -2
- package/components.js.map +1 -1
- package/containers/single-container/config.d.ts +0 -3
- package/containers/single-container/config.js.map +1 -1
- package/containers/single-container/index.js +1 -2
- package/containers/single-container/index.js.map +1 -1
- package/containers/xy-container/config.d.ts +0 -5
- package/containers/xy-container/config.js +1 -1
- package/containers/xy-container/config.js.map +1 -1
- package/containers/xy-container/index.d.ts +0 -1
- package/containers/xy-container/index.js +11 -15
- package/containers/xy-container/index.js.map +1 -1
- package/core/container/config.js +0 -1
- package/core/container/config.js.map +1 -1
- package/index.js +3 -5
- package/index.js.map +1 -1
- package/maps/ind-regions.json.js +1 -1
- package/maps/us-counties.json.js +8 -8
- package/package.json +9 -7
- package/styles/index.js.map +1 -1
- package/styles/patterns.js.map +1 -1
- package/styles/sizes.js.map +1 -1
- package/types/position.d.ts +1 -2
- package/types/position.js +0 -1
- package/types/position.js.map +1 -1
- package/types.d.ts +0 -2
- package/types.js +1 -4
- package/types.js.map +1 -1
- package/utils/color.d.ts +0 -14
- package/utils/color.js +2 -26
- package/utils/color.js.map +1 -1
- package/utils/data.d.ts +1 -1
- package/utils/data.js +2 -2
- package/utils/data.js.map +1 -1
- package/utils/index.js +3 -3
- package/utils/path.d.ts +0 -8
- package/utils/path.js +1 -109
- package/utils/path.js.map +1 -1
- package/utils/text.d.ts +1 -2
- package/utils/text.js +2 -10
- package/utils/text.js.map +1 -1
- package/components/rolling-pin-legend/config.d.ts +0 -19
- package/components/rolling-pin-legend/config.js +0 -9
- package/components/rolling-pin-legend/config.js.map +0 -1
- package/components/rolling-pin-legend/index.d.ts +0 -16
- package/components/rolling-pin-legend/index.js +0 -63
- package/components/rolling-pin-legend/index.js.map +0 -1
- package/components/rolling-pin-legend/style.d.ts +0 -5
- package/components/rolling-pin-legend/style.js +0 -40
- package/components/rolling-pin-legend/style.js.map +0 -1
- package/components/rolling-pin-legend/types.d.ts +0 -1
- package/components/timeline/constants.d.ts +0 -3
- package/components/timeline/constants.js +0 -6
- package/components/timeline/constants.js.map +0 -1
- package/components/timeline/types.d.ts +0 -62
- package/components/timeline/types.js +0 -2
- package/components/timeline/types.js.map +0 -1
- package/components/timeline/utils.d.ts +0 -2
- package/components/timeline/utils.js +0 -16
- package/components/timeline/utils.js.map +0 -1
- package/components/treemap/config.d.ts +0 -44
- package/components/treemap/config.js +0 -6
- package/components/treemap/config.js.map +0 -1
- package/components/treemap/index.d.ts +0 -16
- package/components/treemap/index.js +0 -263
- package/components/treemap/index.js.map +0 -1
- package/components/treemap/style.d.ts +0 -22
- package/components/treemap/style.js +0 -62
- package/components/treemap/style.js.map +0 -1
- package/components/treemap/types.d.ts +0 -11
- package/components/treemap/types.js +0 -2
- package/components/treemap/types.js.map +0 -1
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import { select } from 'd3-selection';
|
|
2
|
-
import { max, min, minIndex } from 'd3-array';
|
|
3
2
|
import { scaleOrdinal } from 'd3-scale';
|
|
4
3
|
import { drag } from 'd3-drag';
|
|
4
|
+
import { max } from 'd3-array';
|
|
5
5
|
import { XYComponentCore } from '../../core/xy-component/index.js';
|
|
6
|
-
import {
|
|
6
|
+
import { isNumber, unique, arrayOfIndices, getString, getNumber, getMin, getMax } from '../../utils/data.js';
|
|
7
7
|
import { smartTransition } from '../../utils/d3.js';
|
|
8
8
|
import { getColor } from '../../utils/color.js';
|
|
9
|
-
import { trimSVGText
|
|
10
|
-
import { arrowPolylinePath } from '../../utils/path.js';
|
|
11
|
-
import { guid } from '../../utils/misc.js';
|
|
12
|
-
import '../../types.js';
|
|
9
|
+
import { trimSVGText } from '../../utils/text.js';
|
|
13
10
|
import { TimelineDefaultConfig } from './config.js';
|
|
14
11
|
import * as style from './style.js';
|
|
15
|
-
import { background, rows,
|
|
16
|
-
import { TIMELINE_DEFAULT_ARROW_HEAD_LENGTH, TIMELINE_DEFAULT_ARROW_HEAD_WIDTH, TIMELINE_DEFAULT_ARROW_MARGIN } from './constants.js';
|
|
17
|
-
import { getIconBleed } from './utils.js';
|
|
18
|
-
import { TextAlign } from '../../types/text.js';
|
|
19
|
-
import { Arrangement } from '../../types/position.js';
|
|
12
|
+
import { background, rows, lines, labels, scrollbar, scrollbarBackground, scrollbarHandle, label, row, rowOdd, line } from './style.js';
|
|
20
13
|
|
|
21
14
|
class Timeline extends XYComponentCore {
|
|
22
15
|
constructor(config) {
|
|
@@ -24,12 +17,6 @@ class Timeline extends XYComponentCore {
|
|
|
24
17
|
this._defaultConfig = TimelineDefaultConfig;
|
|
25
18
|
this.config = this._defaultConfig;
|
|
26
19
|
this.events = {
|
|
27
|
-
[Timeline.selectors.background]: {
|
|
28
|
-
wheel: this._onMouseWheel.bind(this),
|
|
29
|
-
},
|
|
30
|
-
[Timeline.selectors.label]: {
|
|
31
|
-
wheel: this._onMouseWheel.bind(this),
|
|
32
|
-
},
|
|
33
20
|
[Timeline.selectors.rows]: {
|
|
34
21
|
wheel: this._onMouseWheel.bind(this),
|
|
35
22
|
},
|
|
@@ -43,29 +30,14 @@ class Timeline extends XYComponentCore {
|
|
|
43
30
|
this._maxScroll = 0;
|
|
44
31
|
this._scrollbarHeight = 0;
|
|
45
32
|
this._labelMargin = 5;
|
|
46
|
-
this._labelWidth = 0; // Will be overridden in `get bleed ()`
|
|
47
|
-
this._rowIconBleed = [0, 0];
|
|
48
|
-
this._lineBleed = [0, 0];
|
|
49
|
-
/** We define a dedicated clipping path for this component because it needs to behave
|
|
50
|
-
* differently than the regular XYContainer's clipPath */
|
|
51
|
-
this._clipPathId = guid();
|
|
52
33
|
if (config)
|
|
53
34
|
this.setConfig(config);
|
|
54
35
|
// Invisible background rect to track events
|
|
55
36
|
this._background = this.g.append('rect').attr('class', background);
|
|
56
|
-
// Clip path
|
|
57
|
-
this._clipPath = this.g.append('clipPath')
|
|
58
|
-
.attr('id', this._clipPathId);
|
|
59
|
-
this._clipPath.append('rect');
|
|
60
37
|
// Group for content
|
|
61
|
-
this._rowsGroup = this.g.append('g').attr('class', rows)
|
|
62
|
-
|
|
63
|
-
this._arrowsGroup = this.g.append('g').attr('class', arrows)
|
|
64
|
-
.style('clip-path', `url(#${this._clipPathId})`);
|
|
65
|
-
this._linesGroup = this.g.append('g').attr('class', lines)
|
|
66
|
-
.style('clip-path', `url(#${this._clipPathId})`);
|
|
38
|
+
this._rowsGroup = this.g.append('g').attr('class', rows);
|
|
39
|
+
this._linesGroup = this.g.append('g').attr('class', lines);
|
|
67
40
|
this._labelsGroup = this.g.append('g').attr('class', labels);
|
|
68
|
-
this._rowIconsGroup = this.g.append('g').attr('class', rowIcons);
|
|
69
41
|
this._scrollBarGroup = this.g.append('g').attr('class', scrollbar);
|
|
70
42
|
// Scroll bar
|
|
71
43
|
this._scrollBarBackground = this._scrollBarGroup.append('rect')
|
|
@@ -77,80 +49,35 @@ class Timeline extends XYComponentCore {
|
|
|
77
49
|
.on('drag', this._onScrollbarDrag.bind(this));
|
|
78
50
|
this._scrollBarHandle.call(dragBehaviour);
|
|
79
51
|
}
|
|
80
|
-
setConfig(config) {
|
|
81
|
-
super.setConfig(config);
|
|
82
|
-
}
|
|
83
|
-
setData(data) {
|
|
84
|
-
super.setData(data);
|
|
85
|
-
}
|
|
86
52
|
get bleed() {
|
|
87
|
-
var _a, _b, _c, _d;
|
|
88
53
|
const { config, datamodel: { data } } = this;
|
|
89
|
-
const rowLabels = this._getRowLabels(data);
|
|
90
|
-
const rowHeight = config.rowHeight || (this._height / rowLabels.length);
|
|
91
|
-
const hasIcons = rowLabels.some(l => l.iconHref);
|
|
92
|
-
const maxIconSize = max(rowLabels.map(l => l.iconSize || 0));
|
|
93
54
|
// We calculate the longest label width to set the bleed values accordingly
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
55
|
+
let labelsBleed = 0;
|
|
56
|
+
if (config.showLabels) {
|
|
57
|
+
if (config.labelWidth)
|
|
58
|
+
labelsBleed = config.labelWidth + this._labelMargin;
|
|
97
59
|
else {
|
|
98
|
-
const
|
|
60
|
+
const recordLabels = this._getRecordLabels(data);
|
|
61
|
+
const longestLabel = recordLabels.reduce((acc, val) => acc.length > val.length ? acc : val, '');
|
|
99
62
|
const label$1 = this._labelsGroup.append('text')
|
|
100
63
|
.attr('class', label)
|
|
101
|
-
.text(
|
|
102
|
-
.call(trimSVGText,
|
|
64
|
+
.text(longestLabel)
|
|
65
|
+
.call(trimSVGText, config.maxLabelWidth);
|
|
103
66
|
const labelWidth = label$1.node().getBBox().width;
|
|
104
|
-
|
|
67
|
+
this._labelsGroup.empty();
|
|
105
68
|
const tolerance = 1.15; // Some characters are wider than others so we add a little of extra space to take that into account
|
|
106
|
-
|
|
69
|
+
labelsBleed = labelWidth ? tolerance * labelWidth + this._labelMargin : 0;
|
|
107
70
|
}
|
|
108
71
|
}
|
|
109
|
-
|
|
110
|
-
const minTimestamp = min(data, (d, i) => getNumber(d, config.x, i));
|
|
111
|
-
const dataMin = data.filter((d, i) => getNumber(d, config.x, i) === minTimestamp);
|
|
112
|
-
const dataMinShortestItemIdx = minIndex(dataMin, (d, i) => this._getLineDuration(d, i));
|
|
113
|
-
const firstItemIdx = data.findIndex(d => d === dataMin[dataMinShortestItemIdx]);
|
|
114
|
-
const firstItem = data[firstItemIdx];
|
|
115
|
-
const maxTimestamp = max(data, (d, i) => getNumber(d, config.x, i) + this._getLineDuration(d, i));
|
|
116
|
-
const dataMax = data.filter((d, i) => getNumber(d, config.x, i) + this._getLineDuration(d, i) === maxTimestamp);
|
|
117
|
-
const dataMaxShortestItemIdx = minIndex(dataMax, (d, i) => this._getLineDuration(d, i));
|
|
118
|
-
const lastItemIdx = data.findIndex(d => d === dataMax[dataMaxShortestItemIdx]);
|
|
119
|
-
const lastItem = data[lastItemIdx];
|
|
120
|
-
// Small segments bleed
|
|
121
|
-
const lineBleed = [1, 1];
|
|
122
|
-
if (config.showEmptySegments && config.lineCap && firstItem && lastItem) {
|
|
123
|
-
const firstItemStart = getNumber(firstItem, config.x, firstItemIdx);
|
|
124
|
-
const firstItemEnd = getNumber(firstItem, config.x, firstItemIdx) + this._getLineDuration(firstItem, firstItemIdx);
|
|
125
|
-
const lastItemStart = getNumber(lastItem, config.x, lastItemIdx);
|
|
126
|
-
const lastItemEnd = getNumber(lastItem, config.x, lastItemIdx) + this._getLineDuration(lastItem, lastItemIdx);
|
|
127
|
-
const fullTimeRange = lastItemEnd - firstItemStart;
|
|
128
|
-
const firstItemHeight = this._getLineWidth(firstItem, firstItemIdx, rowHeight);
|
|
129
|
-
const lastItemHeight = this._getLineWidth(lastItem, lastItemIdx, rowHeight);
|
|
130
|
-
if ((firstItemEnd - firstItemStart) / fullTimeRange * this._width < firstItemHeight)
|
|
131
|
-
lineBleed[0] = firstItemHeight / 2;
|
|
132
|
-
if ((lastItemEnd - lastItemStart) / fullTimeRange * this._width < lastItemHeight)
|
|
133
|
-
lineBleed[1] = lastItemHeight / 2;
|
|
134
|
-
}
|
|
135
|
-
this._lineBleed = lineBleed;
|
|
136
|
-
// Icon bleed
|
|
137
|
-
const iconBleed = [0, 0];
|
|
138
|
-
if (config.lineStartIcon) {
|
|
139
|
-
iconBleed[0] = max(data, (d, i) => getIconBleed(d, i, config.lineStartIcon, config.lineStartIconSize, config.lineStartIconArrangement, rowHeight)) || 0;
|
|
140
|
-
}
|
|
141
|
-
if (config.lineEndIcon) {
|
|
142
|
-
iconBleed[1] = max(data, (d, i) => getIconBleed(d, i, config.lineEndIcon, config.lineEndIconSize, config.lineEndIconArrangement, rowHeight)) || 0;
|
|
143
|
-
}
|
|
144
|
-
this._rowIconBleed = iconBleed;
|
|
72
|
+
const maxLineWidth = this._getMaxLineWidth();
|
|
145
73
|
return {
|
|
146
74
|
top: 0,
|
|
147
75
|
bottom: 0,
|
|
148
|
-
left:
|
|
149
|
-
right: this._scrollBarWidth + this._scrollBarMargin
|
|
76
|
+
left: maxLineWidth / 2 + labelsBleed,
|
|
77
|
+
right: maxLineWidth / 2 + this._scrollBarWidth + this._scrollBarMargin,
|
|
150
78
|
};
|
|
151
79
|
}
|
|
152
80
|
_render(customDuration) {
|
|
153
|
-
var _a;
|
|
154
81
|
super._render(customDuration);
|
|
155
82
|
const { config, datamodel: { data } } = this;
|
|
156
83
|
const duration = isNumber(customDuration) ? customDuration : config.duration;
|
|
@@ -158,185 +85,71 @@ class Timeline extends XYComponentCore {
|
|
|
158
85
|
const yRange = this.yScale.range();
|
|
159
86
|
const yStart = Math.min(...yRange);
|
|
160
87
|
const yHeight = Math.abs(yRange[1] - yRange[0]);
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
88
|
+
const maxLineWidth = this._getMaxLineWidth();
|
|
89
|
+
const recordLabels = this._getRecordLabels(data);
|
|
90
|
+
const recordLabelsUnique = unique(recordLabels);
|
|
91
|
+
const numUniqueRecords = recordLabelsUnique.length;
|
|
92
|
+
// Ordinal scale to handle records on the same type
|
|
93
|
+
const ordinalScale = scaleOrdinal();
|
|
94
|
+
ordinalScale.range(arrayOfIndices(numUniqueRecords));
|
|
168
95
|
// Invisible Background rect to track events
|
|
169
96
|
this._background
|
|
170
97
|
.attr('width', this._width)
|
|
171
98
|
.attr('height', this._height)
|
|
172
99
|
.attr('opacity', 0);
|
|
173
|
-
// Row Icons
|
|
174
|
-
const rowIcons = this._rowIconsGroup.selectAll(`.${rowIcon}`)
|
|
175
|
-
.data(rowLabels.filter(d => d.iconSize), l => l === null || l === void 0 ? void 0 : l.label);
|
|
176
|
-
const rowIconsEnter = rowIcons.enter().append('use')
|
|
177
|
-
.attr('class', rowIcon)
|
|
178
|
-
.attr('x', 0)
|
|
179
|
-
.attr('width', l => l.iconSize)
|
|
180
|
-
.attr('height', l => l.iconSize)
|
|
181
|
-
.attr('y', l => yStart + (yOrdinalScale(l.label) + 0.5) * rowHeight - l.iconSize / 2)
|
|
182
|
-
.style('opacity', 0);
|
|
183
|
-
smartTransition(rowIconsEnter.merge(rowIcons), duration)
|
|
184
|
-
.attr('href', l => l.iconHref)
|
|
185
|
-
.attr('x', 0)
|
|
186
|
-
.attr('y', l => yStart + (yOrdinalScale(l.label) + 0.5) * rowHeight - l.iconSize / 2)
|
|
187
|
-
.attr('width', l => l.iconSize)
|
|
188
|
-
.attr('height', l => l.iconSize)
|
|
189
|
-
.style('color', l => l.iconColor)
|
|
190
|
-
.style('opacity', 1);
|
|
191
|
-
smartTransition(rowIcons.exit(), duration)
|
|
192
|
-
.style('opacity', 0)
|
|
193
|
-
.remove();
|
|
194
100
|
// Labels
|
|
195
101
|
const labels = this._labelsGroup.selectAll(`.${label}`)
|
|
196
|
-
.data(
|
|
197
|
-
const labelOffset = config.rowLabelTextAlign === TextAlign.Center ? this._labelWidth / 2
|
|
198
|
-
: config.rowLabelTextAlign === TextAlign.Left ? this._labelWidth
|
|
199
|
-
: this._labelMargin;
|
|
200
|
-
const xStart = xRange[0] - this._rowIconBleed[0] - this._lineBleed[0];
|
|
201
|
-
const labelXStart = xStart - labelOffset;
|
|
102
|
+
.data(config.showLabels ? recordLabelsUnique : []);
|
|
202
103
|
const labelsEnter = labels.enter().append('text')
|
|
203
|
-
.attr('class', label)
|
|
204
|
-
|
|
205
|
-
.attr('
|
|
206
|
-
.
|
|
207
|
-
|
|
208
|
-
.text(l => l.formattedLabel)
|
|
104
|
+
.attr('class', label);
|
|
105
|
+
labelsEnter.merge(labels)
|
|
106
|
+
.attr('x', xRange[0] - maxLineWidth / 2 - this._labelMargin)
|
|
107
|
+
.attr('y', (label, i) => yStart + (ordinalScale(label) + 0.5) * config.rowHeight)
|
|
108
|
+
.text(label => label)
|
|
209
109
|
.each((label, i, els) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// Apply custom label style if it has been provided
|
|
214
|
-
const customStyle = getValue(label, config.rowLabelStyle);
|
|
215
|
-
if (!isPlainObject(customStyle))
|
|
216
|
-
return;
|
|
217
|
-
for (const [prop, value] of Object.entries(customStyle)) {
|
|
218
|
-
labelSelection.style(prop, value);
|
|
219
|
-
}
|
|
220
|
-
})
|
|
221
|
-
.style('text-anchor', textAlignToAnchor(config.rowLabelTextAlign));
|
|
222
|
-
smartTransition(labelsMerged, duration)
|
|
223
|
-
.attr('x', labelXStart)
|
|
224
|
-
.attr('y', l => yStart + (yOrdinalScale(l.label) + 0.5) * rowHeight)
|
|
225
|
-
.style('opacity', 1);
|
|
226
|
-
smartTransition(labels.exit(), duration)
|
|
227
|
-
.style('opacity', 0)
|
|
228
|
-
.remove();
|
|
110
|
+
trimSVGText(select(els[i]), config.labelWidth || config.maxLabelWidth);
|
|
111
|
+
});
|
|
112
|
+
labels.exit().remove();
|
|
229
113
|
// Row background rects
|
|
230
|
-
const
|
|
231
|
-
const numRows = Math.max(Math.floor(yHeight / rowHeight),
|
|
232
|
-
const recordTypes = Array(numRows).fill(null).map((_, i) =>
|
|
114
|
+
const xStart = xRange[0];
|
|
115
|
+
const numRows = Math.max(Math.floor(yHeight / config.rowHeight), numUniqueRecords);
|
|
116
|
+
const recordTypes = Array(numRows).fill(null).map((_, i) => recordLabelsUnique[i]);
|
|
233
117
|
const rects = this._rowsGroup.selectAll(`.${row}`)
|
|
234
118
|
.data(recordTypes);
|
|
235
119
|
const rectsEnter = rects.enter().append('rect')
|
|
236
|
-
.attr('class', row)
|
|
237
|
-
|
|
238
|
-
.
|
|
239
|
-
.attr('
|
|
240
|
-
.attr('
|
|
241
|
-
.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
smartTransition(rectsMerged, duration)
|
|
245
|
-
.attr('x', xStart)
|
|
246
|
-
.attr('width', timelineWidth)
|
|
247
|
-
.attr('y', (_, i) => yStart + i * rowHeight)
|
|
248
|
-
.attr('height', rowHeight)
|
|
249
|
-
.style('opacity', 1);
|
|
250
|
-
smartTransition(rects.exit(), duration)
|
|
251
|
-
.style('opacity', 0)
|
|
252
|
-
.remove();
|
|
120
|
+
.attr('class', row);
|
|
121
|
+
rectsEnter.merge(rects)
|
|
122
|
+
.classed(rowOdd, config.alternatingRowColors ? (_, i) => !(i % 2) : null)
|
|
123
|
+
.attr('x', xStart - maxLineWidth / 2)
|
|
124
|
+
.attr('width', xRange[1] - xStart + maxLineWidth)
|
|
125
|
+
.attr('y', (_, i) => yStart + i * config.rowHeight)
|
|
126
|
+
.attr('height', config.rowHeight);
|
|
127
|
+
rects.exit().remove();
|
|
253
128
|
// Lines
|
|
254
|
-
const lines = this._linesGroup.selectAll(`.${
|
|
255
|
-
.data(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
.
|
|
260
|
-
var _a, _b;
|
|
261
|
-
const configuredPos = isFunction(config.animationLineEnterPosition)
|
|
262
|
-
? config.animationLineEnterPosition(d, i, lineDataPrepared)
|
|
263
|
-
: config.animationLineEnterPosition;
|
|
264
|
-
const [x, y] = [(_a = configuredPos === null || configuredPos === void 0 ? void 0 : configuredPos[0]) !== null && _a !== void 0 ? _a : d._xPx, (_b = configuredPos === null || configuredPos === void 0 ? void 0 : configuredPos[1]) !== null && _b !== void 0 ? _b : d._yPx];
|
|
265
|
-
return `translate(${x}, ${y})`;
|
|
129
|
+
const lines = this._linesGroup.selectAll(`.${line}`)
|
|
130
|
+
.data(data, (d, i) => {
|
|
131
|
+
var _a;
|
|
132
|
+
return (_a = getString(d, config.id, i)) !== null && _a !== void 0 ? _a : [
|
|
133
|
+
this._getRecordType(d, i), getNumber(d, config.x, i),
|
|
134
|
+
].join('-');
|
|
266
135
|
});
|
|
267
|
-
linesEnter.append('rect')
|
|
136
|
+
const linesEnter = lines.enter().append('rect')
|
|
268
137
|
.attr('class', line)
|
|
269
|
-
.
|
|
270
|
-
.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
.attr('transform', d => `translate(${d._xPx + d._xOffsetPx}, ${d._yPx})`)
|
|
276
|
-
.style('opacity', 1);
|
|
277
|
-
const lineRectElementsSelection = linesMerged.selectAll(`.${line}`)
|
|
278
|
-
.data(d => [d]);
|
|
279
|
-
smartTransition(lineRectElementsSelection, duration)
|
|
280
|
-
.style('fill', (d, i) => getColor(d, config.color, yOrdinalScale(this._getRecordKey(d, i))))
|
|
281
|
-
.style('cursor', (d, i) => { var _a; return getString(d, (_a = config.lineCursor) !== null && _a !== void 0 ? _a : config.cursor, i); })
|
|
282
|
-
.call(this._renderLines.bind(this), rowHeight);
|
|
283
|
-
linesMerged.selectAll(`.${lineStartIcon}`)
|
|
284
|
-
.data(d => [d])
|
|
285
|
-
.attr('href', (d, i) => getString(d, config.lineStartIcon, i))
|
|
286
|
-
.attr('x', (d, i) => {
|
|
287
|
-
const iconSize = d._startIconSize;
|
|
288
|
-
const iconArrangement = d._startIconArrangement;
|
|
289
|
-
const offset = iconArrangement === Arrangement.Inside ? 0
|
|
290
|
-
: iconArrangement === Arrangement.Center ? -iconSize / 2
|
|
291
|
-
: -iconSize;
|
|
292
|
-
return offset;
|
|
293
|
-
})
|
|
294
|
-
.attr('y', d => (-(d._startIconSize - d._height) / 2) || 0)
|
|
295
|
-
.attr('width', d => d._startIconSize)
|
|
296
|
-
.attr('height', d => d._startIconSize)
|
|
297
|
-
.style('color', d => d._startIconColor);
|
|
298
|
-
linesMerged.selectAll(`.${lineEndIcon}`)
|
|
299
|
-
.data(d => [d])
|
|
300
|
-
.attr('href', (d, i) => getString(d, config.lineEndIcon, i))
|
|
301
|
-
.attr('x', (d, i) => {
|
|
302
|
-
const lineLength = d._lengthCorrected;
|
|
303
|
-
const iconSize = d._endIconSize;
|
|
304
|
-
const iconArrangement = d._endIconArrangement;
|
|
305
|
-
const offset = iconArrangement === Arrangement.Inside ? -iconSize
|
|
306
|
-
: iconArrangement === Arrangement.Center ? -iconSize / 2
|
|
307
|
-
: 0;
|
|
308
|
-
return lineLength + offset;
|
|
309
|
-
})
|
|
310
|
-
.attr('y', d => -((d._endIconSize - d._height) / 2) || 0)
|
|
311
|
-
.attr('width', d => d._endIconSize)
|
|
312
|
-
.attr('height', d => d._endIconSize)
|
|
313
|
-
.style('color', d => d._endIconColor);
|
|
314
|
-
const linesExit = lines.exit();
|
|
315
|
-
smartTransition(linesExit, duration)
|
|
316
|
-
.style('opacity', 0)
|
|
317
|
-
.attr('transform', (d, i) => {
|
|
318
|
-
var _a, _b;
|
|
319
|
-
const configuredPos = isFunction(config.animationLineExitPosition)
|
|
320
|
-
? config.animationLineExitPosition(d, i, lineDataPrepared)
|
|
321
|
-
: config.animationLineExitPosition;
|
|
322
|
-
const [x, y] = [(_a = configuredPos === null || configuredPos === void 0 ? void 0 : configuredPos[0]) !== null && _a !== void 0 ? _a : d._xPx, (_b = configuredPos === null || configuredPos === void 0 ? void 0 : configuredPos[1]) !== null && _b !== void 0 ? _b : d._yPx];
|
|
323
|
-
return `translate(${x}, ${y})`;
|
|
324
|
-
})
|
|
325
|
-
.remove();
|
|
326
|
-
// Arrows
|
|
327
|
-
const arrowsData = this._prepareArrowsData(data, yOrdinalScale, rowHeight);
|
|
328
|
-
const arrows = this._arrowsGroup.selectAll(`.${arrow}`)
|
|
329
|
-
.data(arrowsData !== null && arrowsData !== void 0 ? arrowsData : [], d => d.id);
|
|
330
|
-
const arrowsEnter = arrows.enter().append('path')
|
|
331
|
-
.attr('class', arrow)
|
|
138
|
+
.classed(rowOdd, config.alternatingRowColors
|
|
139
|
+
? (d, i) => !(recordLabelsUnique.indexOf(this._getRecordType(d, i)) % 2)
|
|
140
|
+
: null)
|
|
141
|
+
.style('fill', (d, i) => getColor(d, config.color, ordinalScale(this._getRecordType(d, i))))
|
|
142
|
+
.call(this._positionLines.bind(this), ordinalScale)
|
|
143
|
+
.attr('transform', 'translate(0, 10)')
|
|
332
144
|
.style('opacity', 0);
|
|
333
|
-
|
|
334
|
-
.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
145
|
+
const linesMerged = linesEnter.merge(lines)
|
|
146
|
+
.style('fill', (d, i) => getColor(d, config.color, ordinalScale(this._getRecordType(d, i))))
|
|
147
|
+
.style('cursor', (d, i) => getString(d, config.cursor, i))
|
|
148
|
+
.call(this._positionLines.bind(this), ordinalScale);
|
|
149
|
+
smartTransition(linesMerged, duration)
|
|
150
|
+
.attr('transform', 'translate(0, 0)')
|
|
338
151
|
.style('opacity', 1);
|
|
339
|
-
smartTransition(
|
|
152
|
+
smartTransition(lines.exit(), duration)
|
|
340
153
|
.style('opacity', 0)
|
|
341
154
|
.remove();
|
|
342
155
|
// Scroll Bar
|
|
@@ -358,119 +171,32 @@ class Timeline extends XYComponentCore {
|
|
|
358
171
|
.attr('rx', this._scrollBarWidth / 2)
|
|
359
172
|
.attr('ry', this._scrollBarWidth / 2);
|
|
360
173
|
this._updateScrollPosition(0);
|
|
361
|
-
// Clip path
|
|
362
|
-
const clipPathRect = this._clipPath.select('rect');
|
|
363
|
-
smartTransition(clipPathRect, clipPathRect.attr('width') ? duration : 0)
|
|
364
|
-
.attr('x', xStart)
|
|
365
|
-
.attr('width', timelineWidth)
|
|
366
|
-
.attr('height', this._height);
|
|
367
|
-
}
|
|
368
|
-
_getLineLength(d, i) {
|
|
369
|
-
var _a, _b;
|
|
370
|
-
const { config, xScale } = this;
|
|
371
|
-
const x = getNumber(d, config.x, i);
|
|
372
|
-
const length = (_b = getNumber(d, (_a = config.lineDuration) !== null && _a !== void 0 ? _a : config.length, i)) !== null && _b !== void 0 ? _b : 0;
|
|
373
|
-
const lineLength = xScale(x + length) - xScale(x);
|
|
374
|
-
return lineLength;
|
|
375
174
|
}
|
|
376
|
-
|
|
377
|
-
var _a;
|
|
378
|
-
const { config } = this;
|
|
379
|
-
return (_a = getNumber(d, config.lineWidth, i)) !== null && _a !== void 0 ? _a : Math.max(Math.floor(rowHeight / 2), 1);
|
|
380
|
-
}
|
|
381
|
-
_getLineDuration(d, i) {
|
|
382
|
-
var _a, _b;
|
|
383
|
-
const { config } = this;
|
|
384
|
-
return (_b = getNumber(d, (_a = config.lineDuration) !== null && _a !== void 0 ? _a : config.length, i)) !== null && _b !== void 0 ? _b : 0;
|
|
385
|
-
}
|
|
386
|
-
_prepareLinesData(data, rowOrdinalScale, rowHeight) {
|
|
175
|
+
_positionLines(selection, ordinalScale) {
|
|
387
176
|
const { config, xScale, yScale } = this;
|
|
388
177
|
const yRange = yScale.range();
|
|
389
178
|
const yStart = Math.min(...yRange);
|
|
390
|
-
|
|
391
|
-
var _a
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
|
|
179
|
+
selection.each((d, i, elements) => {
|
|
180
|
+
var _a;
|
|
181
|
+
const x = getNumber(d, config.x, i);
|
|
182
|
+
const y = ordinalScale(this._getRecordType(d, i)) * config.rowHeight;
|
|
183
|
+
const length = (_a = getNumber(d, config.length, i)) !== null && _a !== void 0 ? _a : 0;
|
|
184
|
+
// Rect dimensions
|
|
185
|
+
const height = getNumber(d, config.lineWidth, i);
|
|
186
|
+
const width = xScale(x + length) - xScale(x);
|
|
187
|
+
if (width < 0) {
|
|
398
188
|
console.warn('Unovis | Timeline: Line segments should not have negative lengths. Setting to 0.');
|
|
399
189
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
190
|
+
select(elements[i])
|
|
191
|
+
.attr('x', xScale(x))
|
|
192
|
+
.attr('y', yStart + y + (config.rowHeight - height) / 2)
|
|
193
|
+
.attr('width', config.showEmptySegments
|
|
194
|
+
? Math.max(config.lineCap ? height : 1, width)
|
|
195
|
+
: Math.max(0, width))
|
|
196
|
+
.attr('height', height)
|
|
197
|
+
.attr('rx', config.lineCap ? height / 2 : null);
|
|
408
198
|
});
|
|
409
199
|
}
|
|
410
|
-
_prepareArrowsData(data, rowOrdinalScale, rowHeight) {
|
|
411
|
-
var _a;
|
|
412
|
-
const { config } = this;
|
|
413
|
-
const arrowsData = (_a = config.arrows) === null || _a === void 0 ? void 0 : _a.map(a => {
|
|
414
|
-
var _a, _b, _c, _d, _e;
|
|
415
|
-
const sourceLineIndex = data.findIndex((d, i) => getString(d, config.id, i) === a.lineSourceId);
|
|
416
|
-
const targetLineIndex = data.findIndex((d, i) => getString(d, config.id, i) === a.lineTargetId);
|
|
417
|
-
const sourceLine = data[sourceLineIndex];
|
|
418
|
-
const targetLine = data[targetLineIndex];
|
|
419
|
-
if (!sourceLine || !targetLine) {
|
|
420
|
-
console.warn('Unovis | Timeline: Arrow references a non-existent line. Skipping...', a);
|
|
421
|
-
return undefined;
|
|
422
|
-
}
|
|
423
|
-
const sourceLineY = rowOrdinalScale(this._getRecordKey(sourceLine, sourceLineIndex)) * rowHeight + rowHeight / 2;
|
|
424
|
-
const targetLineY = rowOrdinalScale(this._getRecordKey(targetLine, targetLineIndex)) * rowHeight + rowHeight / 2;
|
|
425
|
-
const sourceLineWidth = this._getLineWidth(sourceLine, sourceLineIndex, rowHeight);
|
|
426
|
-
const targetLineWidth = this._getLineWidth(targetLine, targetLineIndex, rowHeight);
|
|
427
|
-
const x1 = (a.xSource
|
|
428
|
-
? this.xScale(a.xSource)
|
|
429
|
-
: this.xScale(getNumber(sourceLine, config.x, sourceLineIndex)) + this._getLineLength(sourceLine, sourceLineIndex)) + ((_a = a.xSourceOffsetPx) !== null && _a !== void 0 ? _a : 0);
|
|
430
|
-
const targetLineLength = this._getLineLength(targetLine, targetLineIndex);
|
|
431
|
-
const isTargetLineTooShort = config.showEmptySegments && config.lineCap && (targetLineLength < targetLineWidth);
|
|
432
|
-
const targetLineStart = this.xScale(getNumber(targetLine, config.x, targetLineIndex)) + (isTargetLineTooShort ? -targetLineWidth / 2 : 0);
|
|
433
|
-
const x2 = (a.xTarget ? this.xScale(a.xTarget) : targetLineStart) + ((_b = a.xTargetOffsetPx) !== null && _b !== void 0 ? _b : 0);
|
|
434
|
-
const isX2OutsideTargetLineStart = (x2 < targetLineStart) || (x2 > targetLineStart);
|
|
435
|
-
// Points array
|
|
436
|
-
const sourceMargin = (_c = a.lineSourceMarginPx) !== null && _c !== void 0 ? _c : TIMELINE_DEFAULT_ARROW_MARGIN;
|
|
437
|
-
const targetMargin = (_d = a.lineTargetMarginPx) !== null && _d !== void 0 ? _d : TIMELINE_DEFAULT_ARROW_MARGIN;
|
|
438
|
-
const y1 = sourceLineY < targetLineY ? sourceLineY + sourceLineWidth / 2 + sourceMargin : sourceLineY - sourceLineWidth / 2 - sourceMargin;
|
|
439
|
-
const y2 = sourceLineY < targetLineY ? targetLineY - targetLineWidth / 2 - targetMargin : targetLineY + targetLineWidth / 2 + targetMargin;
|
|
440
|
-
const arrowHeadLength = (_e = a.arrowHeadLength) !== null && _e !== void 0 ? _e : TIMELINE_DEFAULT_ARROW_HEAD_LENGTH;
|
|
441
|
-
const isForwardArrow = x1 < x2 && !isX2OutsideTargetLineStart;
|
|
442
|
-
const threshold = arrowHeadLength + (isForwardArrow ? targetMargin : 0);
|
|
443
|
-
const points = [[x1, y1]];
|
|
444
|
-
if (Math.abs(x2 - x1) > threshold) {
|
|
445
|
-
if (isForwardArrow) {
|
|
446
|
-
points.push([x1, (y1 + targetLineY) / 2]); // A dummy point to enable smooth transitions when arrows change
|
|
447
|
-
points.push([x1, targetLineY]);
|
|
448
|
-
points.push([x2 - targetMargin, targetLineY]);
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
const verticalOffset = Math.sign(targetLineY - sourceLineY) * (rowHeight / 4);
|
|
452
|
-
points.push([x1, y2 - verticalOffset]);
|
|
453
|
-
points.push([x2, y2 - verticalOffset]);
|
|
454
|
-
points.push([x2, y2]);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
const quarterOffset = (y2 - y1) / 4;
|
|
459
|
-
points.push([x1, y1 + quarterOffset]); // A dummy point to enable smooth transitions
|
|
460
|
-
points.push([x1, y1 + 3 * quarterOffset]); // A dummy point to enable smooth transitions
|
|
461
|
-
points.push([x1, y2]);
|
|
462
|
-
}
|
|
463
|
-
return Object.assign(Object.assign({}, a), { _points: points });
|
|
464
|
-
}).filter(Boolean);
|
|
465
|
-
return arrowsData;
|
|
466
|
-
}
|
|
467
|
-
_renderLines(selection) {
|
|
468
|
-
const { config } = this;
|
|
469
|
-
selection
|
|
470
|
-
.attr('width', d => d._lengthCorrected)
|
|
471
|
-
.attr('height', d => d._height)
|
|
472
|
-
.attr('rx', d => config.lineCap ? d._height / 2 : null);
|
|
473
|
-
}
|
|
474
200
|
_onScrollbarDrag(event) {
|
|
475
201
|
const yRange = this.yScale.range();
|
|
476
202
|
const yHeight = Math.abs(yRange[1] - yRange[0]);
|
|
@@ -493,40 +219,28 @@ class Timeline extends XYComponentCore {
|
|
|
493
219
|
this._scrollDistance += diff;
|
|
494
220
|
this._scrollDistance = Math.max(0, this._scrollDistance);
|
|
495
221
|
this._scrollDistance = Math.min(this._maxScroll, this._scrollDistance);
|
|
496
|
-
this._clipPath.attr('transform', `translate(0,${this._scrollDistance})`);
|
|
497
222
|
this._linesGroup.attr('transform', `translate(0,${-this._scrollDistance})`);
|
|
498
223
|
this._rowsGroup.attr('transform', `translate(0,${-this._scrollDistance})`);
|
|
499
224
|
this._labelsGroup.attr('transform', `translate(0,${-this._scrollDistance})`);
|
|
500
|
-
this._rowIconsGroup.attr('transform', `translate(0,${-this._scrollDistance})`);
|
|
501
|
-
this._arrowsGroup.attr('transform', `translate(0,${-this._scrollDistance})`);
|
|
502
225
|
const scrollBarPosition = (this._scrollDistance / this._maxScroll * (yHeight - this._scrollbarHeight)) || 0;
|
|
503
226
|
this._scrollBarHandle.attr('y', scrollBarPosition);
|
|
504
227
|
}
|
|
505
|
-
|
|
228
|
+
_getMaxLineWidth() {
|
|
506
229
|
var _a;
|
|
507
|
-
|
|
230
|
+
const { config, datamodel: { data } } = this;
|
|
231
|
+
return (_a = max(data, (d, i) => getNumber(d, config.lineWidth, i))) !== null && _a !== void 0 ? _a : 0;
|
|
508
232
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
return {
|
|
515
|
-
label: key,
|
|
516
|
-
formattedLabel: (_e = (_d = (_c = this.config).rowLabelFormatter) === null || _d === void 0 ? void 0 : _d.call(_c, key, items, i)) !== null && _e !== void 0 ? _e : key,
|
|
517
|
-
iconHref: icon === null || icon === void 0 ? void 0 : icon.href,
|
|
518
|
-
iconSize: icon === null || icon === void 0 ? void 0 : icon.size,
|
|
519
|
-
iconColor: icon === null || icon === void 0 ? void 0 : icon.color,
|
|
520
|
-
data: items,
|
|
521
|
-
};
|
|
522
|
-
});
|
|
523
|
-
return rowLabels;
|
|
233
|
+
_getRecordType(d, i) {
|
|
234
|
+
return getString(d, this.config.type) || `__${i}`;
|
|
235
|
+
}
|
|
236
|
+
_getRecordLabels(data) {
|
|
237
|
+
return data.map((d, i) => getString(d, this.config.type) || `${i + 1}`);
|
|
524
238
|
}
|
|
525
239
|
// Override the default XYComponent getXDataExtent method to take into account line lengths
|
|
526
240
|
getXDataExtent() {
|
|
527
241
|
const { config, datamodel } = this;
|
|
528
242
|
const min = getMin(datamodel.data, config.x);
|
|
529
|
-
const max = getMax(datamodel.data, (d, i) => { var _a
|
|
243
|
+
const max = getMax(datamodel.data, (d, i) => { var _a; return getNumber(d, config.x, i) + ((_a = getNumber(d, config.length, i)) !== null && _a !== void 0 ? _a : 0); });
|
|
530
244
|
return [min, max];
|
|
531
245
|
}
|
|
532
246
|
}
|