react-native-vroom-chart 0.7.0 → 0.9.0
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/cpp/VroomChartHostObject.cpp +131 -1
- package/cpp/_core_include/vroom/vroom_chart.h +54 -14
- package/cpp/_core_src/chart.cpp +36 -2
- package/cpp/_core_src/chart.h +29 -12
- package/cpp/_core_src/chart_facade.cpp +72 -10
- package/cpp/_core_src/curve.h +67 -0
- package/cpp/_core_src/drawings.cpp +147 -4
- package/cpp/_core_src/drawings.h +10 -5
- package/cpp/_core_src/ma_overlay.cpp +200 -34
- package/cpp/_core_src/ma_overlay.h +41 -4
- package/cpp/_core_src/theme.cpp +3 -0
- package/cpp/_core_src/tip_pulse.h +74 -0
- package/lib/index.d.mts +73 -4
- package/lib/index.d.ts +73 -4
- package/lib/index.js +211 -46
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +216 -54
- package/lib/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/VroomChart.tsx +46 -23
- package/src/dataTransitions.ts +148 -0
- package/src/index.ts +6 -0
- package/src/jsi.d.ts +51 -0
- package/src/theme.ts +7 -0
- package/src/useChartCore.ts +179 -5
package/lib/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/VroomChart.tsx
|
|
2
|
-
import React, { useEffect as useEffect2, useRef as useRef2, useCallback, useState as useState2, useMemo } from "react";
|
|
2
|
+
import React, { useEffect as useEffect2, useRef as useRef2, useCallback as useCallback2, useState as useState2, useMemo } from "react";
|
|
3
3
|
import { View } from "react-native";
|
|
4
4
|
import { Canvas, Picture, Skia } from "@shopify/react-native-skia";
|
|
5
5
|
import {
|
|
@@ -7,15 +7,95 @@ import {
|
|
|
7
7
|
GestureDetector,
|
|
8
8
|
GestureHandlerRootView
|
|
9
9
|
} from "react-native-gesture-handler";
|
|
10
|
-
import { useSharedValue } from "react-native-reanimated";
|
|
10
|
+
import { useReducedMotion, useSharedValue } from "react-native-reanimated";
|
|
11
11
|
|
|
12
12
|
// src/useChartCore.ts
|
|
13
|
-
import { useEffect, useRef, useState } from "react";
|
|
13
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
14
14
|
|
|
15
15
|
// src/NativeVroomChart.ts
|
|
16
16
|
import { TurboModuleRegistry } from "react-native";
|
|
17
17
|
var NativeVroomChart_default = TurboModuleRegistry.getEnforcing("VroomChartModule");
|
|
18
18
|
|
|
19
|
+
// src/dataTransitions.ts
|
|
20
|
+
var STEP_TOLERANCE = 0.01;
|
|
21
|
+
var MAX_SAME_ASSET_CLOSE_RATIO = 1.25;
|
|
22
|
+
var MAX_END_DRIFT_STEPS = 3;
|
|
23
|
+
var MAX_STREAM_ADVANCE_STEPS = 5;
|
|
24
|
+
function inferStepMs(candles) {
|
|
25
|
+
if (candles.length < 2) return null;
|
|
26
|
+
const k = Math.min(candles.length - 1, 8);
|
|
27
|
+
const diffs = [];
|
|
28
|
+
for (let i = 0; i < k; i++) diffs.push(candles[i + 1].timeMs - candles[i].timeMs);
|
|
29
|
+
diffs.sort((a, b) => a - b);
|
|
30
|
+
const median = diffs[Math.floor(diffs.length / 2)];
|
|
31
|
+
return median > 0 ? median : null;
|
|
32
|
+
}
|
|
33
|
+
function indexByTime(candles, t) {
|
|
34
|
+
let lo = 0;
|
|
35
|
+
let hi = candles.length - 1;
|
|
36
|
+
while (lo <= hi) {
|
|
37
|
+
const mid = lo + hi >>> 1;
|
|
38
|
+
const v = candles[mid].timeMs;
|
|
39
|
+
if (v === t) return mid;
|
|
40
|
+
if (v < t) lo = mid + 1;
|
|
41
|
+
else hi = mid - 1;
|
|
42
|
+
}
|
|
43
|
+
return -1;
|
|
44
|
+
}
|
|
45
|
+
function classifyTransition(prev, next, seriesKeyChanged) {
|
|
46
|
+
if (!prev || prev.length === 0) return "initial";
|
|
47
|
+
if (next.length === 0) return "stream";
|
|
48
|
+
if (seriesKeyChanged) return "reset";
|
|
49
|
+
const prevStep = inferStepMs(prev);
|
|
50
|
+
const nextStep = inferStepMs(next);
|
|
51
|
+
if (prevStep == null || nextStep == null) return "reset";
|
|
52
|
+
const prevLast = prev[prev.length - 1];
|
|
53
|
+
const nextLast = next[next.length - 1];
|
|
54
|
+
if (Math.abs(nextStep - prevStep) <= prevStep * STEP_TOLERANCE) {
|
|
55
|
+
const idx = indexByTime(next, prevLast.timeMs);
|
|
56
|
+
const aligned = idx >= 0;
|
|
57
|
+
const sharedBarRatio = aligned && next[idx].close > 0 && prevLast.close > 0 ? Math.max(next[idx].close / prevLast.close, prevLast.close / next[idx].close) : Infinity;
|
|
58
|
+
const advanced = nextLast.timeMs >= prevLast.timeMs && nextLast.timeMs - prevLast.timeMs <= MAX_STREAM_ADVANCE_STEPS * nextStep;
|
|
59
|
+
return sharedBarRatio <= MAX_SAME_ASSET_CLOSE_RATIO && advanced ? "stream" : "reset";
|
|
60
|
+
}
|
|
61
|
+
const closeRatio = prevLast.close > 0 && nextLast.close > 0 ? Math.max(nextLast.close / prevLast.close, prevLast.close / nextLast.close) : Infinity;
|
|
62
|
+
const prevEnd = prevLast.timeMs + prevStep;
|
|
63
|
+
const nextEnd = nextLast.timeMs + nextStep;
|
|
64
|
+
const endsTogether = Math.abs(nextEnd - prevEnd) <= MAX_END_DRIFT_STEPS * Math.max(prevStep, nextStep);
|
|
65
|
+
return closeRatio <= MAX_SAME_ASSET_CLOSE_RATIO && endsTogether ? "timeframe" : "reset";
|
|
66
|
+
}
|
|
67
|
+
function timeframeWindow(oldWindow, oldStepMs, oldLastMs, newStepMs, newLastMs) {
|
|
68
|
+
const slots = (oldWindow.endMs - oldWindow.startMs) / oldStepMs;
|
|
69
|
+
const offsetRaw = (oldWindow.endMs - oldLastMs) / oldStepMs;
|
|
70
|
+
const offsetSlots = Math.min(Math.max(offsetRaw, 0), slots * 0.75);
|
|
71
|
+
const endMs = Math.round(newLastMs + offsetSlots * newStepMs);
|
|
72
|
+
return { startMs: Math.round(endMs - slots * newStepMs), endMs };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/easing.ts
|
|
76
|
+
function ease(kind, p) {
|
|
77
|
+
switch (kind) {
|
|
78
|
+
case "linear":
|
|
79
|
+
return p;
|
|
80
|
+
case "ease-in":
|
|
81
|
+
return p * p;
|
|
82
|
+
case "ease-out":
|
|
83
|
+
return p * (2 - p);
|
|
84
|
+
default:
|
|
85
|
+
return p * p * (3 - 2 * p);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
var EASINGS = [
|
|
89
|
+
"linear",
|
|
90
|
+
"ease-in",
|
|
91
|
+
"ease-out",
|
|
92
|
+
"ease-in-out"
|
|
93
|
+
];
|
|
94
|
+
function easingIndex(kind) {
|
|
95
|
+
const i = kind ? EASINGS.indexOf(kind) : -1;
|
|
96
|
+
return i < 0 ? EASINGS.indexOf("ease-in-out") : i;
|
|
97
|
+
}
|
|
98
|
+
|
|
19
99
|
// src/packCandles.ts
|
|
20
100
|
var BYTES_PER_CANDLE = 48;
|
|
21
101
|
function packCandles(candles) {
|
|
@@ -74,12 +154,18 @@ var FLOAT_KEYS = {
|
|
|
74
154
|
// VROOM_FLOAT_VOLUME_RADIUS_PX
|
|
75
155
|
lineWidth: 11,
|
|
76
156
|
// VROOM_FLOAT_LINE_WIDTH_PX
|
|
77
|
-
lineGradientOpacity: 12
|
|
157
|
+
lineGradientOpacity: 12,
|
|
78
158
|
// VROOM_FLOAT_LINE_GRADIENT_OPACITY
|
|
159
|
+
lineTension: 13
|
|
160
|
+
// VROOM_FLOAT_LINE_TENSION
|
|
79
161
|
};
|
|
162
|
+
var FLOAT_LINE_TIP_PULSE = 15;
|
|
80
163
|
var BOOL_KEYS = {
|
|
81
|
-
wickRoundCap: 9
|
|
164
|
+
wickRoundCap: 9,
|
|
82
165
|
// VROOM_FLOAT_WICK_ROUND_CAP
|
|
166
|
+
lineTipDot: 14,
|
|
167
|
+
// VROOM_FLOAT_LINE_TIP_DOT
|
|
168
|
+
lineTipPulse: FLOAT_LINE_TIP_PULSE
|
|
83
169
|
};
|
|
84
170
|
function parseColor(value) {
|
|
85
171
|
if (typeof value === "number") {
|
|
@@ -250,15 +336,53 @@ function ensureInstalled() {
|
|
|
250
336
|
}
|
|
251
337
|
installed = true;
|
|
252
338
|
}
|
|
253
|
-
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands, volume, priceLines) {
|
|
339
|
+
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands, volume, priceLines, transition) {
|
|
254
340
|
const handleRef = useRef(null);
|
|
255
341
|
const defaultWidthAppliedRef = useRef(false);
|
|
256
342
|
const volumeCollapseRef = useRef(null);
|
|
343
|
+
const prevDataRef = useRef(null);
|
|
344
|
+
const intervalMorphRaf = useRef(null);
|
|
257
345
|
const [picture, setPicture] = useState(null);
|
|
258
346
|
if (!handleRef.current && size.width > 0 && size.height > 0) {
|
|
259
347
|
ensureInstalled();
|
|
260
348
|
handleRef.current = globalThis.VroomChartJSI.create();
|
|
261
349
|
}
|
|
350
|
+
const animRef = useRef({ ms: 300, easing: void 0, reduceMotion: false });
|
|
351
|
+
animRef.current = {
|
|
352
|
+
ms: Math.max(0, transition?.transitionMs ?? 300),
|
|
353
|
+
easing: transition?.transitionEasing,
|
|
354
|
+
reduceMotion: transition?.reduceMotion ?? false
|
|
355
|
+
};
|
|
356
|
+
const onFrameRef = useRef(transition?.onFrame);
|
|
357
|
+
onFrameRef.current = transition?.onFrame;
|
|
358
|
+
const seriesKey = transition?.seriesKey;
|
|
359
|
+
const endIntervalMorph = useCallback(() => {
|
|
360
|
+
if (intervalMorphRaf.current != null) {
|
|
361
|
+
cancelAnimationFrame(intervalMorphRaf.current);
|
|
362
|
+
intervalMorphRaf.current = null;
|
|
363
|
+
}
|
|
364
|
+
handleRef.current?.setIntervalMorph(1);
|
|
365
|
+
}, []);
|
|
366
|
+
const startIntervalMorph = useCallback((h) => {
|
|
367
|
+
const { ms, easing } = animRef.current;
|
|
368
|
+
const start = performance.now();
|
|
369
|
+
const step = (now) => {
|
|
370
|
+
const p = Math.min(1, (now - start) / ms);
|
|
371
|
+
h.setIntervalMorph(p < 1 ? ease(easing, p) : 1);
|
|
372
|
+
const pic = h.render();
|
|
373
|
+
if (pic) onFrameRef.current?.(pic);
|
|
374
|
+
intervalMorphRaf.current = p < 1 ? requestAnimationFrame(step) : null;
|
|
375
|
+
};
|
|
376
|
+
intervalMorphRaf.current = requestAnimationFrame(step);
|
|
377
|
+
}, []);
|
|
378
|
+
useEffect(() => {
|
|
379
|
+
return () => {
|
|
380
|
+
if (intervalMorphRaf.current != null) {
|
|
381
|
+
cancelAnimationFrame(intervalMorphRaf.current);
|
|
382
|
+
intervalMorphRaf.current = null;
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}, []);
|
|
262
386
|
const explicit = visibleRange != null;
|
|
263
387
|
const startMs = visibleRange?.startMs ?? 0;
|
|
264
388
|
const endMs = visibleRange?.endMs ?? 0;
|
|
@@ -278,8 +402,54 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
278
402
|
h.setDefaultCandleWidth(defaultCandleWidth);
|
|
279
403
|
defaultWidthAppliedRef.current = true;
|
|
280
404
|
}
|
|
405
|
+
let morphing = false;
|
|
281
406
|
if (candles.length > 0) {
|
|
282
|
-
|
|
407
|
+
const prev = prevDataRef.current;
|
|
408
|
+
const freshHandle = prev == null || prev.handle !== h;
|
|
409
|
+
if (freshHandle || prev.candles !== candles || prev.seriesKey !== seriesKey) {
|
|
410
|
+
const transitionKind = freshHandle ? "initial" : explicit ? "stream" : classifyTransition(prev.candles, candles, seriesKey !== prev.seriesKey);
|
|
411
|
+
let tfArgs = null;
|
|
412
|
+
let prevEnvelope = null;
|
|
413
|
+
if (transitionKind === "timeframe" && prev != null) {
|
|
414
|
+
const oldWindow = h.getVisibleRange();
|
|
415
|
+
const oldStepMs = inferStepMs(prev.candles);
|
|
416
|
+
if (oldWindow.endMs > oldWindow.startMs && oldStepMs != null) {
|
|
417
|
+
tfArgs = {
|
|
418
|
+
oldWindow,
|
|
419
|
+
oldStepMs,
|
|
420
|
+
oldLastMs: prev.candles[prev.candles.length - 1].timeMs
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
prevEnvelope = h.getVisiblePriceEnvelope();
|
|
424
|
+
morphing = animRef.current.ms > 0 && !animRef.current.reduceMotion && onFrameRef.current != null;
|
|
425
|
+
if (morphing) {
|
|
426
|
+
endIntervalMorph();
|
|
427
|
+
h.beginIntervalMorph();
|
|
428
|
+
}
|
|
429
|
+
} else if (transitionKind === "initial" || transitionKind === "reset") {
|
|
430
|
+
endIntervalMorph();
|
|
431
|
+
}
|
|
432
|
+
h.setCandles(packCandles(candles));
|
|
433
|
+
if (transitionKind === "timeframe") {
|
|
434
|
+
const newStepMs = inferStepMs(candles);
|
|
435
|
+
if (tfArgs && newStepMs != null) {
|
|
436
|
+
const w = timeframeWindow(
|
|
437
|
+
tfArgs.oldWindow,
|
|
438
|
+
tfArgs.oldStepMs,
|
|
439
|
+
tfArgs.oldLastMs,
|
|
440
|
+
newStepMs,
|
|
441
|
+
candles[candles.length - 1].timeMs
|
|
442
|
+
);
|
|
443
|
+
h.setVisibleRange(w.startMs, w.endMs);
|
|
444
|
+
}
|
|
445
|
+
if (prevEnvelope) h.preservePriceEnvelope(prevEnvelope.low, prevEnvelope.high);
|
|
446
|
+
else h.resetPriceScale();
|
|
447
|
+
if (morphing) startIntervalMorph(h);
|
|
448
|
+
} else if (transitionKind === "reset") {
|
|
449
|
+
h.resetView();
|
|
450
|
+
}
|
|
451
|
+
prevDataRef.current = { handle: h, candles, seriesKey };
|
|
452
|
+
}
|
|
283
453
|
}
|
|
284
454
|
if (explicit) {
|
|
285
455
|
h.setVisibleRange(startMs, endMs);
|
|
@@ -287,6 +457,9 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
287
457
|
if (theme) {
|
|
288
458
|
applyTheme(h, theme);
|
|
289
459
|
}
|
|
460
|
+
if (animRef.current.reduceMotion) {
|
|
461
|
+
h.setFloat(FLOAT_LINE_TIP_PULSE, 0);
|
|
462
|
+
}
|
|
290
463
|
h.setRSI(rsiToSpec(rsi));
|
|
291
464
|
h.setMACD(macdToSpec(macd));
|
|
292
465
|
h.setOverlays((movingAverages ?? []).map(overlayToNumeric));
|
|
@@ -298,39 +471,16 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
298
471
|
h.setPriceLines(
|
|
299
472
|
priceLines?.lines.length ? priceLinesToSpec(priceLines) : EMPTY_PRICE_LINES
|
|
300
473
|
);
|
|
301
|
-
setPicture(h.render());
|
|
302
|
-
}, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, volumeKey, priceLinesKey]);
|
|
474
|
+
if (!morphing) setPicture(h.render());
|
|
475
|
+
}, [candles, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, volumeKey, priceLinesKey, startIntervalMorph, endIntervalMorph]);
|
|
303
476
|
return { handle: handleRef.current, picture, volumeCollapseRef };
|
|
304
477
|
}
|
|
305
478
|
|
|
306
|
-
// src/easing.ts
|
|
307
|
-
function ease(kind, p) {
|
|
308
|
-
switch (kind) {
|
|
309
|
-
case "linear":
|
|
310
|
-
return p;
|
|
311
|
-
case "ease-in":
|
|
312
|
-
return p * p;
|
|
313
|
-
case "ease-out":
|
|
314
|
-
return p * (2 - p);
|
|
315
|
-
default:
|
|
316
|
-
return p * p * (3 - 2 * p);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
var EASINGS = [
|
|
320
|
-
"linear",
|
|
321
|
-
"ease-in",
|
|
322
|
-
"ease-out",
|
|
323
|
-
"ease-in-out"
|
|
324
|
-
];
|
|
325
|
-
function easingIndex(kind) {
|
|
326
|
-
const i = kind ? EASINGS.indexOf(kind) : -1;
|
|
327
|
-
return i < 0 ? EASINGS.indexOf("ease-in-out") : i;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
479
|
// src/VroomChart.tsx
|
|
331
480
|
function VroomChart(props) {
|
|
332
481
|
const {
|
|
333
482
|
candles,
|
|
483
|
+
seriesKey,
|
|
334
484
|
width: widthProp,
|
|
335
485
|
height: heightProp,
|
|
336
486
|
style,
|
|
@@ -358,7 +508,7 @@ function VroomChart(props) {
|
|
|
358
508
|
const [measured, setMeasured] = useState2({ width: 0, height: 0 });
|
|
359
509
|
const width = widthProp ?? measured.width;
|
|
360
510
|
const height = heightProp ?? measured.height;
|
|
361
|
-
const onLayout =
|
|
511
|
+
const onLayout = useCallback2((e) => {
|
|
362
512
|
const w = Math.round(e.nativeEvent.layout.width);
|
|
363
513
|
const h = Math.round(e.nativeEvent.layout.height);
|
|
364
514
|
setMeasured(
|
|
@@ -373,6 +523,19 @@ function VroomChart(props) {
|
|
|
373
523
|
} : void 0,
|
|
374
524
|
[priceLines, priceLinesStyle, onPriceLineClose]
|
|
375
525
|
);
|
|
526
|
+
const emptyPicture = useMemo(() => {
|
|
527
|
+
const rec = Skia.PictureRecorder();
|
|
528
|
+
rec.beginRecording(Skia.XYWHRect(0, 0, 1, 1));
|
|
529
|
+
return rec.finishRecordingAsPicture();
|
|
530
|
+
}, []);
|
|
531
|
+
const pictureSV = useSharedValue(emptyPicture);
|
|
532
|
+
const reduceMotion = useReducedMotion();
|
|
533
|
+
const onFrame = useCallback2(
|
|
534
|
+
(p) => {
|
|
535
|
+
pictureSV.value = p;
|
|
536
|
+
},
|
|
537
|
+
[pictureSV]
|
|
538
|
+
);
|
|
376
539
|
const { handle, picture, volumeCollapseRef } = useChartCore(
|
|
377
540
|
candles,
|
|
378
541
|
{ width, height },
|
|
@@ -386,21 +549,13 @@ function VroomChart(props) {
|
|
|
386
549
|
vwap,
|
|
387
550
|
bollingerBands,
|
|
388
551
|
volume,
|
|
389
|
-
priceLinesProp
|
|
552
|
+
priceLinesProp,
|
|
553
|
+
{ seriesKey, transitionMs, transitionEasing, reduceMotion, onFrame }
|
|
390
554
|
);
|
|
391
|
-
const emptyPicture = useMemo(() => {
|
|
392
|
-
const rec = Skia.PictureRecorder();
|
|
393
|
-
rec.beginRecording(Skia.XYWHRect(0, 0, 1, 1));
|
|
394
|
-
return rec.finishRecordingAsPicture();
|
|
395
|
-
}, []);
|
|
396
|
-
const pictureSV = useSharedValue(emptyPicture);
|
|
397
555
|
const crosshairActive = useRef2(false);
|
|
398
556
|
const lastCrosshairTime = useRef2(null);
|
|
399
|
-
useEffect2(() => {
|
|
400
|
-
if (picture) pictureSV.value = picture;
|
|
401
|
-
}, [picture, pictureSV]);
|
|
402
557
|
const decayRaf = useRef2(null);
|
|
403
|
-
const cancelDecay =
|
|
558
|
+
const cancelDecay = useCallback2(() => {
|
|
404
559
|
if (decayRaf.current != null) {
|
|
405
560
|
cancelAnimationFrame(decayRaf.current);
|
|
406
561
|
decayRaf.current = null;
|
|
@@ -408,7 +563,7 @@ function VroomChart(props) {
|
|
|
408
563
|
}, []);
|
|
409
564
|
useEffect2(() => cancelDecay, [cancelDecay]);
|
|
410
565
|
const animRaf = useRef2(null);
|
|
411
|
-
const animTick =
|
|
566
|
+
const animTick = useCallback2(() => {
|
|
412
567
|
animRaf.current = null;
|
|
413
568
|
if (!handle) return;
|
|
414
569
|
const next = handle.render();
|
|
@@ -417,7 +572,7 @@ function VroomChart(props) {
|
|
|
417
572
|
animRaf.current = requestAnimationFrame(animTick);
|
|
418
573
|
}
|
|
419
574
|
}, [handle, pictureSV]);
|
|
420
|
-
const maybeStartAnim =
|
|
575
|
+
const maybeStartAnim = useCallback2(() => {
|
|
421
576
|
if (animRaf.current != null) return;
|
|
422
577
|
if (!handle?.isAnimating()) return;
|
|
423
578
|
animRaf.current = requestAnimationFrame(animTick);
|
|
@@ -430,6 +585,10 @@ function VroomChart(props) {
|
|
|
430
585
|
}
|
|
431
586
|
};
|
|
432
587
|
}, []);
|
|
588
|
+
useEffect2(() => {
|
|
589
|
+
if (picture) pictureSV.value = picture;
|
|
590
|
+
maybeStartAnim();
|
|
591
|
+
}, [picture, pictureSV, maybeStartAnim]);
|
|
433
592
|
const morphRaf = useRef2(null);
|
|
434
593
|
const morphFade = useRef2(null);
|
|
435
594
|
const morphHandle = useRef2(null);
|
|
@@ -466,7 +625,7 @@ function VroomChart(props) {
|
|
|
466
625
|
const prog = Math.min(1, (now - startTs) / dur);
|
|
467
626
|
const fade = from + (target - from) * ease(easingRef.current, prog);
|
|
468
627
|
morphFade.current = fade;
|
|
469
|
-
handle.setMorph(fade, fade);
|
|
628
|
+
handle.setMorph(reduceMotion ? 0 : fade, fade);
|
|
470
629
|
const p = handle.render();
|
|
471
630
|
if (p) pictureSV.value = p;
|
|
472
631
|
if (prog < 1) {
|
|
@@ -486,7 +645,7 @@ function VroomChart(props) {
|
|
|
486
645
|
morphRaf.current = null;
|
|
487
646
|
}
|
|
488
647
|
};
|
|
489
|
-
}, [handle, chartType, transitionMs, pictureSV]);
|
|
648
|
+
}, [handle, chartType, transitionMs, reduceMotion, pictureSV]);
|
|
490
649
|
const volumeRaf = useRef2(null);
|
|
491
650
|
const volumeHandle = useRef2(null);
|
|
492
651
|
useEffect2(() => {
|
|
@@ -504,7 +663,7 @@ function VroomChart(props) {
|
|
|
504
663
|
volumeRaf.current = null;
|
|
505
664
|
}
|
|
506
665
|
const dur = Math.max(0, transitionMs ?? 300);
|
|
507
|
-
if (dur === 0) {
|
|
666
|
+
if (dur === 0 || reduceMotion) {
|
|
508
667
|
volumeCollapseRef.current = { t: target, easing };
|
|
509
668
|
handle.setVolumeCollapse(target, easing);
|
|
510
669
|
const p = handle.render();
|
|
@@ -531,8 +690,8 @@ function VroomChart(props) {
|
|
|
531
690
|
volumeRaf.current = null;
|
|
532
691
|
}
|
|
533
692
|
};
|
|
534
|
-
}, [handle, volume?.enabled, transitionMs, pictureSV, volumeCollapseRef]);
|
|
535
|
-
const hitAxis =
|
|
693
|
+
}, [handle, volume?.enabled, transitionMs, reduceMotion, pictureSV, volumeCollapseRef]);
|
|
694
|
+
const hitAxis = useCallback2(
|
|
536
695
|
(x, y) => {
|
|
537
696
|
if (!handle) return "chart";
|
|
538
697
|
const { yAxisWidth, xAxisHeight, indicatorHeight } = handle.getAxisMetrics();
|
|
@@ -545,7 +704,7 @@ function VroomChart(props) {
|
|
|
545
704
|
},
|
|
546
705
|
[handle, width, height]
|
|
547
706
|
);
|
|
548
|
-
const hitPriceLine =
|
|
707
|
+
const hitPriceLine = useCallback2(
|
|
549
708
|
(x, y) => {
|
|
550
709
|
if (!handle || !priceLines?.length) return null;
|
|
551
710
|
const hit = handle.hitTestPriceLine(x, y);
|
|
@@ -742,6 +901,9 @@ function VroomChart(props) {
|
|
|
742
901
|
);
|
|
743
902
|
}
|
|
744
903
|
export {
|
|
745
|
-
VroomChart
|
|
904
|
+
VroomChart,
|
|
905
|
+
classifyTransition,
|
|
906
|
+
inferStepMs,
|
|
907
|
+
timeframeWindow
|
|
746
908
|
};
|
|
747
909
|
//# sourceMappingURL=index.mjs.map
|