@spider-analyzer/timeline 4.0.3 → 5.0.1
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/CHANGELOG.md +80 -1
- package/README.md +275 -637
- package/dist/index.d.mts +132 -0
- package/dist/index.d.ts +132 -0
- package/dist/index.js +2913 -22
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2906 -0
- package/dist/index.mjs.map +1 -0
- package/dist/timeline.css +139 -0
- package/package.json +52 -15
- package/src/Cursor.jsx +5 -13
- package/src/TimeLine.tsx +994 -0
- package/src/TimeLineResizer.jsx +2 -8
- package/src/ToolTip.jsx +7 -7
- package/src/cursorElements/CursorIcon.jsx +6 -29
- package/src/cursorElements/CursorSelection.jsx +4 -19
- package/src/cursorElements/DragOverlay.jsx +2 -12
- package/src/cursorElements/LeftHandle.jsx +3 -19
- package/src/cursorElements/LeftToolTip.jsx +2 -7
- package/src/cursorElements/RightHandle.jsx +3 -19
- package/src/cursorElements/RightToolTip.jsx +4 -13
- package/src/cursorElements/ZoomIn.jsx +5 -25
- package/src/cursorElements/ZoomOut.jsx +4 -21
- package/src/cursorElements/utils.js +1 -1
- package/src/index.js +6 -0
- package/src/index.ts +158 -0
- package/src/moment-shim.ts +169 -0
- package/src/styles.ts +15 -0
- package/src/time.ts +52 -0
- package/src/timeLineElements/Button.jsx +5 -30
- package/src/timeLineElements/HistoToolTip.jsx +3 -17
- package/src/timeLineElements/Histogram.jsx +4 -16
- package/src/timeLineElements/Legend.jsx +2 -16
- package/src/timeLineElements/QualityLine.jsx +4 -11
- package/src/timeLineElements/Tools.jsx +1 -1
- package/src/timeLineElements/XAxis.jsx +5 -8
- package/src/timeLineElements/XGrid.jsx +3 -7
- package/src/timeLineElements/YAxis.jsx +4 -7
- package/src/timeLineElements/YGrid.jsx +2 -6
- package/src/timeLineElements/axesStyles.jsx +0 -49
- package/src/timeline.css +139 -0
- package/src/utils.ts +60 -0
- package/.babelrc +0 -8
- package/.gitlab-ci.yml +0 -27
- package/Makefile +0 -20
- package/dist/Cursor.js +0 -290
- package/dist/TimeLine.js +0 -1177
- package/dist/TimeLineResizer.js +0 -70
- package/dist/ToolTip.js +0 -43
- package/dist/cursorElements/CursorIcon.js +0 -98
- package/dist/cursorElements/CursorSelection.js +0 -179
- package/dist/cursorElements/DragOverlay.js +0 -168
- package/dist/cursorElements/LeftHandle.js +0 -95
- package/dist/cursorElements/LeftToolTip.js +0 -70
- package/dist/cursorElements/RightHandle.js +0 -95
- package/dist/cursorElements/RightToolTip.js +0 -75
- package/dist/cursorElements/ZoomIn.js +0 -93
- package/dist/cursorElements/ZoomOut.js +0 -67
- package/dist/cursorElements/commonStyles.js +0 -28
- package/dist/cursorElements/handleHistoHovering.js +0 -79
- package/dist/cursorElements/utils.js +0 -30
- package/dist/theme.js +0 -59
- package/dist/timeLineElements/Button.js +0 -101
- package/dist/timeLineElements/HistoToolTip.js +0 -78
- package/dist/timeLineElements/Histogram.js +0 -110
- package/dist/timeLineElements/Legend.js +0 -70
- package/dist/timeLineElements/QualityLine.js +0 -81
- package/dist/timeLineElements/Tools.js +0 -115
- package/dist/timeLineElements/XAxis.js +0 -76
- package/dist/timeLineElements/XGrid.js +0 -47
- package/dist/timeLineElements/YAxis.js +0 -60
- package/dist/timeLineElements/YGrid.js +0 -46
- package/dist/timeLineElements/axesStyles.js +0 -57
- package/src/TimeLine.jsx +0 -1163
- package/src/cursorElements/commonStyles.js +0 -21
package/README.md
CHANGED
|
@@ -1,739 +1,377 @@
|
|
|
1
1
|
# TimeLine
|
|
2
2
|
|
|
3
|
-
React graphical component to display
|
|
3
|
+
React graphical component to display metrics over time with an interactive
|
|
4
|
+
time-selection cursor, zoom, pan, and an optional quality line.
|
|
5
|
+
|
|
4
6
|
- Drag & pan to shift time
|
|
5
|
-
- Scroll to zoom
|
|
6
|
-
- Drag to move, resize or redraw time selection
|
|
7
|
-
-
|
|
8
|
-
-
|
|
7
|
+
- Scroll to zoom
|
|
8
|
+
- Drag to move, resize or redraw the time selection
|
|
9
|
+
- Built-in zoom-out undo (no host-managed stack required)
|
|
10
|
+
- Themable through plain CSS classes — no CSS-in-JS peer dep
|
|
9
11
|
|
|
10
12
|
Live example: https://timeline.oss.spider-analyzer.io
|
|
11
13
|
|
|
12
14
|
![alt text][example]
|
|
13
|
-
|
|
14
15
|
![alt text][styled]
|
|
15
16
|
|
|
16
17
|
## Content
|
|
18
|
+
|
|
17
19
|
- [Features](#features)
|
|
18
|
-
* [Displaying metrics](#displaying-metrics)
|
|
19
|
-
* [Quality line](#quality-line)
|
|
20
|
-
* [Selecting time](#selecting-time)
|
|
21
|
-
* [Zooming](#zooming)
|
|
22
|
-
* [Dragging the domain](#dragging-the-domain)
|
|
23
|
-
* [Buttons](#buttons)
|
|
24
|
-
* [Limits when refreshing](#limits-when-refreshing)
|
|
25
20
|
- [Design considerations](#design-considerations)
|
|
26
|
-
- [
|
|
21
|
+
- [Installation](#installation)
|
|
22
|
+
- [Integration example](#integration-example)
|
|
27
23
|
- [Props](#props)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* [xAxis](#xaxis)
|
|
33
|
-
* [yAxis](#yaxis)
|
|
34
|
-
* [timeSpan](#timespan)
|
|
35
|
-
* [histo](#histo)
|
|
36
|
-
* [showHistoToolTip](#showhistotooltip)
|
|
37
|
-
* [HistoToolTip](#HistoToolTip)
|
|
38
|
-
* [quality](#quality)
|
|
39
|
-
* [qualityScale](#qualityscale)
|
|
40
|
-
* [zoomOutFactor](#zoomoutfactor)
|
|
41
|
-
* [domains](#domains)
|
|
42
|
-
* [maxDomain](#maxdomain)
|
|
43
|
-
* [metricsDefinition](#metricsdefinition)
|
|
44
|
-
* [biggestVisibleDomain](#biggestvisibledomain)
|
|
45
|
-
* [biggestTimeSpan](#biggesttimespan)
|
|
46
|
-
* [smallestResolution](#smallestresolution)
|
|
47
|
-
* [labels](#labels)
|
|
48
|
-
* [showLegend](#showlegend)
|
|
49
|
-
* [tools](#tools)
|
|
50
|
-
* [fetchWhileSliding](#fetchwhilesliding)
|
|
51
|
-
* [selectBarOnClick](#selectbaronclick)
|
|
52
|
-
- [Actions](#actions)
|
|
53
|
-
* [onLoadDefaultDomain()](#onloaddefaultdomain)
|
|
54
|
-
* [onLoadHisto(intervalMs: number, start: Moment, end: Moment)](#onloadhistointervalms-number-start-moment-end-moment)
|
|
55
|
-
* [onCustomRange(start: Moment, stop: Moment)](#oncustomrangestart-moment-stop-moment)
|
|
56
|
-
* [onShowMessage(msg: string)](#onshowmessagemsg-string)
|
|
57
|
-
* [onUpdateDomains(domains: arrayOf({min: Moment, max: Moment}))](#onupdatedomainsdomains-arrayofmin-moment-max-moment)
|
|
58
|
-
* [onResetTime()](#onresettime)
|
|
59
|
-
* [onFormatTimeToolTips(time: Moment) :string](#onformattimetooltipstime-moment-string)
|
|
60
|
-
* [onFormatTimeLegend(time: Date) :string](#onformattimelegendtime-date-string)
|
|
61
|
-
* [onFormatMetricLegend(value: number) :string](#onformatmetriclegendvalue-number-string)
|
|
62
|
-
- [Public functions](#public-functions)
|
|
63
|
-
* [zoomIn()](#zoomin)
|
|
64
|
-
* [zoomOut()](#zoomout)
|
|
65
|
-
* [shiftTimeLine(number)](#shifttimelinenumber)
|
|
24
|
+
- [Callbacks](#callbacks)
|
|
25
|
+
- [Imperative API](#imperative-api)
|
|
26
|
+
- [Styling](#styling)
|
|
27
|
+
- [Migrating from v4](#migrating-from-v4)
|
|
66
28
|
- [Testing / Dev](#testing--dev)
|
|
67
29
|
- [Dependencies](#dependencies)
|
|
68
|
-
- [ToDo](#todo)
|
|
69
|
-
- [Trello dashboard](#trello-dashboard)
|
|
70
30
|
|
|
71
31
|
## Features
|
|
72
32
|
|
|
73
33
|
### Displaying metrics
|
|
74
|
-
- TimeLine displays the evolution of metric(s) through time
|
|
75
|
-
- The time displayed has a min and max time, called hereunder a `domain
|
|
76
|
-
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- Order of metrics must be the same in `metricsDefinition.legend[]`, `metricsDefinition.colors[]` and `histo.items[].metrics[]`
|
|
82
|
-
- Names of the metrics are defined in `metricsDefinition.legend[]`, and displayed left to the chart
|
|
83
|
-
- The maximum value in the domain is displayed at the top of the y axis
|
|
84
|
-
- Current time is displayed by a vertical arrow on the x axis
|
|
34
|
+
- TimeLine displays the evolution of metric(s) through time.
|
|
35
|
+
- The time displayed has a min and max time, called hereunder a `domain`.
|
|
36
|
+
- 1 to n stacked metrics per bar — defined by `metricsDefinition`.
|
|
37
|
+
- Colors of the histogram bars are defined in `metricsDefinition.colors[]`.
|
|
38
|
+
- Metric names are displayed to the left of the chart.
|
|
39
|
+
- The maximum value in the visible window is shown at the top of the y-axis.
|
|
40
|
+
- Current time is displayed as a vertical arrow on the x-axis.
|
|
85
41
|
|
|
86
42
|
### Quality line
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
- A color scale renders the quality in different color depending on the value
|
|
91
|
-
- A custom tip can be displayed for each distinct slot
|
|
43
|
+
- Optional secondary line below the chart showing a per-slot quality value.
|
|
44
|
+
- May have its own x-axis granularity, independent of the histogram.
|
|
45
|
+
- Custom tooltip content per slot.
|
|
92
46
|
|
|
93
47
|
### Selecting time
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
- The cursor can be moved by drag an drop
|
|
98
|
-
- If moved outside the domain, the domain is adjusted (shifted)
|
|
99
|
-
- The cursor displays tooltips to show start and stop of time selection
|
|
100
|
-
- The cursor can be re-drawn by click and dragging over the chart
|
|
101
|
-
- When clicking outside the cursor
|
|
102
|
-
- When clicking below the cursor
|
|
48
|
+
- The cursor has handles to resize it via drag-and-drop.
|
|
49
|
+
- If dragged outside the domain, the domain shifts.
|
|
50
|
+
- Cursor can be redrawn by clicking and dragging over the chart.
|
|
103
51
|
|
|
104
52
|
### Zooming
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- **Click** on the zoom-in icon at the top right corner of the time selection cursor.
|
|
111
|
-
- The TimeLine is zoomed over the selected area.
|
|
112
|
-
- TimeLine can be zoomed out:
|
|
113
|
-
- **Scroll down** with the mouse over the graph.
|
|
114
|
-
- **Click** on the zoom-in icon at the right corner of the x axis.
|
|
115
|
-
- At start, zooming out is done using `zoomOutFactor`
|
|
116
|
-
- Once zoomed in, zooming out reverts the last zoom level
|
|
53
|
+
- **Scroll** — zooms on the mouse position (factor 4 on zoom-in).
|
|
54
|
+
- **Double-click** on the cursor — zooms over the selection.
|
|
55
|
+
- **Zoom-in/out icons** on the cursor / x-axis.
|
|
56
|
+
- **Zoom-out undo** — zooming out after zooming in returns to the exact
|
|
57
|
+
previous view (internal breadcrumb, transparent to the host).
|
|
117
58
|
|
|
118
59
|
Limits:
|
|
119
|
-
- Zoom-in
|
|
120
|
-
- Zoom-out
|
|
121
|
-
|
|
60
|
+
- Zoom-in stops at 15 px = `smallestResolution`.
|
|
61
|
+
- Zoom-out stops at `biggestVisibleDomain`.
|
|
62
|
+
|
|
122
63
|
### Dragging the domain
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
- The zoom levels above this one are adjusted if the min/max gets beyond their limits. For better U/X.
|
|
64
|
+
- `Ctrl` + drag shifts the visible window.
|
|
65
|
+
- Respects `maxDomain` if set.
|
|
126
66
|
|
|
127
67
|
### Buttons
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
- Reset the chart: getting back to initial zoom level.
|
|
131
|
-
- Goto now: Move the domain and time selection to select current time.
|
|
68
|
+
- Double arrow icons on either side of the x-axis slide the domain.
|
|
69
|
+
- Right-side icons: reset, goto-now.
|
|
132
70
|
|
|
133
|
-
###
|
|
134
|
-
-
|
|
135
|
-
-
|
|
71
|
+
### Data refresh limits
|
|
72
|
+
- Zoom is disabled while a fetch is in progress.
|
|
73
|
+
- Resize triggers a refresh only every 30 px — avoids flooding the API.
|
|
136
74
|
|
|
137
75
|
## Design considerations
|
|
138
|
-
TimeLine is design for integration in time series or operational data reporting and display.
|
|
139
|
-
It is perfectly suited for integration aside a grid of records to define the time range of records to display.
|
|
140
|
-
|
|
141
|
-
When integrating the TimeLine in your project, you have to define:
|
|
142
|
-
- The metrics to display, their colors and legend: `metricsDefinition`
|
|
143
|
-
- The default domain to display on load: `domains[0]` loaded by `onLoadDefaultDomain`
|
|
144
|
-
- The absolute minimum and maximum time to display (optional): `maxDomain`
|
|
145
|
-
- The limit in duration of a visible domain (optional): `biggestVisibleDomain`
|
|
146
|
-
- The smallest resolution unit of the time displayed: `smallestResolution`
|
|
147
|
-
- What to do when resetting time: `onResetTime`.
|
|
148
|
-
- Default expected behavior would be to execute `onLoadDefaultDomain` and reset the domains.
|
|
149
|
-
- How to display time:
|
|
150
|
-
- On x axis: `onFormatTimeLegend`
|
|
151
|
-
- In tooltips: `onFormatTimeToolTips`
|
|
152
|
-
- How to display metric value on y axis: `onFormatMetricLegend`
|
|
153
|
-
- If selected time should be rounded.
|
|
154
|
-
|
|
155
|
-
Default resolution is millisecond, the time may rounded outside TimeLine component to second, minute or so.
|
|
156
|
-
- To do this, adjust `onCustomRange`, `onLoadDefaultDomain`, `onLoadHisto` functions, as shown in demo.
|
|
157
|
-
- `smallestResolution` and `onFormatTimeToolTips` should be adjusted in consequence.
|
|
158
|
-
|
|
159
|
-
You may also redefine labels displayed: `labels`
|
|
160
|
-
|
|
161
|
-
## Integration
|
|
162
|
-
Install using npm or your favorite tool.
|
|
163
76
|
|
|
164
|
-
|
|
77
|
+
TimeLine is designed for integration into time-series and operational
|
|
78
|
+
reporting UIs. It pairs naturally with a grid of records, using the
|
|
79
|
+
cursor to select the time range of interest.
|
|
165
80
|
|
|
166
|
-
|
|
81
|
+
When integrating, you define:
|
|
167
82
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
83
|
+
- Metrics to display + their colors and legend: `metricsDefinition`.
|
|
84
|
+
- The initial window: return it from `onLoadDefaultDomain`, or pass it
|
|
85
|
+
directly as `domain`.
|
|
86
|
+
- Optional outer bounds: `maxDomain`.
|
|
87
|
+
- Zoom limits: `biggestVisibleDomain`, `smallestResolution`.
|
|
88
|
+
- Reset behavior: `onResetTime` (typically clears `domain` so the
|
|
89
|
+
component re-asks for a default).
|
|
90
|
+
- Formatters for x-axis, tooltips, and metric values.
|
|
91
|
+
- Required time zone (IANA name): `timeZone`.
|
|
172
92
|
|
|
93
|
+
## Installation
|
|
173
94
|
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
className={'timeLine'}
|
|
177
|
-
timeSpan = {this.state.timeSpan} //start and stop of selection
|
|
178
|
-
histo = {{
|
|
179
|
-
items: this.state.items, // table of histo columns: [{time: moment, metrics: [metric1 value, metric2 value...], total: sum of metrics}, ...]
|
|
180
|
-
intervalMs: this.state.intervalMs //interval duration of column in ms
|
|
181
|
-
}}
|
|
182
|
-
showHistoToolTip
|
|
183
|
-
quality = {{
|
|
184
|
-
items: this.state.quality, //table of quality indicators [{time: moment, quality: float [0,1], tip: string}]
|
|
185
|
-
intervalMin: this.state.intervalMin //interval duration of column in Min
|
|
186
|
-
}}
|
|
187
|
-
qualityScale = {
|
|
188
|
-
scaleLinear()
|
|
189
|
-
.domain([0,1])
|
|
190
|
-
.range(['red','green'])
|
|
191
|
-
.clamp(true)
|
|
192
|
-
} //color scale (optional)
|
|
193
|
-
zoomOutFactor = {1.75} //zoom out factor if never zoomed in
|
|
194
|
-
domains = {this.state.domains} //array of zoom levels
|
|
195
|
-
maxDomain = {this.state.maxDomain} //max zoom level allowed
|
|
196
|
-
metricsDefinition = {metricsDefinition}
|
|
197
|
-
biggestVisibleDomain = {moment.duration('P1M')} //maximum visible duration, cannot zoom out further
|
|
198
|
-
biggestTimeSpan = {moment.duration('P1D')} //maximum duration that can be selected
|
|
199
|
-
smallestResolution = {moment.duration('PT1M')} //max zoom level: 15pixels = duration
|
|
200
|
-
labels={{
|
|
201
|
-
backwardButtonTip: 'Slide into the past'
|
|
202
|
-
}}
|
|
203
|
-
tools={{
|
|
204
|
-
gotoNow: false
|
|
205
|
-
}}
|
|
206
|
-
showLegend
|
|
207
|
-
fetchWhileSliding
|
|
208
|
-
selectBarOnClick
|
|
209
|
-
|
|
210
|
-
onLoadDefaultDomain = {this.onLoadDefaultDomain} //called on mount to get the default domain
|
|
211
|
-
onLoadHisto = {this.onLoadHisto} //called to load items. give the needed interval, computed from props.width, props.domains[0]
|
|
212
|
-
onCustomRange = {this.onCustomRange} //called when user has drawn or resized the cursor
|
|
213
|
-
onShowMessage = {console.log} //called to display an error message
|
|
214
|
-
onUpdateDomains = {this.onUpdateDomains} //called to save domains
|
|
215
|
-
onResetTime = {this.onResetTime} //called when user want to reset timeline
|
|
216
|
-
onFormatTimeToolTips = {this.onFormatTimeToolTips} //called to display time in tooltips
|
|
217
|
-
onFormatTimeLegend = {multiFormat} //called to format x axis legend
|
|
218
|
-
onFormatMetricLegend = {formatNumber} //called to format y axis metric legend
|
|
219
|
-
/>
|
|
95
|
+
```sh
|
|
96
|
+
npm install --save @spider-analyzer/timeline
|
|
220
97
|
```
|
|
221
98
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
## Props
|
|
225
|
-
### className
|
|
226
|
-
Main class used in the `<div/>` encapsulating the svg graphic.
|
|
227
|
-
The width and height of the chart should be defined there. In % or strict dimensions.
|
|
228
|
-
When resizing the window, the chart will adapt.
|
|
229
|
-
|
|
230
|
-
### classes
|
|
231
|
-
Allows to override any classes used by the component.
|
|
232
|
-
|
|
233
|
-
To be used by a CSS-in-JS solution, are by listing classes from your own CSS.
|
|
234
|
-
To find the classes to update... best is to play with developer tools ;)
|
|
235
|
-
|
|
236
|
-
### rcToolTipPrefixCls
|
|
237
|
-
Allows changing the class prefix for rc-tooltip
|
|
99
|
+
Import the stylesheet once in your entry:
|
|
238
100
|
|
|
239
|
-
### margin
|
|
240
|
-
Allows to adjust the margin around the graphic area.
|
|
241
|
-
|
|
242
|
-
The metrics legend, and time legend are rendered inside the margin.
|
|
243
|
-
|
|
244
|
-
```js
|
|
245
|
-
margin: PropTypes.shape({
|
|
246
|
-
left: PropTypes.number,
|
|
247
|
-
right: PropTypes.number,
|
|
248
|
-
top: PropTypes.number,
|
|
249
|
-
bottom: PropTypes.number,
|
|
250
|
-
})
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### xAxis
|
|
254
|
-
Allows customising the xAxis (time):
|
|
255
|
-
- arrowPath: SVG path of the arrow
|
|
256
|
-
- spaceBetweenTicks: How many pixels between two points in the x grid / legend
|
|
257
|
-
- barsBetweenTicks: How many histogram bar do you want between ticks
|
|
258
|
-
- showGrid: Displays vertical lines for each tick (default: no)
|
|
259
|
-
- height: Height of the axis (useful if you change the text style ;))
|
|
260
|
-
|
|
261
|
-
spaceBetweenTicks and spaceBetweenTicks are used to compute the resolution 'interval' of the onLoadHisto function.
|
|
262
|
-
|
|
263
|
-
```js
|
|
264
|
-
xAxis: PropTypes.shape({
|
|
265
|
-
arrowPath: PropTypes.string,
|
|
266
|
-
spaceBetweenTicks: PropTypes.number.isRequired,
|
|
267
|
-
barsBetweenTicks: PropTypes.number.isRequired,
|
|
268
|
-
showGrid: PropTypes.bool,
|
|
269
|
-
height: PropTypes.number,
|
|
270
|
-
})
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### yAxis
|
|
274
|
-
Allows customising the yAxis (metrics):
|
|
275
|
-
- arrowPath: SVG path of the arrow
|
|
276
|
-
- spaceBetweenTicks: How many pixels between two points in the x grid / legend
|
|
277
|
-
- showGrid: Displays horizontal lines for each tick (default: no)
|
|
278
|
-
|
|
279
|
-
```js
|
|
280
|
-
yAxis: PropTypes.shape({
|
|
281
|
-
path: PropTypes.string,
|
|
282
|
-
spaceBetweenTicks: PropTypes.number.isRequired,
|
|
283
|
-
showGrid: PropTypes.bool,
|
|
284
|
-
})
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### timeSpan
|
|
288
|
-
Defines the start and stop of the selected time window.
|
|
289
|
-
```js
|
|
290
|
-
timeSpan: PropTypes.shape({
|
|
291
|
-
start: PropTypes.instanceOf(moment).isRequired,
|
|
292
|
-
stop: PropTypes.instanceOf(moment).isRequired
|
|
293
|
-
}).isRequired
|
|
294
|
-
```
|
|
295
|
-
Ex:
|
|
296
101
|
```js
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
stop: moment().add(1, 'HOUR'),
|
|
300
|
-
}
|
|
102
|
+
import '@spider-analyzer/timeline/dist/timeline.css';
|
|
103
|
+
import '@spider-analyzer/timeline/dist/tipDark.css';
|
|
301
104
|
```
|
|
302
105
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
/!\ items and intervalMs have to be provided in sync.
|
|
307
|
-
|
|
308
|
-
When loading new items when processing [onLoadHisto](#onloadhistointervalms-number-start-moment-end-moment), both intervalMs and items must be
|
|
309
|
-
given back together. That's why they are in same prop.
|
|
310
|
-
If intervalMs is not consistent with items own duration 'interval', then you'll have an ugly
|
|
311
|
-
glitch when zooming out and resizing. And wrong information display when zooming in.
|
|
106
|
+
No moment / MUI / lodash peer deps. `luxon` is declared as a
|
|
107
|
+
dependency but is already on most modern React apps; if not, npm will
|
|
108
|
+
pull it in transitively.
|
|
312
109
|
|
|
313
|
-
|
|
314
|
-
than the loading request itself.
|
|
110
|
+
## Integration example
|
|
315
111
|
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
intervalMs:
|
|
324
|
-
}
|
|
112
|
+
```jsx
|
|
113
|
+
<TimeLine
|
|
114
|
+
className="my-timeline"
|
|
115
|
+
timeZone="Europe/Paris" /* required */
|
|
116
|
+
timeSpan={this.state.timeSpan} /* { start: Date, stop: Date } */
|
|
117
|
+
histo={{
|
|
118
|
+
items: this.state.items, /* [{ time: Date, metrics: number[], total: number }] */
|
|
119
|
+
intervalMs: this.state.intervalMs, /* number */
|
|
120
|
+
}}
|
|
121
|
+
showHistoToolTip
|
|
122
|
+
quality={{
|
|
123
|
+
items: this.state.quality, /* [{ time: Date, quality: 0..1, tip?: ReactNode }] */
|
|
124
|
+
intervalMin: this.state.intervalMin,
|
|
125
|
+
}}
|
|
126
|
+
zoomOutFactor={1.75}
|
|
127
|
+
domain={this.state.domain} /* { min: Date, max: Date } | null */
|
|
128
|
+
maxDomain={this.state.maxDomain}
|
|
129
|
+
metricsDefinition={metricsDefinition}
|
|
130
|
+
biggestVisibleDomain={30 * 24 * 60 * 60 * 1000} /* 1 month in ms */
|
|
131
|
+
biggestTimeSpan={24 * 60 * 60 * 1000} /* 1 day in ms */
|
|
132
|
+
smallestResolution={60 * 1000} /* 1 minute in ms */
|
|
133
|
+
labels={{ backwardButtonTip: 'Slide into the past' }}
|
|
134
|
+
tools={{ gotoNow: false }}
|
|
135
|
+
showLegend
|
|
136
|
+
fetchWhileSliding
|
|
137
|
+
selectBarOnClick
|
|
138
|
+
|
|
139
|
+
onLoadDefaultDomain={this.onLoadDefaultDomain} /* returns Domain | Promise<Domain> */
|
|
140
|
+
onLoadHisto={this.onLoadHisto} /* ({ intervalMs, start, end }) */
|
|
141
|
+
onTimeSpanChange={this.onTimeSpanChange} /* ({ start, stop }) */
|
|
142
|
+
onShowMessage={console.log}
|
|
143
|
+
onDomainChange={this.onDomainChange} /* (domain) */
|
|
144
|
+
onResetTime={this.onResetTime}
|
|
145
|
+
onFormatTimeToolTips={this.onFormatTimeToolTips}
|
|
146
|
+
onFormatTimeLegend={multiFormat}
|
|
147
|
+
onFormatMetricLegend={formatNumber}
|
|
148
|
+
/>
|
|
325
149
|
```
|
|
326
150
|
|
|
327
|
-
|
|
328
|
-
When true, timeline will display a tooltip when hover the histogram stacked bars.
|
|
329
|
-
|
|
330
|
-
The tooltip lists the time slot and the different metrics values for the bar.
|
|
331
|
-
It may be customized by providing a custom `HistoToolTip` component.
|
|
151
|
+
TimeLine is a controlled component.
|
|
332
152
|
|
|
333
|
-
|
|
334
|
-
showHistoToolTip: PropTypes.bool
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### HistoToolTip
|
|
338
|
-
React component to replace and customize the histogram tooltips content.
|
|
153
|
+
## Props
|
|
339
154
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
155
|
+
| Prop | Type | Required | Notes |
|
|
156
|
+
|------------------------|-------------------------------------------------------------------------------------------|----------|--------------------------------------------------------------------------------|
|
|
157
|
+
| `timeZone` | `string` (IANA) | yes | Threads into the internal tz-aware time engine for formatting. |
|
|
158
|
+
| `domain` | `{ min: Date, max: Date } \| null` | yes | Pass `null` on first render to defer to `onLoadDefaultDomain`. |
|
|
159
|
+
| `timeSpan` | `{ start: Date, stop: Date }` | yes | The cursor selection. |
|
|
160
|
+
| `histo` | `{ items: HistoItem[], intervalMs: number \| null }` | yes | `items[].time` is `Date`. `items` and `intervalMs` MUST be updated atomically. |
|
|
161
|
+
| `metricsDefinition` | `{ count, legends, colors }` | yes | See example below. |
|
|
162
|
+
| `maxDomain` | `{ min?: Date, max?: Date }` | no | Hard outer bounds for pan. |
|
|
163
|
+
| `biggestVisibleDomain` | `number` (ms) | no | Max visible window; caps zoom-out. |
|
|
164
|
+
| `biggestTimeSpan` | `number` (ms) | no | Max selectable cursor span. |
|
|
165
|
+
| `smallestResolution` | `number` (ms) | yes | Floor for zoom-in (15 px == this duration). |
|
|
166
|
+
| `quality` | `{ items: QualityItem[], intervalMin?: number }` | no | Optional quality line below the chart. |
|
|
167
|
+
| `qualityScale` | `(q: number) => string` | no | Color for a quality value. Defaults to a red→green scale. |
|
|
168
|
+
| `zoomOutFactor` | `number` | no | Default 1.25. Used only when the internal breadcrumb is empty. |
|
|
169
|
+
| `showHistoToolTip` | `boolean` | no | |
|
|
170
|
+
| `HistoToolTip` | React component | no | Custom tooltip content — see below. |
|
|
171
|
+
| `className` | `string` | no | Applied to the outer container. |
|
|
172
|
+
| `classes` | `Record<slot, string>` | no | Override per-slot class names. See [Styling](#styling). |
|
|
173
|
+
| `rcToolTipPrefixCls` | `string` | no | Override rc-tooltip class prefix. |
|
|
174
|
+
| `margin` | `{ left?, right?, top?, bottom? }` numbers | no | |
|
|
175
|
+
| `xAxis`, `yAxis` | axis config objects (see below) | no | |
|
|
176
|
+
| `tools` | `{ slideForward?, slideBackward?, resetTimeline?, gotoNow?, cursor?, zoomIn?, zoomOut? }` | no | Toggle individual tools. |
|
|
177
|
+
| `fetchWhileSliding` | `boolean` | no | Refetch while panning. |
|
|
178
|
+
| `selectBarOnClick` | `boolean` | no | Clicking a histogram bar snaps the cursor to it. |
|
|
179
|
+
| `labels` | `Record<string, string>` | no | Translations / message overrides. |
|
|
180
|
+
| `showLegend` | `boolean` | no | Defaults to `true`. |
|
|
181
|
+
|
|
182
|
+
`xAxis` / `yAxis`:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
xAxis?: {
|
|
186
|
+
arrowPath?: string;
|
|
187
|
+
spaceBetweenTicks: number;
|
|
188
|
+
barsBetweenTicks: number;
|
|
189
|
+
showGrid?: boolean;
|
|
190
|
+
height?: number;
|
|
191
|
+
};
|
|
192
|
+
yAxis?: {
|
|
193
|
+
arrowPath?: string;
|
|
194
|
+
spaceBetweenTicks?: number;
|
|
195
|
+
showGrid?: boolean;
|
|
355
196
|
};
|
|
356
197
|
```
|
|
357
198
|
|
|
358
|
-
|
|
359
|
-
Provides the data to display on the quality line.
|
|
360
|
-
```js
|
|
361
|
-
quality: PropTypes.shape({
|
|
362
|
-
items: PropTypes.arrayOf(PropTypes.shape({
|
|
363
|
-
time: PropTypes.instanceOf(moment).isRequired, //time of quality slot
|
|
364
|
-
quality: PropTypes.number.isRequired, //quality of the slot
|
|
365
|
-
tip: PropTypes.node, //text to display in tooltip - optional
|
|
366
|
-
})),
|
|
367
|
-
intervalMin: PropTypes.number //duration of each slot (in minutes)
|
|
368
|
-
})
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
### qualityScale
|
|
372
|
-
Allows to override the color scale for the quality line.
|
|
373
|
-
Expects a function converting a quality number into a CSS color.
|
|
374
|
-
```js
|
|
375
|
-
qualityScale: PropTypes.func
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### zoomOutFactor
|
|
379
|
-
Allows to override the default zoom factor (1.25) for zooming out
|
|
380
|
-
when never zoomed in before.
|
|
381
|
-
|
|
382
|
-
Should be > 1 ;)
|
|
383
|
-
|
|
384
|
-
```js
|
|
385
|
-
zoomOutFactor: PropTypes.number
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### domains
|
|
389
|
-
Stores/defines the actual zooms levels of the timeline.
|
|
390
|
-
```js
|
|
391
|
-
domains: PropTypes.arrayOf(PropTypes.shape({
|
|
392
|
-
min: PropTypes.instanceOf(moment).isRequired,
|
|
393
|
-
max: PropTypes.instanceOf(moment).isRequired
|
|
394
|
-
})).isRequired
|
|
395
|
-
```
|
|
396
|
-
- min and max are the visual bounds of the TimeLine
|
|
397
|
-
- When zooming in/out, `onUpdateDomains` is called with an update of the domains.
|
|
398
|
-
- On mount, the timeline calls `onLoadDefaultDomain` that should be used to define the initial domain.
|
|
199
|
+
`metricsDefinition`:
|
|
399
200
|
|
|
400
|
-
Ex:
|
|
401
201
|
```js
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
```js
|
|
411
|
-
maxDomain: PropTypes.shape({
|
|
412
|
-
min: PropTypes.instanceOf(moment).isRequired,
|
|
413
|
-
max: PropTypes.instanceOf(moment).isRequired
|
|
414
|
-
})
|
|
415
|
-
```
|
|
416
|
-
Ex:
|
|
417
|
-
```js
|
|
418
|
-
maxDomain = {
|
|
419
|
-
min: moment().subtract(2, 'MONTHS').startOf('DAY'),
|
|
420
|
-
max: moment().add(1, 'WEEK').endOf('DAY')
|
|
202
|
+
{
|
|
203
|
+
count: 3,
|
|
204
|
+
legends: ['Info', 'Warn', 'Fail'],
|
|
205
|
+
colors: [
|
|
206
|
+
{ fill: '#9be18c', stroke: '#5db352', text: '#5db352' },
|
|
207
|
+
{ fill: '#f6bc62', stroke: '#e69825', text: '#e69825' },
|
|
208
|
+
{ fill: '#ff5d5a', stroke: '#f6251e', text: '#f6251e' },
|
|
209
|
+
],
|
|
421
210
|
}
|
|
422
211
|
```
|
|
423
212
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
legends: ['Info', 'Warn', 'Fail'], //Name of the metrics, in order. Will be displayed left of the chart
|
|
442
|
-
colors: [{ //Colors of the metrics, in order: fill of bar, stroke of bar, text in legend
|
|
443
|
-
fill: '#9be18c',
|
|
444
|
-
stroke: '#5db352',
|
|
445
|
-
text: '#5db352'
|
|
446
|
-
},
|
|
447
|
-
{
|
|
448
|
-
fill: '#f6bc62',
|
|
449
|
-
stroke: '#e69825',
|
|
450
|
-
text: '#e69825'
|
|
451
|
-
},{
|
|
452
|
-
fill: '#ff5d5a',
|
|
453
|
-
stroke: '#f6251e',
|
|
454
|
-
text: '#f6251e'
|
|
455
|
-
}]
|
|
456
|
-
}
|
|
213
|
+
Custom `HistoToolTip` props:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
HistoToolTip.propTypes = {
|
|
217
|
+
classes: object,
|
|
218
|
+
item: {
|
|
219
|
+
start: Date,
|
|
220
|
+
end: Date,
|
|
221
|
+
x1: number,
|
|
222
|
+
x2: number,
|
|
223
|
+
metrics: number[],
|
|
224
|
+
total: number,
|
|
225
|
+
},
|
|
226
|
+
metricsDefinition: object,
|
|
227
|
+
onFormatTimeToolTips: (time: Date) => ReactNode,
|
|
228
|
+
onFormatMetricLegend: (value: number) => string,
|
|
229
|
+
};
|
|
457
230
|
```
|
|
458
231
|
|
|
459
|
-
|
|
460
|
-
Defines the maximum visible duration of a domain, if any.
|
|
461
|
-
For instance, allows set a maxDomain of 1 year, but limit visible histogram to a window of 1 month.
|
|
462
|
-
Limits the overloading of the aggregation API.
|
|
463
|
-
```js
|
|
464
|
-
biggestVisibleDomain: PropTypes.object //expects a Duration created by moment.duration() object
|
|
465
|
-
```
|
|
466
|
-
Ex:
|
|
467
|
-
```js
|
|
468
|
-
biggestVisibleDomain = moment.duration('P1M')
|
|
469
|
-
```
|
|
232
|
+
## Callbacks
|
|
470
233
|
|
|
471
|
-
###
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
```
|
|
476
|
-
Ex:
|
|
477
|
-
```js
|
|
478
|
-
biggestTimeSpan = moment.duration('P1D')
|
|
479
|
-
```
|
|
234
|
+
### `onLoadDefaultDomain(): Domain | Promise<Domain> | void`
|
|
235
|
+
Called on mount when `domain` is `null`. Return the default domain
|
|
236
|
+
synchronously or asynchronously; the component seeds its internal stack
|
|
237
|
+
from the returned value and emits `onDomainChange` once resolved.
|
|
480
238
|
|
|
239
|
+
### `onLoadHisto({ intervalMs, start, end }): void`
|
|
240
|
+
Called when the component needs histogram data. Fires on mount (if the
|
|
241
|
+
domain is known), on domain changes, on width changes, and on pan if
|
|
242
|
+
`fetchWhileSliding` is set.
|
|
481
243
|
|
|
482
|
-
###
|
|
483
|
-
|
|
484
|
-
```js
|
|
485
|
-
smallestResolution: PropTypes.object.isRequired //expects a Duration created by moment.duration() object
|
|
486
|
-
```
|
|
487
|
-
Ex:
|
|
488
|
-
```js
|
|
489
|
-
smallestResolution = moment.duration('PT1M')
|
|
490
|
-
```
|
|
244
|
+
### `onTimeSpanChange({ start, stop }): void`
|
|
245
|
+
Called when the user resizes, moves, or redraws the cursor.
|
|
491
246
|
|
|
492
|
-
###
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
```js
|
|
496
|
-
labels: PropTypes.shape({
|
|
497
|
-
forwardButtonTip: PropTypes.string,
|
|
498
|
-
backwardButtonTip: PropTypes.string,
|
|
499
|
-
resetButtonTip: PropTypes.string,
|
|
500
|
-
gotoNowButtonTip: PropTypes.string,
|
|
501
|
-
doubleClickMaxZoomMsg: PropTypes.string,
|
|
502
|
-
zoomInWithoutChangingSelectionMsg: PropTypes.string,
|
|
503
|
-
zoomSelectionResolutionExtended: PropTypes.string,
|
|
504
|
-
maxSelectionMsg: PropTypes.string,
|
|
505
|
-
scrollMaxZoomMsg: PropTypes.string,
|
|
506
|
-
minZoomMsg: PropTypes.string,
|
|
507
|
-
maxDomainMsg: PropTypes.string,
|
|
508
|
-
minDomainMsg: PropTypes.string,
|
|
509
|
-
gotoCursor: PropTypes.string,
|
|
510
|
-
zoomInLabel: PropTypes.string,
|
|
511
|
-
zoomOutLabel: PropTypes.string,
|
|
512
|
-
})
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
Default:
|
|
516
|
-
```js
|
|
517
|
-
const defaultLabels = {
|
|
518
|
-
forwardButtonTip: 'Slide forward',
|
|
519
|
-
backwardButtonTip: 'Slide backward',
|
|
520
|
-
resetButtonTip: 'Reset time span',
|
|
521
|
-
gotoNowButtonTip: 'Goto Now',
|
|
522
|
-
doubleClickMaxZoomMsg: 'Cannot zoom anymore!',
|
|
523
|
-
zoomInWithoutChangingSelectionMsg: 'Please change time selection before clicking on zoom ;)',
|
|
524
|
-
zoomSelectionResolutionExtended: 'You reached maximum zoom level',
|
|
525
|
-
maxSelectionMsg: 'You reached maximum selection',
|
|
526
|
-
scrollMaxZoomMsg: 'Cannot zoom anymore!',
|
|
527
|
-
minZoomMsg: 'You reached minimum zoom level',
|
|
528
|
-
maxDomainMsg: 'You reached maximum visible time',
|
|
529
|
-
minDomainMsg: 'You reached minimum visible time',
|
|
530
|
-
gotoCursor: 'Goto Cursor',
|
|
531
|
-
zoomInLabel: 'Zoom in',
|
|
532
|
-
zoomOutLabel: 'Zoom out',
|
|
533
|
-
};
|
|
534
|
-
```
|
|
247
|
+
### `onDomainChange(domain): void`
|
|
248
|
+
Called whenever the visible domain changes — zoom in/out, pan, or a
|
|
249
|
+
cursor-triggered edge shift. Host updates its `domain` state.
|
|
535
250
|
|
|
536
|
-
###
|
|
537
|
-
|
|
251
|
+
### `onResetTime(): void`
|
|
252
|
+
Called when the user clicks the reset tool. Typical handler: clear the
|
|
253
|
+
host domain and let `onLoadDefaultDomain` re-seed.
|
|
538
254
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
255
|
+
### `onShowMessage(msg: ReactNode): void`
|
|
256
|
+
Called to display an informational or error message (e.g. "reached max
|
|
257
|
+
zoom").
|
|
542
258
|
|
|
543
|
-
###
|
|
544
|
-
|
|
545
|
-
|
|
259
|
+
### `onFormatTimeToolTips(time: Date): ReactNode`
|
|
260
|
+
Formats time for the cursor tooltips. Use your timezone library of
|
|
261
|
+
choice — the component passes a raw `Date`.
|
|
546
262
|
|
|
547
263
|
```js
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
resetTimeline: PropTypes.bool,
|
|
552
|
-
gotoNow: PropTypes.bool,
|
|
553
|
-
cursor: PropTypes.bool,
|
|
554
|
-
zoomIn: PropTypes.bool,
|
|
555
|
-
zoomOut: PropTypes.bool,
|
|
556
|
-
})
|
|
264
|
+
// With luxon
|
|
265
|
+
onFormatTimeToolTips = (time) =>
|
|
266
|
+
DateTime.fromJSDate(time).toFormat('yyyy-LL-dd HH:mm:ss');
|
|
557
267
|
```
|
|
558
268
|
|
|
559
|
-
###
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
fetchWhileSliding: PropTypes.bool
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
### selectBarOnClick
|
|
567
|
-
Defines if clicking on a bar of the histogram automatically switch the time selection to this bar.
|
|
568
|
-
```js
|
|
569
|
-
selectBarOnClick: PropTypes.bool
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
## Actions
|
|
573
|
-
|
|
574
|
-
### onLoadDefaultDomain()
|
|
575
|
-
Called on mount to get the default domain.
|
|
576
|
-
- Expected to initialize the `domains` prop.
|
|
577
|
-
- Usually with a single default domain `[{min: moment, max: moment}]`.
|
|
578
|
-
|
|
579
|
-
### onLoadHisto(intervalMs: number, start: Moment, end: Moment)
|
|
580
|
-
Called to load items. Give the needed interval, computed from props.width and props.domains[0].
|
|
581
|
-
- Expected to update the `histo` prop.
|
|
269
|
+
### `onFormatTimeLegend(time: Date): string`
|
|
270
|
+
Formats the x-axis tick. `time` is rounded to one of: millisecond,
|
|
271
|
+
second, minute, hour, day, month, year. Return a different string per
|
|
272
|
+
rounded level for readable ticks.
|
|
582
273
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
- domain change
|
|
586
|
-
- width change
|
|
587
|
-
- sliding if `fetchWhileSliding` prop is set
|
|
274
|
+
### `onFormatMetricLegend(value: number): string`
|
|
275
|
+
Formats a metric amount shown at the top of the y-axis.
|
|
588
276
|
|
|
589
|
-
|
|
590
|
-
- intervalsMs: Number - Milliseconds to use in the aggregation query
|
|
591
|
-
- start: Moment - Current domain min
|
|
592
|
-
- end: Moment - Current domain max
|
|
277
|
+
## Imperative API
|
|
593
278
|
|
|
594
|
-
|
|
595
|
-
Called when user has drawn or resized the cursor.
|
|
596
|
-
- Expected to update the `timeSpan` prop.
|
|
279
|
+
Three methods are exposed on the ref:
|
|
597
280
|
|
|
598
|
-
|
|
599
|
-
|
|
281
|
+
- `zoomIn()` — zooms to the current cursor selection.
|
|
282
|
+
- `zoomOut()` — pops the internal breadcrumb; if empty, expands by
|
|
283
|
+
`zoomOutFactor`.
|
|
284
|
+
- `shiftTimeLine(delta)` — animates the domain backward (`>0`) or
|
|
285
|
+
forward (`<0`) by `delta` pixels.
|
|
600
286
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
### onResetTime()
|
|
606
|
-
Called when user want to reset timeline.
|
|
607
|
-
- Expected to update the `domains` prop. Usually to a new array with only default domain.
|
|
608
|
-
- `domains[0]` is expected to be changed (new object) to trigger a new `onLoadHisto` call.
|
|
609
|
-
|
|
610
|
-
### onFormatTimeToolTips(time: Moment) :string
|
|
611
|
-
Called to display time in tooltips.
|
|
612
|
-
- Must return a formatted date as string.
|
|
613
|
-
|
|
614
|
-
Ex:
|
|
615
|
-
```js
|
|
616
|
-
onFormatTimeToolTips = (time) => {
|
|
617
|
-
return moment(time).second(0).millisecond(0).format(TIME_FORMAT_TOOLTIP);
|
|
618
|
-
};
|
|
287
|
+
```jsx
|
|
288
|
+
const ref = useRef();
|
|
289
|
+
<TimeLine ref={ref} ... />
|
|
290
|
+
<button onClick={() => ref.current.zoomIn()}>+</button>
|
|
619
291
|
```
|
|
620
292
|
|
|
621
|
-
|
|
622
|
-
Called to format the x axis legend. Depending of zoom resolution, the input will be a date rounded to:
|
|
623
|
-
- millisecond
|
|
624
|
-
- second
|
|
625
|
-
- minute
|
|
626
|
-
- hour
|
|
627
|
-
- day
|
|
628
|
-
- month
|
|
629
|
-
- year
|
|
630
|
-
|
|
293
|
+
## Styling
|
|
631
294
|
|
|
632
|
-
|
|
633
|
-
|
|
295
|
+
The library ships a single stylesheet (`dist/timeline.css`) whose rules
|
|
296
|
+
are keyed on `tl-<slot>` class names. Every SVG element also receives
|
|
297
|
+
any additional class you hand it via the `classes` prop — so your rules
|
|
298
|
+
win via CSS specificity + source order.
|
|
634
299
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
formatDay = timeFormat('%b %d'), // Nov 02
|
|
644
|
-
formatMonth = timeFormat('%b %d'), // Nov 01
|
|
645
|
-
formatYear = timeFormat('%Y %b %d') // 2017 Nov 01
|
|
646
|
-
;
|
|
647
|
-
|
|
648
|
-
const onFormatTimeLegend = (date) => {
|
|
649
|
-
return (timeSecond(date) < date ? formatMillisecond
|
|
650
|
-
: timeMinute(date) < date ? formatSecond
|
|
651
|
-
: timeHour(date) < date ? formatMinute
|
|
652
|
-
: timeDay(date) < date ? formatHour
|
|
653
|
-
: timeMonth(date) < date ? formatDay
|
|
654
|
-
: timeYear(date) < date ? formatMonth
|
|
655
|
-
: formatYear)(date);
|
|
656
|
-
};
|
|
657
|
-
```
|
|
658
|
-
|
|
659
|
-
### onFormatMetricLegend(value: number) :string
|
|
660
|
-
Called to format metric amount value to display on the top of y axis.
|
|
661
|
-
|
|
662
|
-
Example:
|
|
663
|
-
```js
|
|
664
|
-
import {formatLocale } from 'd3';
|
|
665
|
-
|
|
666
|
-
const locale = formatLocale({
|
|
667
|
-
decimal: '.',
|
|
668
|
-
thousands: ' ',
|
|
669
|
-
grouping: [3],
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
const onFormatMetricLegend = (number) => {
|
|
673
|
-
return locale.format(`,d`)(number);
|
|
674
|
-
};
|
|
300
|
+
```css
|
|
301
|
+
/* my-theme.css */
|
|
302
|
+
.my-cursorArea { fill: #4347fdff; stroke: #4347fdff; fill-opacity: 0.1; }
|
|
303
|
+
.my-cursorLeftHandle,
|
|
304
|
+
.my-cursorRightHandle { stroke: #4347fdff; }
|
|
305
|
+
.my-zoomIn { fill: #4347fdff; }
|
|
306
|
+
.my-verticalAxisText { fill: #949494; }
|
|
307
|
+
.my-legend { transform: translateX(-25px); }
|
|
675
308
|
```
|
|
676
309
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
Other functions are supposed to be private.
|
|
680
|
-
|
|
681
|
-
### zoomIn()
|
|
682
|
-
- Zooms the time scale over the selected time frame.
|
|
683
|
-
- A message will be sent if zooming is not possible any more (resolution...).
|
|
310
|
+
```jsx
|
|
311
|
+
import './my-theme.css';
|
|
684
312
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
-
|
|
689
|
-
-
|
|
313
|
+
<TimeLine
|
|
314
|
+
classes={{
|
|
315
|
+
cursorArea: 'my-cursorArea',
|
|
316
|
+
cursorLeftHandle: 'my-cursorLeftHandle',
|
|
317
|
+
cursorRightHandle:'my-cursorRightHandle',
|
|
318
|
+
zoomIn: 'my-zoomIn',
|
|
319
|
+
verticalAxisText: 'my-verticalAxisText',
|
|
320
|
+
legend: 'my-legend',
|
|
321
|
+
/* any tl-<slot> in timeline.css is overridable */
|
|
322
|
+
}}
|
|
323
|
+
...
|
|
324
|
+
/>
|
|
325
|
+
```
|
|
690
326
|
|
|
691
|
-
|
|
327
|
+
Full list of slots: see `src/timeline.css` in the repo (or inspect a
|
|
328
|
+
rendered timeline — every class starts with `tl-`). The `test/src/App.jsx`
|
|
329
|
+
demo exercises the full set.
|
|
692
330
|
|
|
693
|
-
|
|
694
|
-
- Moves gradually the timeline backward (>0) or forward(<0)
|
|
331
|
+
## Migrating from v4
|
|
695
332
|
|
|
696
|
-
|
|
333
|
+
See `MIGRATION-v5.md` for a step-by-step guide. TL;DR:
|
|
697
334
|
|
|
335
|
+
- moment objects → `Date`; `moment.Duration` → `number` (ms).
|
|
336
|
+
- `domains: Domain[]` → `domain: Domain | null`.
|
|
337
|
+
- `onUpdateDomains` → `onDomainChange`; `onCustomRange` → `onTimeSpanChange`.
|
|
338
|
+
- `onLoadHisto(intervalMs, start, end)` → `onLoadHisto({intervalMs, start, end})`.
|
|
339
|
+
- `onLoadDefaultDomain()` now RETURNS the default (sync or Promise).
|
|
340
|
+
- New required `timeZone` prop.
|
|
341
|
+
- `@material-ui/styles` peer dep gone; style via the `classes` prop
|
|
342
|
+
pointing at your own CSS class names.
|
|
698
343
|
|
|
699
344
|
## Testing / Dev
|
|
700
|
-
|
|
345
|
+
|
|
701
346
|
```bash
|
|
702
|
-
#clone the repo
|
|
703
347
|
git clone https://gitlab.com/TincaTibo/timeline.git
|
|
704
|
-
cd timeline
|
|
705
|
-
|
|
706
|
-
#
|
|
707
|
-
|
|
348
|
+
cd timeline
|
|
349
|
+
npm install
|
|
350
|
+
npm test # Vitest regression suite (12 tests)
|
|
351
|
+
npm run build # tsup -> dist/ (ESM + CJS + .d.ts + timeline.css)
|
|
352
|
+
npm run typecheck # tsc --noEmit
|
|
708
353
|
```
|
|
709
354
|
|
|
710
|
-
|
|
711
|
-
```
|
|
712
|
-
# run the demo in prod mode
|
|
713
|
-
make demo
|
|
714
|
-
```
|
|
355
|
+
Demo app (Vite, no Docker required):
|
|
715
356
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
#
|
|
719
|
-
make
|
|
357
|
+
```bash
|
|
358
|
+
cd test
|
|
359
|
+
make start # dev server on :5000 with HMR, aliased to ../src
|
|
360
|
+
make demo # production build + `vite preview`
|
|
720
361
|
```
|
|
721
|
-
To access it, go to http://localhost:5000 in your browser
|
|
722
362
|
|
|
723
|
-
|
|
724
|
-
- React 16
|
|
725
|
-
- D3.js
|
|
726
|
-
- moment.js
|
|
727
|
-
- lodash
|
|
728
|
-
- rc-tooltip
|
|
363
|
+
Editing any file under `src/` hot-reloads the demo — no package rebuild.
|
|
729
364
|
|
|
730
|
-
##
|
|
731
|
-
- Make input agnostic to moment.js
|
|
732
|
-
|
|
733
|
-
## Trello dashboard
|
|
734
|
-
[Timeline React Component](https://trello.com/b/DxjkiuFB/timeline-react-component)
|
|
365
|
+
## Dependencies
|
|
735
366
|
|
|
367
|
+
- React ≥ 16.8 (hooks).
|
|
368
|
+
- d3-{scale,selection,drag,time}
|
|
369
|
+
- luxon (runtime timezone engine — internal; host doesn't use it)
|
|
370
|
+
- rc-tooltip
|
|
371
|
+
- clsx
|
|
372
|
+
- prop-types (dev-time only — types ship via `.d.ts`)
|
|
736
373
|
|
|
374
|
+
Removed in v5: `@material-ui/styles`, `moment-timezone`, `lodash-es`.
|
|
737
375
|
|
|
738
376
|
[example]: https://gitlab.com/TincaTibo/timeline/raw/master/img/TimeLine.png "Example"
|
|
739
377
|
[styled]: https://gitlab.com/TincaTibo/timeline/-/raw/master/img/Styled-Timeline.png "Styled example"
|