react-native-vroom-chart 0.15.0 → 0.16.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 +171 -1
- package/cpp/_core_include/vroom/vroom_chart.h +137 -4
- package/cpp/_core_src/atr.cpp +67 -0
- package/cpp/_core_src/atr.h +44 -0
- package/cpp/_core_src/atr_pane.cpp +162 -0
- package/cpp/_core_src/atr_pane.h +48 -0
- package/cpp/_core_src/chart.cpp +461 -172
- package/cpp/_core_src/chart.h +150 -1
- package/cpp/_core_src/chart_facade.cpp +209 -23
- package/cpp/_core_src/fair_value_gaps.cpp +76 -0
- package/cpp/_core_src/fair_value_gaps.h +54 -0
- package/cpp/_core_src/fvg_overlay.cpp +262 -0
- package/cpp/_core_src/fvg_overlay.h +43 -0
- package/cpp/_core_src/ichimoku.cpp +65 -0
- package/cpp/_core_src/ichimoku.h +45 -0
- package/cpp/_core_src/labels.cpp +3 -0
- package/cpp/_core_src/line_morph.h +159 -0
- package/cpp/_core_src/ma_overlay.cpp +259 -36
- package/cpp/_core_src/ma_overlay.h +57 -2
- package/cpp/_core_src/macd.cpp +24 -1
- package/cpp/_core_src/macd.h +16 -0
- package/cpp/_core_src/macd_pane.cpp +71 -62
- package/cpp/_core_src/macd_pane.h +13 -1
- package/cpp/_core_src/pane_series.h +169 -0
- package/cpp/_core_src/rsi.cpp +4 -0
- package/cpp/_core_src/rsi.h +7 -0
- package/cpp/_core_src/rsi_pane.cpp +85 -29
- package/cpp/_core_src/rsi_pane.h +11 -1
- package/cpp/_core_src/viewport.h +35 -0
- package/lib/index.d.mts +251 -3
- package/lib/index.d.ts +251 -3
- package/lib/index.js +224 -6
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +224 -6
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/VroomChart.tsx +21 -3
- package/src/dataTransitions.ts +47 -0
- package/src/index.ts +5 -0
- package/src/jsi.d.ts +97 -1
- package/src/types.ts +5 -0
- package/src/useChartCore.ts +284 -5
package/lib/index.js
CHANGED
|
@@ -99,6 +99,13 @@ function classifyTransition(prev, next, seriesKeyChanged) {
|
|
|
99
99
|
const endsTogether = Math.abs(nextEnd - prevEnd) <= MAX_END_DRIFT_STEPS * Math.max(prevStep, nextStep);
|
|
100
100
|
return closeRatio <= MAX_SAME_ASSET_CLOSE_RATIO && endsTogether ? "timeframe" : "reset";
|
|
101
101
|
}
|
|
102
|
+
function classifyStream(prev, next) {
|
|
103
|
+
if (prev.length === 0 || next.length === 0) return "tick";
|
|
104
|
+
return next[next.length - 1].timeMs > prev[prev.length - 1].timeMs ? "append" : "tick";
|
|
105
|
+
}
|
|
106
|
+
function isPinnedToLatest(window, lastMs, stepMs) {
|
|
107
|
+
return window.endMs >= lastMs + stepMs;
|
|
108
|
+
}
|
|
102
109
|
function timeframeWindow(oldWindow, oldStepMs, oldLastMs, newStepMs, newLastMs) {
|
|
103
110
|
const slots = (oldWindow.endMs - oldWindow.startMs) / oldStepMs;
|
|
104
111
|
const offsetRaw = (oldWindow.endMs - oldLastMs) / oldStepMs;
|
|
@@ -244,6 +251,7 @@ var MA_SOURCES = [
|
|
|
244
251
|
"hlc3",
|
|
245
252
|
"ohlc4"
|
|
246
253
|
];
|
|
254
|
+
var ATR_SMOOTHINGS = ["rma", "sma", "ema"];
|
|
247
255
|
var inheritColor = (v) => (v != null ? parseColor(v) : null) ?? 0;
|
|
248
256
|
function overlayToNumeric(o) {
|
|
249
257
|
const srcIdx = o.source ? MA_SOURCES.indexOf(o.source) : 0;
|
|
@@ -270,7 +278,8 @@ function rsiToSpec(cfg) {
|
|
|
270
278
|
maColor: inheritColor(cfg?.maColor),
|
|
271
279
|
maWidth: cfg?.maWidth ?? -1,
|
|
272
280
|
bandColor: inheritColor(cfg?.bandColor),
|
|
273
|
-
bandsVisible: cfg?.bandsVisible ?? true
|
|
281
|
+
bandsVisible: cfg?.bandsVisible ?? true,
|
|
282
|
+
extremeFill: cfg?.extremeFill ?? true
|
|
274
283
|
};
|
|
275
284
|
}
|
|
276
285
|
function vwapToSpec(cfg) {
|
|
@@ -301,6 +310,79 @@ function bollingerToSpec(cfg) {
|
|
|
301
310
|
fillOpacity: cfg?.fillOpacity ?? 0.1
|
|
302
311
|
};
|
|
303
312
|
}
|
|
313
|
+
var DEFAULT_ICH_GREEN = 4280723098;
|
|
314
|
+
var DEFAULT_ICH_RED = 4293874512;
|
|
315
|
+
var DEFAULT_ICH_BLUE = 4280902399;
|
|
316
|
+
var DEFAULT_ICH_ORANGE = 4294929664;
|
|
317
|
+
var DEFAULT_ICH_TEAL = 4278238420;
|
|
318
|
+
function ichimokuToSpec(cfg) {
|
|
319
|
+
const color = (v, fallback) => (v != null ? parseColor(v) : null) ?? fallback;
|
|
320
|
+
return {
|
|
321
|
+
enabled: cfg?.enabled ?? false,
|
|
322
|
+
tenkanPeriod: cfg?.tenkanPeriod ?? 9,
|
|
323
|
+
kijunPeriod: cfg?.kijunPeriod ?? 26,
|
|
324
|
+
senkouBPeriod: cfg?.senkouBPeriod ?? 52,
|
|
325
|
+
displacement: cfg?.displacement ?? 26,
|
|
326
|
+
tenkanColor: color(cfg?.tenkanColor, DEFAULT_ICH_BLUE),
|
|
327
|
+
tenkanWidth: cfg?.tenkanWidth ?? 1,
|
|
328
|
+
tenkanEnabled: cfg?.tenkanVisible ?? true,
|
|
329
|
+
kijunColor: color(cfg?.kijunColor, DEFAULT_ICH_RED),
|
|
330
|
+
kijunWidth: cfg?.kijunWidth ?? 1,
|
|
331
|
+
kijunEnabled: cfg?.kijunVisible ?? true,
|
|
332
|
+
senkouAColor: color(cfg?.senkouAColor, DEFAULT_ICH_GREEN),
|
|
333
|
+
senkouAWidth: cfg?.senkouAWidth ?? 1,
|
|
334
|
+
senkouAEnabled: cfg?.senkouAVisible ?? true,
|
|
335
|
+
senkouBColor: color(cfg?.senkouBColor, DEFAULT_ICH_ORANGE),
|
|
336
|
+
senkouBWidth: cfg?.senkouBWidth ?? 1,
|
|
337
|
+
senkouBEnabled: cfg?.senkouBVisible ?? true,
|
|
338
|
+
chikouColor: color(cfg?.chikouColor, DEFAULT_ICH_TEAL),
|
|
339
|
+
chikouWidth: cfg?.chikouWidth ?? 1,
|
|
340
|
+
chikouEnabled: cfg?.chikouVisible ?? true,
|
|
341
|
+
cloudEnabled: cfg?.cloudVisible ?? true,
|
|
342
|
+
bullishCloudColor: color(cfg?.bullishCloudColor, DEFAULT_ICH_GREEN),
|
|
343
|
+
bearishCloudColor: color(cfg?.bearishCloudColor, DEFAULT_ICH_RED),
|
|
344
|
+
cloudOpacity: cfg?.cloudOpacity ?? 0.15
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
var DEFAULT_FVG_GREEN = 4280723098;
|
|
348
|
+
var DEFAULT_FVG_RED = 4293874512;
|
|
349
|
+
var FVG_FILL_TYPES = ["close", "wick"];
|
|
350
|
+
var FVG_BORDER_STYLES = ["solid", "dotted", "dashed"];
|
|
351
|
+
function fvgToSpec(cfg) {
|
|
352
|
+
const color = (v, fallback) => (v != null ? parseColor(v) : null) ?? fallback;
|
|
353
|
+
const bullish = color(cfg?.bullishColor, DEFAULT_FVG_GREEN);
|
|
354
|
+
const bearish = color(cfg?.bearishColor, DEFAULT_FVG_RED);
|
|
355
|
+
return {
|
|
356
|
+
enabled: cfg?.enabled ?? false,
|
|
357
|
+
maxBarsBack: cfg?.maxBarsBack ?? 300,
|
|
358
|
+
waitForClose: cfg?.waitForClose ?? false,
|
|
359
|
+
fillType: Math.max(0, FVG_FILL_TYPES.indexOf(cfg?.fillType ?? "close")),
|
|
360
|
+
deleteAfterFill: cfg?.deleteAfterFill ?? true,
|
|
361
|
+
extendBoxes: cfg?.extendBoxes ?? false,
|
|
362
|
+
boxLength: cfg?.boxLength ?? 20,
|
|
363
|
+
bullishColor: bullish,
|
|
364
|
+
bearishColor: bearish,
|
|
365
|
+
opacity: cfg?.opacity ?? 0.15,
|
|
366
|
+
borderEnabled: cfg?.borderVisible ?? true,
|
|
367
|
+
borderStyle: Math.max(
|
|
368
|
+
0,
|
|
369
|
+
FVG_BORDER_STYLES.indexOf(cfg?.borderStyle ?? "solid")
|
|
370
|
+
),
|
|
371
|
+
borderWidth: cfg?.borderWidth ?? 1,
|
|
372
|
+
bullishBorderColor: color(cfg?.bullishBorderColor, bullish),
|
|
373
|
+
bearishBorderColor: color(cfg?.bearishBorderColor, bearish),
|
|
374
|
+
labelsEnabled: cfg?.showLabels ?? true,
|
|
375
|
+
label: cfg?.label ?? "FVG",
|
|
376
|
+
labelDistance: cfg?.labelDistance ?? 10,
|
|
377
|
+
// Alpha 0 is the core's "inherit the border color" sentinel.
|
|
378
|
+
labelColor: color(cfg?.labelColor, 0),
|
|
379
|
+
labelFontSize: cfg?.labelFontSize ?? 0,
|
|
380
|
+
showInverse: cfg?.showInverse ?? false,
|
|
381
|
+
inverseBullishColor: color(cfg?.inverseBullishColor, bullish),
|
|
382
|
+
inverseBearishColor: color(cfg?.inverseBearishColor, bearish),
|
|
383
|
+
inverseLabel: cfg?.inverseLabel ?? "iFVG"
|
|
384
|
+
};
|
|
385
|
+
}
|
|
304
386
|
function macdToSpec(cfg) {
|
|
305
387
|
const srcIdx = cfg?.source ? MA_SOURCES.indexOf(cfg.source) : 0;
|
|
306
388
|
return {
|
|
@@ -326,6 +408,15 @@ function macdToSpec(cfg) {
|
|
|
326
408
|
zeroVisible: cfg?.zeroLineVisible ?? true
|
|
327
409
|
};
|
|
328
410
|
}
|
|
411
|
+
function atrToSpec(cfg) {
|
|
412
|
+
return {
|
|
413
|
+
enabled: cfg?.enabled ?? false,
|
|
414
|
+
period: cfg?.period ?? 14,
|
|
415
|
+
smoothing: Math.max(0, ATR_SMOOTHINGS.indexOf(cfg?.smoothing ?? "rma")),
|
|
416
|
+
lineColor: inheritColor(cfg?.lineColor),
|
|
417
|
+
lineWidth: cfg?.lineWidth ?? -1
|
|
418
|
+
};
|
|
419
|
+
}
|
|
329
420
|
function volumeToSpec(cfg) {
|
|
330
421
|
return {
|
|
331
422
|
enabled: cfg?.enabled ?? true,
|
|
@@ -396,23 +487,37 @@ function ensureInstalled() {
|
|
|
396
487
|
}
|
|
397
488
|
installed = true;
|
|
398
489
|
}
|
|
399
|
-
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands, volume, priceLines, footprints, transition) {
|
|
490
|
+
function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, atr, movingAverages, vwap, bollingerBands, ichimoku, fairValueGaps, volume, priceLines, footprints, transition) {
|
|
400
491
|
const handleRef = (0, import_react.useRef)(null);
|
|
401
492
|
const defaultWidthAppliedRef = (0, import_react.useRef)(false);
|
|
402
493
|
const volumeCollapseRef = (0, import_react.useRef)(null);
|
|
403
494
|
const prevDataRef = (0, import_react.useRef)(null);
|
|
404
495
|
const intervalMorphRaf = (0, import_react.useRef)(null);
|
|
496
|
+
const streamRaf = (0, import_react.useRef)(null);
|
|
497
|
+
const streamWindowRef = (0, import_react.useRef)(null);
|
|
498
|
+
const streamMorphRef = (0, import_react.useRef)(false);
|
|
405
499
|
const [picture, setPicture] = (0, import_react.useState)(null);
|
|
406
500
|
if (!handleRef.current && size.width > 0 && size.height > 0) {
|
|
407
501
|
ensureInstalled();
|
|
408
502
|
handleRef.current = globalThis.VroomChartJSI.create();
|
|
409
503
|
}
|
|
410
|
-
const animRef = (0, import_react.useRef)({
|
|
504
|
+
const animRef = (0, import_react.useRef)({
|
|
505
|
+
ms: 300,
|
|
506
|
+
easing: void 0,
|
|
507
|
+
reduceMotion: false,
|
|
508
|
+
interval: "transform",
|
|
509
|
+
stream: "none",
|
|
510
|
+
streamMs: 150
|
|
511
|
+
});
|
|
411
512
|
animRef.current = {
|
|
412
513
|
ms: Math.max(0, transition?.transitionMs ?? 300),
|
|
413
514
|
easing: transition?.transitionEasing,
|
|
414
515
|
reduceMotion: transition?.reduceMotion ?? false,
|
|
415
|
-
interval: transition?.intervalTransition === "fade" ? "fade" : "transform"
|
|
516
|
+
interval: transition?.intervalTransition === "fade" ? "fade" : "transform",
|
|
517
|
+
stream: transition?.streamTransition === "transform" ? "transform" : "none",
|
|
518
|
+
// Shorter than transitionMs by default: ticks can land faster than a 300ms
|
|
519
|
+
// curve, and every one that does interrupts the last.
|
|
520
|
+
streamMs: Math.max(0, transition?.streamTransitionMs ?? 150)
|
|
416
521
|
};
|
|
417
522
|
const onFrameRef = (0, import_react.useRef)(transition?.onFrame);
|
|
418
523
|
onFrameRef.current = transition?.onFrame;
|
|
@@ -436,12 +541,70 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
436
541
|
};
|
|
437
542
|
intervalMorphRaf.current = requestAnimationFrame(step);
|
|
438
543
|
}, []);
|
|
544
|
+
const settleStream = (0, import_react.useCallback)((keepMorph = false) => {
|
|
545
|
+
if (streamRaf.current != null) {
|
|
546
|
+
cancelAnimationFrame(streamRaf.current);
|
|
547
|
+
streamRaf.current = null;
|
|
548
|
+
}
|
|
549
|
+
const h = handleRef.current;
|
|
550
|
+
const target = streamWindowRef.current;
|
|
551
|
+
streamWindowRef.current = null;
|
|
552
|
+
if (target) h?.setVisibleRange(target.startMs, target.endMs);
|
|
553
|
+
if (streamMorphRef.current && !keepMorph) {
|
|
554
|
+
streamMorphRef.current = false;
|
|
555
|
+
h?.setIntervalMorph(1);
|
|
556
|
+
}
|
|
557
|
+
}, []);
|
|
558
|
+
const startStreamAnim = (0, import_react.useCallback)(
|
|
559
|
+
(h, morphing, window) => {
|
|
560
|
+
const { streamMs, easing } = animRef.current;
|
|
561
|
+
let from = window ? h.getVisibleRange() : null;
|
|
562
|
+
let applied = null;
|
|
563
|
+
streamWindowRef.current = window;
|
|
564
|
+
streamMorphRef.current = morphing;
|
|
565
|
+
const start = performance.now();
|
|
566
|
+
const step = (now) => {
|
|
567
|
+
if (from && applied) {
|
|
568
|
+
const now_w = h.getVisibleRange();
|
|
569
|
+
if (now_w.startMs !== applied.startMs || now_w.endMs !== applied.endMs) {
|
|
570
|
+
from = null;
|
|
571
|
+
streamWindowRef.current = null;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
const p = Math.min(1, (now - start) / streamMs);
|
|
575
|
+
const e = p < 1 ? ease(easing, p) : 1;
|
|
576
|
+
if (morphing) h.setIntervalMorph(e);
|
|
577
|
+
if (from && window) {
|
|
578
|
+
applied = {
|
|
579
|
+
startMs: Math.round(from.startMs + (window.startMs - from.startMs) * e),
|
|
580
|
+
endMs: Math.round(from.endMs + (window.endMs - from.endMs) * e)
|
|
581
|
+
};
|
|
582
|
+
h.setVisibleRange(applied.startMs, applied.endMs);
|
|
583
|
+
}
|
|
584
|
+
const pic = h.render();
|
|
585
|
+
if (pic) onFrameRef.current?.(pic);
|
|
586
|
+
if (p < 1) {
|
|
587
|
+
streamRaf.current = requestAnimationFrame(step);
|
|
588
|
+
} else {
|
|
589
|
+
streamRaf.current = null;
|
|
590
|
+
streamWindowRef.current = null;
|
|
591
|
+
streamMorphRef.current = false;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
streamRaf.current = requestAnimationFrame(step);
|
|
595
|
+
},
|
|
596
|
+
[]
|
|
597
|
+
);
|
|
439
598
|
(0, import_react.useEffect)(() => {
|
|
440
599
|
return () => {
|
|
441
600
|
if (intervalMorphRaf.current != null) {
|
|
442
601
|
cancelAnimationFrame(intervalMorphRaf.current);
|
|
443
602
|
intervalMorphRaf.current = null;
|
|
444
603
|
}
|
|
604
|
+
if (streamRaf.current != null) {
|
|
605
|
+
cancelAnimationFrame(streamRaf.current);
|
|
606
|
+
streamRaf.current = null;
|
|
607
|
+
}
|
|
445
608
|
};
|
|
446
609
|
}, []);
|
|
447
610
|
const explicit = visibleRange != null;
|
|
@@ -450,9 +613,12 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
450
613
|
const themeKey = theme ? JSON.stringify(theme) : "";
|
|
451
614
|
const rsiKey = rsi ? JSON.stringify(rsi) : "";
|
|
452
615
|
const macdKey = macd ? JSON.stringify(macd) : "";
|
|
616
|
+
const atrKey = atr ? JSON.stringify(atr) : "";
|
|
453
617
|
const maKey = movingAverages ? JSON.stringify(movingAverages) : "";
|
|
454
618
|
const vwapKey = vwap ? JSON.stringify(vwap) : "";
|
|
455
619
|
const bollingerKey = bollingerBands ? JSON.stringify(bollingerBands) : "";
|
|
620
|
+
const ichimokuKey = ichimoku ? JSON.stringify(ichimoku) : "";
|
|
621
|
+
const fvgKey = fairValueGaps ? JSON.stringify(fairValueGaps) : "";
|
|
456
622
|
const volumeKey = volume ? JSON.stringify(volume) : "";
|
|
457
623
|
const priceLinesKey = priceLines ? JSON.stringify(priceLines) : "";
|
|
458
624
|
const footprintsKey = footprints ? JSON.stringify(footprints) : "";
|
|
@@ -460,6 +626,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
460
626
|
const h = handleRef.current;
|
|
461
627
|
if (!h) return;
|
|
462
628
|
h.setSize(size.width, size.height, size.pxRatio ?? 1);
|
|
629
|
+
h.setIchimoku(ichimokuToSpec(ichimoku));
|
|
463
630
|
if (!defaultWidthAppliedRef.current && !explicit && defaultCandleWidth != null && defaultCandleWidth > 0) {
|
|
464
631
|
h.setDefaultCandleWidth(defaultCandleWidth);
|
|
465
632
|
defaultWidthAppliedRef.current = true;
|
|
@@ -472,6 +639,36 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
472
639
|
const transitionKind = freshHandle ? "initial" : explicit ? "stream" : classifyTransition(prev.candles, candles, seriesKey !== prev.seriesKey);
|
|
473
640
|
let tfArgs = null;
|
|
474
641
|
let prevEnvelope = null;
|
|
642
|
+
let stream = null;
|
|
643
|
+
if (transitionKind === "stream" && prev != null && !explicit) {
|
|
644
|
+
const { stream: mode, streamMs, reduceMotion } = animRef.current;
|
|
645
|
+
const stepMs = inferStepMs(candles);
|
|
646
|
+
if (mode === "transform" && streamMs > 0 && stepMs != null && !reduceMotion && onFrameRef.current != null) {
|
|
647
|
+
const lastMs = candles[candles.length - 1].timeMs;
|
|
648
|
+
const prevLastMs = prev.candles[prev.candles.length - 1].timeMs;
|
|
649
|
+
if (classifyStream(prev.candles, candles) === "append") {
|
|
650
|
+
const w = h.getVisibleRange();
|
|
651
|
+
const prevStepMs = inferStepMs(prev.candles) ?? stepMs;
|
|
652
|
+
if (isPinnedToLatest(w, prevLastMs, prevStepMs)) {
|
|
653
|
+
const by = lastMs - prevLastMs;
|
|
654
|
+
stream = {
|
|
655
|
+
morph: false,
|
|
656
|
+
window: { startMs: w.startMs + by, endMs: w.endMs + by }
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
} else {
|
|
660
|
+
stream = { morph: true, window: null };
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
if (stream?.morph) {
|
|
664
|
+
settleStream(true);
|
|
665
|
+
h.beginStreamMorph();
|
|
666
|
+
} else {
|
|
667
|
+
settleStream();
|
|
668
|
+
}
|
|
669
|
+
} else if (transitionKind === "stream") {
|
|
670
|
+
settleStream();
|
|
671
|
+
}
|
|
475
672
|
if (transitionKind === "timeframe" && prev != null) {
|
|
476
673
|
const oldWindow = h.getVisibleRange();
|
|
477
674
|
const oldStepMs = inferStepMs(prev.candles);
|
|
@@ -507,6 +704,8 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
507
704
|
if (prevEnvelope) h.preservePriceEnvelope(prevEnvelope.low, prevEnvelope.high);
|
|
508
705
|
else h.resetPriceScale();
|
|
509
706
|
if (morphing) startIntervalMorph(h);
|
|
707
|
+
} else if (stream) {
|
|
708
|
+
startStreamAnim(h, stream.morph, stream.window);
|
|
510
709
|
} else if (transitionKind === "reset") {
|
|
511
710
|
h.resetView();
|
|
512
711
|
}
|
|
@@ -524,9 +723,11 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
524
723
|
}
|
|
525
724
|
h.setRSI(rsiToSpec(rsi));
|
|
526
725
|
h.setMACD(macdToSpec(macd));
|
|
726
|
+
h.setATR(atrToSpec(atr));
|
|
527
727
|
h.setOverlays((movingAverages ?? []).map(overlayToNumeric));
|
|
528
728
|
h.setVWAP(vwapToSpec(vwap));
|
|
529
729
|
h.setBollinger(bollingerToSpec(bollingerBands));
|
|
730
|
+
h.setFairValueGaps(fvgToSpec(fairValueGaps));
|
|
530
731
|
h.setVolume(volumeToSpec(volume));
|
|
531
732
|
const collapse = volumeCollapseRef.current;
|
|
532
733
|
if (collapse) h.setVolumeCollapse(collapse.t, collapse.easing);
|
|
@@ -537,7 +738,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
|
|
|
537
738
|
footprints?.prints.length ? footprintsToSpec(footprints) : EMPTY_FOOTPRINTS
|
|
538
739
|
);
|
|
539
740
|
if (!morphing) setPicture(h.render());
|
|
540
|
-
}, [candles, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, volumeKey, priceLinesKey, footprintsKey, startIntervalMorph, endIntervalMorph]);
|
|
741
|
+
}, [candles, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, atrKey, maKey, vwapKey, bollingerKey, ichimokuKey, fvgKey, volumeKey, priceLinesKey, footprintsKey, startIntervalMorph, endIntervalMorph, startStreamAnim, settleStream]);
|
|
541
742
|
return { handle: handleRef.current, picture, volumeCollapseRef };
|
|
542
743
|
}
|
|
543
744
|
|
|
@@ -559,12 +760,17 @@ function VroomChart(props) {
|
|
|
559
760
|
transitionMs,
|
|
560
761
|
transitionEasing,
|
|
561
762
|
intervalTransition,
|
|
763
|
+
streamTransition,
|
|
764
|
+
streamTransitionMs,
|
|
562
765
|
theme,
|
|
563
766
|
rsi,
|
|
564
767
|
macd,
|
|
768
|
+
atr,
|
|
565
769
|
movingAverages,
|
|
566
770
|
vwap,
|
|
567
771
|
bollingerBands,
|
|
772
|
+
ichimoku,
|
|
773
|
+
fairValueGaps,
|
|
568
774
|
volume,
|
|
569
775
|
crosshairOffset = 40,
|
|
570
776
|
onCrosshair,
|
|
@@ -643,13 +849,25 @@ function VroomChart(props) {
|
|
|
643
849
|
theme,
|
|
644
850
|
rsi,
|
|
645
851
|
macd,
|
|
852
|
+
atr,
|
|
646
853
|
movingAverages,
|
|
647
854
|
vwap,
|
|
648
855
|
bollingerBands,
|
|
856
|
+
ichimoku,
|
|
857
|
+
fairValueGaps,
|
|
649
858
|
volume,
|
|
650
859
|
priceLinesProp,
|
|
651
860
|
footprintsProp,
|
|
652
|
-
{
|
|
861
|
+
{
|
|
862
|
+
seriesKey,
|
|
863
|
+
transitionMs,
|
|
864
|
+
transitionEasing,
|
|
865
|
+
intervalTransition,
|
|
866
|
+
streamTransition,
|
|
867
|
+
streamTransitionMs,
|
|
868
|
+
reduceMotion,
|
|
869
|
+
onFrame
|
|
870
|
+
}
|
|
653
871
|
);
|
|
654
872
|
const crosshairActive = (0, import_react2.useRef)(false);
|
|
655
873
|
const footprintActive = (0, import_react2.useRef)(false);
|