@insync-stageplayer/plotly-chart 0.5.35 → 0.5.38-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.
Files changed (35) hide show
  1. package/lib/PlotlyGraph/EventMenu.d.ts +12 -12
  2. package/lib/PlotlyGraph/EventMenu.js +65 -65
  3. package/lib/PlotlyGraph/MarkerTracks.d.ts +20 -16
  4. package/lib/PlotlyGraph/MarkerTracks.d.ts.map +1 -1
  5. package/lib/PlotlyGraph/MarkerTracks.js +257 -239
  6. package/lib/PlotlyGraph/MarkerTracks.js.map +1 -1
  7. package/lib/PlotlyGraph/PlotlyLiveview.d.ts +4 -4
  8. package/lib/PlotlyGraph/PlotlyLiveview.js +297 -297
  9. package/lib/PlotlyGraph/PlotlyPlayback.d.ts +4 -4
  10. package/lib/PlotlyGraph/PlotlyPlayback.d.ts.map +1 -1
  11. package/lib/PlotlyGraph/PlotlyPlayback.js +486 -308
  12. package/lib/PlotlyGraph/PlotlyPlayback.js.map +1 -1
  13. package/lib/PlotlyGraph/PlotlyPlaybackOverlay.d.ts +23 -22
  14. package/lib/PlotlyGraph/PlotlyPlaybackOverlay.d.ts.map +1 -1
  15. package/lib/PlotlyGraph/PlotlyPlaybackOverlay.js +187 -146
  16. package/lib/PlotlyGraph/PlotlyPlaybackOverlay.js.map +1 -1
  17. package/lib/PlotlyGraph/index.d.ts +2 -2
  18. package/lib/PlotlyGraph/index.d.ts.map +1 -1
  19. package/lib/PlotlyGraph/index.js +2 -2
  20. package/lib/PlotlyGraph/index.js.map +1 -1
  21. package/lib/index.d.ts +1 -1
  22. package/lib/index.js +1 -1
  23. package/package.json +5 -3
  24. package/lib/Plotly.d.ts +0 -5
  25. package/lib/Plotly.d.ts.map +0 -1
  26. package/lib/Plotly.js +0 -338
  27. package/lib/Plotly.js.map +0 -1
  28. package/lib/PlotlyGraph/Plotly.d.ts +0 -5
  29. package/lib/PlotlyGraph/Plotly.d.ts.map +0 -1
  30. package/lib/PlotlyGraph/Plotly.js +0 -347
  31. package/lib/PlotlyGraph/Plotly.js.map +0 -1
  32. package/lib/PlotlyLiveview.d.ts +0 -5
  33. package/lib/PlotlyLiveview.d.ts.map +0 -1
  34. package/lib/PlotlyLiveview.js +0 -310
  35. package/lib/PlotlyLiveview.js.map +0 -1
@@ -1,28 +1,48 @@
1
- import React, { useCallback, useEffect, useState } from "react";
2
- import Plot from "react-plotly.js";
3
- import PropTypes from "prop-types";
4
- import { withResizeDetector } from "react-resize-detector";
5
- import { useTheme as useSelectedTheme, styled, } from "@insync-stageplayer/ui-components";
6
- const convertMicrosecondstoDateFormat = (inputMicroseconds) => {
7
- let convertedDate = new Date(+inputMicroseconds / 1000);
8
- return adjustWithLocalTimeZone(convertedDate);
9
- };
10
- const adjustWithLocalTimeZone = (date) => {
11
- let adjustedDate = new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
12
- return adjustedDate;
13
- };
14
- const convertDateToMicroseconds = (inputDate) => {
15
- const convertIntoDate = new Date(inputDate);
16
- return (convertIntoDate.getTime() * 1000 -
17
- convertIntoDate.getTimezoneOffset() * 60 * 1000 * 1000);
18
- };
19
- const getMicroSecondStartAndLength = (originalFromDate, originalStopDate, totalTime) => {
20
- const start = convertDateToMicroseconds(originalFromDate);
21
- const end = convertDateToMicroseconds(originalStopDate);
22
- let sLength = end - start;
23
- const length = sLength + (totalTime % 1000) === totalTime ? totalTime : sLength;
24
- return [start, length];
25
- };
1
+ import React, { useCallback, useEffect, useState, useRef } from "react";
2
+ import Plot from "react-plotly.js";
3
+ import PropTypes from "prop-types";
4
+ import { withResizeDetector } from "react-resize-detector";
5
+ import { useTheme as useSelectedTheme, styled, } from "@insync-stageplayer/ui-components";
6
+ const normalizeRange = 1000;
7
+ const convertMicrosecondstoDateFormat = (inputMicroseconds) => {
8
+ let convertedDate = new Date(+inputMicroseconds / 1000);
9
+ return adjustWithLocalTimeZone(convertedDate);
10
+ };
11
+ const adjustWithLocalTimeZone = (date) => {
12
+ let adjustedDate = new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
13
+ return adjustedDate;
14
+ };
15
+ const convertDateToMicroseconds = (inputDate) => {
16
+ const convertIntoDate = new Date(inputDate);
17
+ return (convertIntoDate.getTime() * 1000 -
18
+ convertIntoDate.getTimezoneOffset() * 60 * 1000 * 1000);
19
+ };
20
+ const getMicroSecondStartAndLength = (originalFromDate, originalStopDate, totalTime) => {
21
+ const start = convertDateToMicroseconds(originalFromDate);
22
+ const end = convertDateToMicroseconds(originalStopDate);
23
+ let sLength = end - start;
24
+ const length = sLength + (totalTime % 1000) === totalTime ? totalTime : sLength;
25
+ return [start, length];
26
+ };
27
+ const convertMicrosecondsToDate = (inputTime) => {
28
+ const date = new Date(inputTime / 1000 - 3600 * 1000);
29
+ const pad = function (num) {
30
+ return (num < 10 ? "0" : "") + num;
31
+ };
32
+ return (date.getFullYear() +
33
+ "-" +
34
+ pad(date.getMonth() + 1) +
35
+ "-" +
36
+ pad(date.getDate()) +
37
+ " " +
38
+ pad(date.getHours()) +
39
+ ":" +
40
+ pad(date.getMinutes()) +
41
+ ":" +
42
+ pad(date.getSeconds()) +
43
+ "." +
44
+ pad(date.getMilliseconds()));
45
+ };
26
46
  const StyledPlotly = styled(Plot) `
27
47
  rect.nsewdrag.cursor-ew-resize {
28
48
  cursor: zoom-in;
@@ -35,287 +55,445 @@ const StyledPlotly = styled(Plot) `
35
55
  cursor: grab;
36
56
  pointer-events: none !important;
37
57
  }
38
- `;
39
- export const PlotlyPlayback = withResizeDetector(({ xRange, data, metadata, onStopSelect, onDrag, xScaleTickFormat, scrubbing, yAxisLabel, displaySecondYAxis, displayArrow, totalTime, }) => {
40
- var _a;
41
- const [plotData, setPlotData] = useState([]);
42
- const [nowLine, setNowline] = useState((_a = sessionStorage.getItem("nl")) !== null && _a !== void 0 ? _a : 0);
43
- const [layout, setLayout] = useState(null);
44
- const selectedTheme = useSelectedTheme();
45
- const [yAxisLabelLeft, setYAxisLabelLeft] = useState("");
46
- const [yAxisLabelRight, setYAxisLabelRight] = useState("");
47
- const updateLayout = useCallback(() => {
48
- let annotations = [
49
- {
50
- xref: "paper",
51
- yref: "paper",
52
- x: nowLine,
53
- xanchor: "right",
54
- y: 1,
55
- yanchor: "bottom",
56
- text: "",
57
- showarrow: displayArrow,
58
- arrowhead: 0,
59
- ax: 0,
60
- ay: 1000,
61
- arrowcolor: "red",
62
- },
63
- ];
64
- const convertXRangeFrom = xScaleTickFormat.includes(":")
65
- ? convertMicrosecondstoDateFormat(xRange.from > 0
66
- ? xRange.length === totalTime
67
- ? 0
68
- : xRange.from + xRange.length > totalTime
69
- ? totalTime - xRange.length
70
- : xRange.from
71
- : 0)
72
- : xRange.from / 1e6;
73
- const convertXRangeTo = xScaleTickFormat.includes(":")
74
- ? convertMicrosecondstoDateFormat(xRange.from > 0
75
- ? xRange.length === totalTime
76
- ? xRange.length
77
- : xRange.from + xRange.length > totalTime
78
- ? totalTime
79
- : xRange.from + xRange.length
80
- : xRange.length)
81
- : (xRange.from + xRange.length) / 1e6;
82
- let defaultLayout = {
83
- // this hovermode setting creates a hover-over legend for all the signals at the same time. It also adds a spike line
84
- hovermode: "x unified",
85
- yaxis: {
86
- fixedrange: true,
87
- rangemode: "",
88
- hoverformat: ".2f",
89
- range: selectedTheme.name === "noldus" ? [0, 1] : [],
90
- title: yAxisLabelLeft,
91
- showline: true,
92
- showticklabels: false,
93
- linewidth: 2,
94
- linecolor: selectedTheme.colors.accent,
95
- tickformat: null,
96
- },
97
- xaxis: {
98
- rangemode: "",
99
- showline: false,
100
- linewidth: 2,
101
- linecolor: selectedTheme.colors.accent,
102
- fixedrange: false,
103
- range: [convertXRangeFrom, convertXRangeTo],
104
- tickformat: xScaleTickFormat.includes(":") ? "%H:%M:%S" : null,
105
- },
106
- showlegend: false,
107
- autosize: true,
108
- margin: { l: 25, r: 10, t: 20, b: 20 },
109
- paper_bgcolor: selectedTheme.colors.background,
110
- plot_bgcolor: selectedTheme.colors.background,
111
- font: { color: selectedTheme.colors.foreground },
112
- };
113
- // Check if a second y-axis needs to be added
114
- if (displaySecondYAxis && metadata.length == 2) {
115
- const yAxis2 = {
116
- fixedrange: true,
117
- title: yAxisLabelRight,
118
- anchor: "x",
119
- overlaying: "y",
120
- side: "right",
121
- };
122
- defaultLayout = Object.assign(Object.assign({}, defaultLayout), { yaxis2: yAxis2 });
123
- }
124
- // when scrubbing plotly is in charge, this to prevent the xRange to update and mess while
125
- // still scrubbing in plotly
126
- if (!scrubbing) {
127
- setLayout(Object.assign(Object.assign({}, defaultLayout), { annotations }));
128
- }
129
- }, [
130
- selectedTheme,
131
- xRange,
132
- xScaleTickFormat,
133
- yAxisLabelLeft,
134
- yAxisLabelRight,
135
- displaySecondYAxis,
136
- displayArrow,
137
- scrubbing,
138
- metadata,
139
- nowLine,
140
- ]);
141
- const onRelayout = (e) => {
142
- if (e["xaxis.range[0]"] && e["xaxis.range[1]"]) {
143
- let selection;
144
- if (xScaleTickFormat.includes(":")) {
145
- const [from, length] = getMicroSecondStartAndLength(e["xaxis.range[0]"], e["xaxis.range[1]"], totalTime);
146
- selection = {
147
- from: from,
148
- length: length,
149
- };
150
- }
151
- else {
152
- selection = {
153
- from: e["xaxis.range[0]"] * 1e6,
154
- length: (e["xaxis.range[1]"] - e["xaxis.range[0]"]) * 1e6,
155
- };
156
- }
157
- onStopSelect({ selection });
158
- }
159
- };
160
- const onRelayouting = (e) => {
161
- if (e["xaxis.range[0]"] && e["xaxis.range[1]"]) {
162
- let seekTime;
163
- if (xScaleTickFormat.includes(":")) {
164
- const [from, length] = getMicroSecondStartAndLength(e["xaxis.range[0]"], e["xaxis.range[1]"], totalTime);
165
- const possibleSeekTime = length * nowLine + from;
166
- seekTime =
167
- possibleSeekTime > totalTime
168
- ? totalTime
169
- : possibleSeekTime < 0
170
- ? 0
171
- : possibleSeekTime;
172
- }
173
- else {
174
- seekTime =
175
- ((e["xaxis.range[1]"] - e["xaxis.range[0]"]) / 2 +
176
- e["xaxis.range[0]"]) *
177
- 1e6;
178
- }
179
- onDrag(seekTime);
180
- }
181
- };
182
- useEffect(() => {
183
- updateLayout();
184
- const plotDataArr = [];
185
- data.forEach((signal, idx) => {
186
- const x = signal.map((item) => {
187
- if (xScaleTickFormat.includes(":")) {
188
- const xDateFormatted = convertMicrosecondstoDateFormat(+item.x);
189
- return xDateFormatted;
190
- }
191
- else {
192
- const xDateFormatted = +item.x / 1e6;
193
- return xDateFormatted;
194
- }
195
- });
196
- const yVal = signal.map((item) => {
197
- return item.y;
198
- });
199
- const { min, max } = metadata[idx];
200
- const range = max - min;
201
- const y = yVal.map((value) => {
202
- return (value - min) / range;
203
- });
204
- const signalData = {
205
- x,
206
- y,
207
- hovertemplate: "%{customdata:.2f}",
208
- customdata: yVal.map((point) => `${point}`),
209
- type: "scattergl",
210
- mode: metadata[idx].frequency * (xRange.length / 1000 / 1000) > 250
211
- ? "lines"
212
- : "lines+markers",
213
- name: metadata[idx].name,
214
- marker: {
215
- color: metadata[idx].color,
216
- size: 5,
217
- line: {
218
- color: metadata[idx].color,
219
- width: 1,
220
- },
221
- },
222
- };
223
- plotDataArr.push(signalData);
224
- });
225
- // Check if a second y-axis needs to be added
226
- if (displaySecondYAxis && metadata.length == 2) {
227
- plotDataArr[1] = Object.assign(Object.assign({}, plotDataArr[1]), { yaxis: "y2" });
228
- }
229
- // Setting y-axis labels if needed and meeting the requirements
230
- if (metadata.length == 1) {
231
- setYAxisLabelLeft(yAxisLabel ? metadata[0].name : "");
232
- }
233
- else if (metadata.length == 2 && displaySecondYAxis) {
234
- setYAxisLabelLeft(yAxisLabel ? metadata[0].name : "");
235
- setYAxisLabelRight(yAxisLabel ? metadata[1].name : "");
236
- }
237
- else {
238
- setYAxisLabelLeft("");
239
- setYAxisLabelRight("");
240
- }
241
- setPlotData(plotDataArr);
242
- }, [
243
- data,
244
- metadata,
245
- updateLayout,
246
- xScaleTickFormat,
247
- xRange,
248
- scrubbing,
249
- yAxisLabel,
250
- displaySecondYAxis,
251
- ]);
252
- useEffect(() => {
253
- if (!scrubbing) {
254
- if (xRange.from < 0) {
255
- let d = (xRange.length / 2 + xRange.from) / xRange.length;
256
- setNowline(d);
257
- }
258
- else {
259
- if (xRange.length === totalTime) {
260
- setNowline(0.5 + xRange.from / totalTime);
261
- }
262
- else if (xRange.from + xRange.length > totalTime) {
263
- setNowline(0.5 + (xRange.from - (totalTime - xRange.length)) / xRange.length);
264
- }
265
- else {
266
- setNowline(0.5);
267
- }
268
- }
269
- }
270
- sessionStorage.setItem("nl", nowLine);
271
- }, [plotData, xRange]);
272
- return (React.createElement(StyledPlotly, { useResizeHandler: true, className: "plot-div", data: plotData, layout: layout, style: { width: "100%", height: "100%" }, config: {
273
- displaylogo: false,
274
- displayModeBar: false,
275
- responsive: true,
276
- }, onRelayout: (e) => onRelayout(e), onRelayouting: (e) => onRelayouting(e) }));
277
- });
278
- PlotlyPlayback.defaultProps = {
279
- xRange: null,
280
- data: [],
281
- metadata: [],
282
- onStopSelect: () => { },
283
- onDrag: () => { },
284
- xScaleTickFormat: "SS",
285
- scrubbing: false,
286
- yAxisLabel: false,
287
- displaySecondYAxis: false,
288
- displayArrow: true,
289
- selectedTheme: null,
290
- totalTime: null,
291
- };
292
- const dataElement = PropTypes.shape({
293
- x: PropTypes.number,
294
- y: PropTypes.number,
295
- });
296
- const metadataElement = PropTypes.shape({
297
- name: PropTypes.string,
298
- color: PropTypes.string,
299
- });
300
- PlotlyPlayback.propTypes = {
301
- xRange: PropTypes.shape({
302
- from: PropTypes.number,
303
- length: PropTypes.number,
304
- }),
305
- data: PropTypes.arrayOf(PropTypes.arrayOf(dataElement), PropTypes.arrayOf(dataElement)),
306
- metadata: PropTypes.arrayOf(metadataElement),
307
- onStopSelect: PropTypes.func,
308
- onDrag: PropTypes.func,
309
- xScaleTickFormat: PropTypes.string,
310
- scrubbing: PropTypes.bool,
311
- yAxisLabel: PropTypes.bool,
312
- displaySecondYAxis: PropTypes.bool,
313
- displayArrow: PropTypes.bool,
314
- selectedTheme: PropTypes.shape({
315
- colors: PropTypes.shape({
316
- background: PropTypes.string,
317
- }),
318
- }),
319
- totalTime: PropTypes.number,
320
- };
58
+ `;
59
+ export const PlotlyPlayback = withResizeDetector(({ xRange, data, metadata, onStopSelect, onDrag, xScaleTickFormat, scrubbing, yAxisLabel, displaySecondYAxis, displayArrow, totalTime, startPositionCurrentTimeIndicator, onRenderedWidth, onRenderedLeft, onRenderedTop, onRenderedHeight, onRenderedScrubbar, percentageHeight, }) => {
60
+ var _a;
61
+ const [plotData, setPlotData] = useState([]);
62
+ const [nowLine, setNowline] = useState((_a = sessionStorage.getItem("nl")) !== null && _a !== void 0 ? _a : 0);
63
+ const [layout, setLayout] = useState(null);
64
+ const selectedTheme = useSelectedTheme();
65
+ const [yAxisLabelLeft, setYAxisLabelLeft] = useState("");
66
+ const [yAxisLabelRight, setYAxisLabelRight] = useState("");
67
+ const [yAxisLabelLeftColor, setYAxisLabelLeftColor] = useState("");
68
+ const [yAxisLabelRightColor, setYAxisLabelRightColor] = useState("");
69
+ const plotlyRef = useRef();
70
+ const updateLayout = useCallback(() => {
71
+ const nowline_color = "rgba(255, 0, 0, 1)";
72
+ const annotations = [
73
+ {
74
+ xref: "paper",
75
+ yref: "paper",
76
+ x: nowLine,
77
+ xanchor: "right",
78
+ y: 1,
79
+ yanchor: "bottom",
80
+ text: "",
81
+ showarrow: displayArrow,
82
+ arrowhead: 0,
83
+ ax: 0,
84
+ ay: 4000,
85
+ arrowcolor: nowline_color,
86
+ },
87
+ ];
88
+ const shapes = [
89
+ {
90
+ type: "rect",
91
+ xref: "paper",
92
+ yref: "paper",
93
+ layer: "below",
94
+ x0: 0,
95
+ y0: 0,
96
+ x1: 1,
97
+ y1: -0.19,
98
+ fillcolor: selectedTheme.colors.scrubBarColor,
99
+ line: {
100
+ color: selectedTheme.colors.scrubBarColor,
101
+ },
102
+ },
103
+ ];
104
+ const convertXRangeFrom = xScaleTickFormat.includes(":")
105
+ ? convertMicrosecondstoDateFormat(xRange.from > 0
106
+ ? xRange.length === totalTime
107
+ ? 0
108
+ : xRange.from + xRange.length > totalTime
109
+ ? totalTime - xRange.length
110
+ : xRange.from
111
+ : 0)
112
+ : xRange.from / 1e6;
113
+ const convertXRangeTo = xScaleTickFormat.includes(":")
114
+ ? convertMicrosecondstoDateFormat(xRange.from > 0
115
+ ? xRange.length === totalTime
116
+ ? xRange.length
117
+ : xRange.from + xRange.length > totalTime
118
+ ? totalTime
119
+ : xRange.from + xRange.length
120
+ : xRange.length)
121
+ : (xRange.from + xRange.length) / 1e6;
122
+ const minY = yScaleRange[0].min;
123
+ const maxY = yScaleRange[0].max;
124
+ // only add y label when set, otherwise will give a lot of extra margin
125
+ const yAxisWithLabel = yAxisLabel && yAxisLabelLeft !== ""
126
+ ? {
127
+ title: yAxisLabelLeft,
128
+ automargin: "width",
129
+ titlefont: {
130
+ color: yAxisLabelLeftColor,
131
+ },
132
+ }
133
+ : {
134
+ // a bit of margin for the y axis otherwise
135
+ anchor: "free",
136
+ shift: 5,
137
+ };
138
+ const sharedYaxis = Object.assign(Object.assign({}, yAxisWithLabel), { fixedrange: true, rangemode: "", showline: true, showticklabels: selectedTheme.name === "noldus" ? false : true, linewidth: 2, linecolor: selectedTheme.colors.accent, tickformat: null });
139
+ // Noldus doesn't need the precision, where MARIN wants it to be as precise as possible
140
+ // MARIN wants it's own normalization when working with different units (e.g kn and m)
141
+ const yAxis = selectedTheme.name === "noldus"
142
+ ? Object.assign(Object.assign({}, sharedYaxis), { hoverformat: ".2f" }) : Object.assign(Object.assign({}, sharedYaxis), { range: [minY, maxY], showline: shouldNormalize ? false : true, showticklabels: shouldNormalize ? false : true });
143
+ let defaultLayout = {
144
+ // this hovermode setting creates a hover-over legend for all the signals at the same time. It also adds a spike line
145
+ hovermode: "x unified",
146
+ yaxis: yAxis,
147
+ xaxis: {
148
+ rangemode: "",
149
+ showline: true,
150
+ linewidth: 2,
151
+ linecolor: selectedTheme.colors.accent,
152
+ fixedrange: false,
153
+ range: [convertXRangeFrom, convertXRangeTo],
154
+ tickformat: xScaleTickFormat.includes(":") ? "%H:%M:%S" : null,
155
+ // dtick: 5, // removing this allows for automatic per zoom level
156
+ ticks: "outside top",
157
+ ticklen: 15,
158
+ tickcolor: selectedTheme.colors.dtickColor,
159
+ ticklabelposition: "inside",
160
+ minor: {
161
+ ticks: "inside top",
162
+ ticklen: 9,
163
+ tickmode: "auto",
164
+ nticks: 10,
165
+ tickcolor: selectedTheme.colors.dtickMinorColor,
166
+ },
167
+ },
168
+ showlegend: false,
169
+ autosize: true,
170
+ margin: { l: 25, r: 10, t: 20, b: 20 },
171
+ paper_bgcolor: selectedTheme.colors.background,
172
+ plot_bgcolor: selectedTheme.colors.background,
173
+ font: { color: selectedTheme.colors.foreground },
174
+ };
175
+ // only add y label when set, setting it empty otherwise will give extra margin
176
+ const yAxis2WithLabel = yAxisLabel && yAxisLabelRight !== ""
177
+ ? {
178
+ title: yAxisLabelRight,
179
+ titlefont: {
180
+ color: yAxisLabelRightColor,
181
+ },
182
+ }
183
+ : {};
184
+ // Check if a second y-axis needs to be added
185
+ if (displaySecondYAxis && metadata.length == 2) {
186
+ const yAxis2 = Object.assign(Object.assign({}, yAxis2WithLabel), { fixedrange: true, range: [yScaleRange[1].min, yScaleRange[1].max], anchor: "x", overlaying: "y", side: "right", automargin: "width" });
187
+ defaultLayout = Object.assign(Object.assign({}, defaultLayout), { yaxis2: yAxis2 });
188
+ }
189
+ // when scrubbing plotly is in charge, this to prevent the xRange to update and mess while
190
+ // still scrubbing in plotly
191
+ if (!scrubbing) {
192
+ setLayout(Object.assign(Object.assign({}, defaultLayout), { shapes, annotations }));
193
+ }
194
+ }, [
195
+ selectedTheme,
196
+ xRange,
197
+ xScaleTickFormat,
198
+ yAxisLabel,
199
+ yAxisLabelLeft,
200
+ yAxisLabelRight,
201
+ displaySecondYAxis,
202
+ displayArrow,
203
+ scrubbing,
204
+ metadata,
205
+ nowLine,
206
+ totalTime,
207
+ yAxisLabelLeftColor,
208
+ yAxisLabelRightColor,
209
+ ]);
210
+ const onRelayout = (e) => {
211
+ if (e["xaxis.range[0]"] && e["xaxis.range[1]"]) {
212
+ let selection;
213
+ if (xScaleTickFormat.includes(":")) {
214
+ const [from, length] = getMicroSecondStartAndLength(e["xaxis.range[0]"], e["xaxis.range[1]"], totalTime);
215
+ selection = {
216
+ from: from,
217
+ length: length,
218
+ };
219
+ }
220
+ else {
221
+ selection = {
222
+ from: e["xaxis.range[0]"] * 1e6,
223
+ length: (e["xaxis.range[1]"] - e["xaxis.range[0]"]) * 1e6,
224
+ };
225
+ }
226
+ onStopSelect({ selection });
227
+ }
228
+ };
229
+ const onRelayouting = (e) => {
230
+ if (e["xaxis.range[0]"] && e["xaxis.range[1]"]) {
231
+ let seekTime;
232
+ if (xScaleTickFormat.includes(":")) {
233
+ const [from, length] = getMicroSecondStartAndLength(e["xaxis.range[0]"], e["xaxis.range[1]"], totalTime);
234
+ const possibleSeekTime = length * nowLine + from;
235
+ onDrag(possibleSeekTime);
236
+ }
237
+ else {
238
+ // set on drag
239
+ if (startPositionCurrentTimeIndicator === "0") {
240
+ seekTime = e["xaxis.range[0]"] * 1e6;
241
+ }
242
+ else {
243
+ seekTime =
244
+ ((e["xaxis.range[1]"] - e["xaxis.range[0]"]) / 2 +
245
+ e["xaxis.range[0]"]) *
246
+ 1e6;
247
+ }
248
+ onDrag(seekTime);
249
+ }
250
+ }
251
+ };
252
+ // MARIN data should be normalized if the unit of the different signals are not the same
253
+ const shouldNormalize = React.useMemo(() => {
254
+ const units = metadata.reduce((acc, curr) => {
255
+ if (acc.indexOf(curr.unit) < 0) {
256
+ return [...acc, curr.unit];
257
+ }
258
+ return acc;
259
+ }, []);
260
+ return displaySecondYAxis ? units.length > 2 : units.length > 1;
261
+ }, [metadata, displaySecondYAxis]);
262
+ // Getting the range for the y-axis
263
+ const yScaleRange = React.useMemo(() => {
264
+ if (!shouldNormalize && metadata) {
265
+ if (displaySecondYAxis && metadata.length == 2) {
266
+ return [
267
+ { min: metadata[0].min, max: metadata[0].max },
268
+ { min: metadata[1].min, max: metadata[1].max },
269
+ ];
270
+ }
271
+ else {
272
+ const min = metadata.reduce((acc, l) => Math.min(acc, l.min), Infinity);
273
+ const max = metadata.reduce((acc, l) => Math.max(acc, l.max), -Infinity);
274
+ return [{ min, max }];
275
+ }
276
+ }
277
+ return [{ min: 0, max: 1 }];
278
+ }, [shouldNormalize, metadata, displaySecondYAxis]);
279
+ useEffect(() => {
280
+ const plotDataArr = [];
281
+ data.forEach((signal, idx) => {
282
+ // For Noldus we need to filter out the x from the objects, MARIN directly returns a Plotly optimized format
283
+ const x = selectedTheme.name === "noldus"
284
+ ? signal.map((item) => {
285
+ if (xScaleTickFormat.includes(":")) {
286
+ const xDateFormatted = convertMicrosecondstoDateFormat(+item.x);
287
+ return xDateFormatted;
288
+ }
289
+ else {
290
+ const xValue = +item.x / 1e6;
291
+ return xValue;
292
+ }
293
+ })
294
+ : signal[0].map((item) => {
295
+ if (xScaleTickFormat.includes(":")) {
296
+ const xDateFormatted = convertMicrosecondstoDateFormat(+item);
297
+ return xDateFormatted;
298
+ }
299
+ else {
300
+ const xValue = +item / 1e6;
301
+ return xValue;
302
+ }
303
+ });
304
+ // For Noldus we need to filter out the y from the objects, MARIN directly returns a Plotly optimized format
305
+ const yVal = selectedTheme.name === "noldus"
306
+ ? signal.map((item) => {
307
+ return item.y;
308
+ })
309
+ : signal[1];
310
+ const y = handleYValue(yVal, idx);
311
+ const sharedSignalData = {
312
+ x,
313
+ y,
314
+ type: "scattergl",
315
+ mode: metadata[idx].frequency * (xRange.length / 1000 / 1000) > 250
316
+ ? "lines"
317
+ : "lines+markers",
318
+ name: metadata[idx].name,
319
+ marker: {
320
+ color: metadata[idx].color,
321
+ size: 5,
322
+ line: {
323
+ color: metadata[idx].color,
324
+ width: 1,
325
+ },
326
+ },
327
+ };
328
+ const signalData = getSignalData(sharedSignalData, yVal);
329
+ plotDataArr.push(signalData);
330
+ });
331
+ // Check if a second y-axis needs to be added
332
+ if (displaySecondYAxis && metadata.length == 2) {
333
+ plotDataArr[1] = Object.assign(Object.assign({}, plotDataArr[1]), { yaxis: "y2" });
334
+ }
335
+ // Setting y-axis labels if needed and meeting the requirements
336
+ if (metadata.length == 1) {
337
+ setYAxisLabelLeft(yAxisLabel ? metadata[0].name : "");
338
+ setYAxisLabelLeftColor(yAxisLabel ? selectedTheme.colors.foreground : "");
339
+ }
340
+ else if (metadata.length == 2 && displaySecondYAxis) {
341
+ setYAxisLabelLeft(yAxisLabel ? metadata[0].name : "");
342
+ setYAxisLabelLeftColor(yAxisLabel ? metadata[0].color : "");
343
+ setYAxisLabelRight(yAxisLabel ? metadata[1].name : "");
344
+ setYAxisLabelRightColor(yAxisLabel ? metadata[1].color : "");
345
+ }
346
+ else {
347
+ setYAxisLabelLeft("");
348
+ setYAxisLabelRight("");
349
+ setYAxisLabelLeftColor("");
350
+ setYAxisLabelRightColor("");
351
+ }
352
+ setPlotData(plotDataArr);
353
+ }, [
354
+ data,
355
+ metadata,
356
+ xScaleTickFormat,
357
+ xRange.length,
358
+ yAxisLabel,
359
+ displaySecondYAxis,
360
+ selectedTheme.colors.foreground,
361
+ selectedTheme.name,
362
+ ]);
363
+ useEffect(() => {
364
+ updateLayout();
365
+ }, [updateLayout]);
366
+ useEffect(() => {
367
+ if (!scrubbing) {
368
+ if (selectedTheme.name === "noldus") {
369
+ if (xRange.from < 0) {
370
+ let d = (xRange.length / 2 + xRange.from) / xRange.length;
371
+ setNowline(d);
372
+ }
373
+ else {
374
+ if (xRange.length === totalTime) {
375
+ setNowline(0.5 + xRange.from / totalTime);
376
+ }
377
+ else if (xRange.from + xRange.length > totalTime) {
378
+ setNowline(0.5 +
379
+ (xRange.from - (totalTime - xRange.length)) / xRange.length);
380
+ }
381
+ else {
382
+ setNowline(0.5);
383
+ }
384
+ }
385
+ }
386
+ else {
387
+ setNowline(0.5);
388
+ }
389
+ }
390
+ }, [scrubbing, xRange]);
391
+ const afterPlot = () => {
392
+ //console.log(plotlyRef.current);
393
+ //console.log(plotlyRef.current.el);
394
+ // TODO: get from plotlyRef instead of document
395
+ var layer = document.getElementsByClassName("axesclip")[0].firstChild;
396
+ const yAxisSignalLeft = layer.x.baseVal.value;
397
+ const yAxisSignalWidth = layer.width.baseVal.value;
398
+ const xAxisSignalTop = layer.y.baseVal.value;
399
+ const xAxisSignalHeight = layer.height.baseVal.value;
400
+ onRenderedLeft(yAxisSignalLeft);
401
+ onRenderedWidth(yAxisSignalWidth);
402
+ onRenderedTop(xAxisSignalTop);
403
+ onRenderedHeight(xAxisSignalHeight);
404
+ // TODO: get from plotlyRef instead of document
405
+ const scrubbar = document.getElementsByClassName("ewdrag")[0];
406
+ const scrubbarHeight = scrubbar.height.baseVal.value;
407
+ onRenderedScrubbar(scrubbarHeight);
408
+ };
409
+ const handleYValue = (yVal, idx) => {
410
+ // Noldus wants the Y data to be relative between 0 and 1
411
+ // MARIN data engineers always wants the data as it is
412
+ if (selectedTheme.name === "noldus" || shouldNormalize) {
413
+ const { min, max } = metadata[idx];
414
+ const range = max - min;
415
+ const y = yVal.map((value) => {
416
+ return (value - min) / range;
417
+ });
418
+ return y;
419
+ }
420
+ else {
421
+ return yVal;
422
+ }
423
+ };
424
+ const getSignalData = (sharedSignalData, yVal) => {
425
+ if (selectedTheme.name === "noldus") {
426
+ const noldusSignalData = {
427
+ hovertemplate: "%{customdata:.2f}",
428
+ customdata: yVal.map((point) => `${point}`), // Setting raw data for each point
429
+ };
430
+ return Object.assign(Object.assign({}, sharedSignalData), noldusSignalData);
431
+ }
432
+ else {
433
+ if (shouldNormalize) {
434
+ const marinSignalData = {
435
+ hovertemplate: "%{customdata}",
436
+ customdata: yVal.map((point) => `${point}`),
437
+ };
438
+ return Object.assign(Object.assign({}, sharedSignalData), marinSignalData);
439
+ }
440
+ else {
441
+ return sharedSignalData;
442
+ }
443
+ }
444
+ };
445
+ return (React.createElement(StyledPlotly, { useResizeHandler: true, className: "plot-div", data: plotData, layout: layout, style: { width: "100%", height: percentageHeight + "%" }, config: {
446
+ displaylogo: false,
447
+ displayModeBar: false,
448
+ responsive: true,
449
+ doubleClick: false,
450
+ showTips: false,
451
+ }, onRelayout: (e) => onRelayout(e), onRelayouting: (e) => onRelayouting(e), onAfterPlot: () => afterPlot(), ref: plotlyRef }));
452
+ });
453
+ PlotlyPlayback.defaultProps = {
454
+ xRange: null,
455
+ data: [],
456
+ metadata: [],
457
+ onStopSelect: () => { },
458
+ onDrag: () => { },
459
+ xScaleTickFormat: "SS",
460
+ scrubbing: false,
461
+ yAxisLabel: false,
462
+ displaySecondYAxis: false,
463
+ displayArrow: true,
464
+ selectedTheme: null,
465
+ totalTime: null,
466
+ startPositionCurrentTimeIndicator: "0.5",
467
+ };
468
+ const dataElement = PropTypes.shape({
469
+ x: PropTypes.number,
470
+ y: PropTypes.number,
471
+ });
472
+ const metadataElement = PropTypes.shape({
473
+ name: PropTypes.string,
474
+ color: PropTypes.string,
475
+ });
476
+ PlotlyPlayback.propTypes = {
477
+ xRange: PropTypes.shape({
478
+ from: PropTypes.number,
479
+ length: PropTypes.number,
480
+ }),
481
+ data: PropTypes.arrayOf(PropTypes.arrayOf(dataElement), PropTypes.arrayOf(dataElement)),
482
+ metadata: PropTypes.arrayOf(metadataElement),
483
+ onStopSelect: PropTypes.func,
484
+ onDrag: PropTypes.func,
485
+ xScaleTickFormat: PropTypes.string,
486
+ scrubbing: PropTypes.bool,
487
+ yAxisLabel: PropTypes.bool,
488
+ displaySecondYAxis: PropTypes.bool,
489
+ displayArrow: PropTypes.bool,
490
+ selectedTheme: PropTypes.shape({
491
+ colors: PropTypes.shape({
492
+ background: PropTypes.string,
493
+ }),
494
+ name: PropTypes.string,
495
+ }),
496
+ totalTime: PropTypes.number,
497
+ startPositionCurrentTimeIndicator: PropTypes.string,
498
+ };
321
499
  //# sourceMappingURL=PlotlyPlayback.js.map