react-native-vroom-chart 0.6.0 → 0.8.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.
Files changed (49) hide show
  1. package/cpp/VroomChartHostObject.cpp +281 -33
  2. package/cpp/_core_include/vroom/vroom_chart.h +231 -36
  3. package/cpp/_core_src/bollinger.h +1 -1
  4. package/cpp/_core_src/candles.cpp +138 -41
  5. package/cpp/_core_src/candles.h +11 -1
  6. package/cpp/_core_src/chart.cpp +91 -40
  7. package/cpp/_core_src/chart.h +69 -29
  8. package/cpp/_core_src/chart_facade.cpp +247 -69
  9. package/cpp/_core_src/drawings.cpp +147 -4
  10. package/cpp/_core_src/drawings.h +10 -5
  11. package/cpp/_core_src/gradient.cpp +46 -0
  12. package/cpp/_core_src/gradient.h +31 -0
  13. package/cpp/_core_src/labels.cpp +49 -16
  14. package/cpp/_core_src/labels.h +33 -4
  15. package/cpp/_core_src/liquidity.cpp +3 -37
  16. package/cpp/_core_src/ma_overlay.cpp +174 -12
  17. package/cpp/_core_src/ma_overlay.h +55 -3
  18. package/cpp/_core_src/macd.cpp +13 -42
  19. package/cpp/_core_src/macd.h +11 -8
  20. package/cpp/_core_src/macd_pane.cpp +57 -27
  21. package/cpp/_core_src/price_line_layout.h +1 -1
  22. package/cpp/_core_src/rsi.cpp +4 -18
  23. package/cpp/_core_src/rsi.h +6 -6
  24. package/cpp/_core_src/rsi_pane.cpp +34 -19
  25. package/cpp/_core_src/series_ma.cpp +64 -0
  26. package/cpp/_core_src/series_ma.h +30 -0
  27. package/cpp/_core_src/style_inherit.h +35 -0
  28. package/cpp/_core_src/theme.cpp +2 -1
  29. package/cpp/_core_src/viewport.cpp +36 -12
  30. package/cpp/_core_src/viewport.h +50 -0
  31. package/cpp/_core_src/volume.cpp +33 -8
  32. package/cpp/_core_src/volume.h +12 -1
  33. package/cpp/_core_src/volume_anim.cpp +32 -0
  34. package/cpp/_core_src/volume_anim.h +41 -0
  35. package/lib/index.d.mts +206 -31
  36. package/lib/index.d.ts +206 -31
  37. package/lib/index.js +324 -44
  38. package/lib/index.js.map +1 -1
  39. package/lib/index.mjs +329 -52
  40. package/lib/index.mjs.map +1 -1
  41. package/package.json +1 -1
  42. package/src/VroomChart.tsx +100 -17
  43. package/src/dataTransitions.ts +148 -0
  44. package/src/easing.ts +40 -0
  45. package/src/index.ts +9 -0
  46. package/src/jsi.d.ts +126 -19
  47. package/src/theme.ts +1 -0
  48. package/src/types.ts +3 -0
  49. package/src/useChartCore.ts +273 -30
@@ -29,7 +29,7 @@ ChartHostObject::~ChartHostObject() {
29
29
  std::vector<jsi::PropNameID> ChartHostObject::getPropertyNames(
30
30
  jsi::Runtime& rt) {
31
31
  std::vector<jsi::PropNameID> out;
32
- out.reserve(29);
32
+ out.reserve(39);
33
33
  out.push_back(jsi::PropNameID::forAscii(rt, "setCandles"));
34
34
  out.push_back(jsi::PropNameID::forAscii(rt, "setSize"));
35
35
  out.push_back(jsi::PropNameID::forAscii(rt, "setColor"));
@@ -38,6 +38,13 @@ std::vector<jsi::PropNameID> ChartHostObject::getPropertyNames(
38
38
  out.push_back(jsi::PropNameID::forAscii(rt, "setDefaultCandleWidth"));
39
39
  out.push_back(jsi::PropNameID::forAscii(rt, "setChartType"));
40
40
  out.push_back(jsi::PropNameID::forAscii(rt, "setMorph"));
41
+ out.push_back(jsi::PropNameID::forAscii(rt, "getVisibleRange"));
42
+ out.push_back(jsi::PropNameID::forAscii(rt, "resetView"));
43
+ out.push_back(jsi::PropNameID::forAscii(rt, "resetPriceScale"));
44
+ out.push_back(jsi::PropNameID::forAscii(rt, "getVisiblePriceEnvelope"));
45
+ out.push_back(jsi::PropNameID::forAscii(rt, "preservePriceEnvelope"));
46
+ out.push_back(jsi::PropNameID::forAscii(rt, "beginIntervalMorph"));
47
+ out.push_back(jsi::PropNameID::forAscii(rt, "setIntervalMorph"));
41
48
  out.push_back(jsi::PropNameID::forAscii(rt, "pan"));
42
49
  out.push_back(jsi::PropNameID::forAscii(rt, "translate"));
43
50
  out.push_back(jsi::PropNameID::forAscii(rt, "zoom"));
@@ -54,6 +61,8 @@ std::vector<jsi::PropNameID> ChartHostObject::getPropertyNames(
54
61
  out.push_back(jsi::PropNameID::forAscii(rt, "setOverlays"));
55
62
  out.push_back(jsi::PropNameID::forAscii(rt, "setVWAP"));
56
63
  out.push_back(jsi::PropNameID::forAscii(rt, "setBollinger"));
64
+ out.push_back(jsi::PropNameID::forAscii(rt, "setVolume"));
65
+ out.push_back(jsi::PropNameID::forAscii(rt, "setVolumeCollapse"));
57
66
  out.push_back(jsi::PropNameID::forAscii(rt, "coordAt"));
58
67
  out.push_back(jsi::PropNameID::forAscii(rt, "setPriceLines"));
59
68
  out.push_back(jsi::PropNameID::forAscii(rt, "hitTestPriceLine"));
@@ -295,6 +304,129 @@ jsi::Value ChartHostObject::get(jsi::Runtime& rt,
295
304
  });
296
305
  }
297
306
 
307
+ if (name == "getVisibleRange") {
308
+ // getVisibleRange() -> { startMs, endMs }. Both 0 while uninitialized.
309
+ return jsi::Function::createFromHostFunction(
310
+ rt,
311
+ jsi::PropNameID::forAscii(rt, "getVisibleRange"),
312
+ 0,
313
+ [this](jsi::Runtime& rt2,
314
+ const jsi::Value& /*thisVal*/,
315
+ const jsi::Value* /*args*/,
316
+ size_t /*count*/) -> jsi::Value {
317
+ int64_t s = 0, e = 0;
318
+ vroom_chart_get_visible_range(chart_, &s, &e);
319
+ jsi::Object obj(rt2);
320
+ obj.setProperty(rt2, "startMs", static_cast<double>(s));
321
+ obj.setProperty(rt2, "endMs", static_cast<double>(e));
322
+ return obj;
323
+ });
324
+ }
325
+
326
+ if (name == "resetView") {
327
+ // resetView() — reframe the most recent candles and re-enable y auto-fit.
328
+ return jsi::Function::createFromHostFunction(
329
+ rt,
330
+ jsi::PropNameID::forAscii(rt, "resetView"),
331
+ 0,
332
+ [this](jsi::Runtime& /*rt2*/,
333
+ const jsi::Value& /*thisVal*/,
334
+ const jsi::Value* /*args*/,
335
+ size_t /*count*/) -> jsi::Value {
336
+ vroom_chart_reset_view(chart_);
337
+ return jsi::Value::undefined();
338
+ });
339
+ }
340
+
341
+ if (name == "resetPriceScale") {
342
+ // resetPriceScale() — re-enable y auto-fit, leaving the time window alone.
343
+ return jsi::Function::createFromHostFunction(
344
+ rt,
345
+ jsi::PropNameID::forAscii(rt, "resetPriceScale"),
346
+ 0,
347
+ [this](jsi::Runtime& /*rt2*/,
348
+ const jsi::Value& /*thisVal*/,
349
+ const jsi::Value* /*args*/,
350
+ size_t /*count*/) -> jsi::Value {
351
+ vroom_chart_reset_price_scale(chart_);
352
+ return jsi::Value::undefined();
353
+ });
354
+ }
355
+
356
+ if (name == "getVisiblePriceEnvelope") {
357
+ // getVisiblePriceEnvelope() -> { low, high } | null. The extent the visible
358
+ // candles occupy, not the (wider) axis range. No rendering.
359
+ return jsi::Function::createFromHostFunction(
360
+ rt,
361
+ jsi::PropNameID::forAscii(rt, "getVisiblePriceEnvelope"),
362
+ 0,
363
+ [this](jsi::Runtime& rt2,
364
+ const jsi::Value& /*thisVal*/,
365
+ const jsi::Value* /*args*/,
366
+ size_t /*count*/) -> jsi::Value {
367
+ double low = 0.0, high = 0.0;
368
+ if (!vroom_chart_get_visible_price_envelope(chart_, &low, &high)) {
369
+ return jsi::Value::null();
370
+ }
371
+ jsi::Object obj(rt2);
372
+ obj.setProperty(rt2, "low", low);
373
+ obj.setProperty(rt2, "high", high);
374
+ return obj;
375
+ });
376
+ }
377
+
378
+ if (name == "preservePriceEnvelope") {
379
+ // preservePriceEnvelope(prevLow, prevHigh) — scale-lock a manual price
380
+ // range across a timeframe switch. No-op in auto-y mode.
381
+ return jsi::Function::createFromHostFunction(
382
+ rt,
383
+ jsi::PropNameID::forAscii(rt, "preservePriceEnvelope"),
384
+ 2,
385
+ [this](jsi::Runtime& /*rt2*/,
386
+ const jsi::Value& /*thisVal*/,
387
+ const jsi::Value* args,
388
+ size_t count) -> jsi::Value {
389
+ if (count < 2) return jsi::Value::undefined();
390
+ vroom_chart_preserve_price_envelope(chart_, args[0].asNumber(),
391
+ args[1].asNumber());
392
+ return jsi::Value::undefined();
393
+ });
394
+ }
395
+
396
+ if (name == "beginIntervalMorph") {
397
+ // beginIntervalMorph() — capture the visible candle geometry so the next
398
+ // setCandles can be animated as a reshape. Call before setCandles.
399
+ return jsi::Function::createFromHostFunction(
400
+ rt,
401
+ jsi::PropNameID::forAscii(rt, "beginIntervalMorph"),
402
+ 0,
403
+ [this](jsi::Runtime& /*rt2*/,
404
+ const jsi::Value& /*thisVal*/,
405
+ const jsi::Value* /*args*/,
406
+ size_t /*count*/) -> jsi::Value {
407
+ vroom_chart_begin_interval_morph(chart_);
408
+ return jsi::Value::undefined();
409
+ });
410
+ }
411
+
412
+ if (name == "setIntervalMorph") {
413
+ // setIntervalMorph(t) — advance the capture toward the new candles. `t` is
414
+ // pre-eased progress: 0 = the captured frame, 1 = settled (capture freed).
415
+ return jsi::Function::createFromHostFunction(
416
+ rt,
417
+ jsi::PropNameID::forAscii(rt, "setIntervalMorph"),
418
+ 1,
419
+ [this](jsi::Runtime& /*rt2*/,
420
+ const jsi::Value& /*thisVal*/,
421
+ const jsi::Value* args,
422
+ size_t count) -> jsi::Value {
423
+ if (count < 1) return jsi::Value::undefined();
424
+ vroom_chart_set_interval_morph(
425
+ chart_, static_cast<float>(args[0].asNumber()));
426
+ return jsi::Value::undefined();
427
+ });
428
+ }
429
+
298
430
  if (name == "pan") {
299
431
  // pan(dx, dy) -> JsiSkPicture
300
432
  // Mutates the visible range and renders in one JSI call so gesture
@@ -519,46 +651,106 @@ jsi::Value ChartHostObject::get(jsi::Runtime& rt,
519
651
  }
520
652
 
521
653
  if (name == "setRSI") {
522
- // setRSI(enabled, period, upperBand, lowerBand, maEnabled, maPeriod) —
523
- // configures the RSI pane. No render; the next render() picks it up.
654
+ // setRSI({enabled, period, upperBand, lowerBand, maPeriod, maKind,
655
+ // maVisible, lineColor, lineWidth, lineVisible, maColor, maWidth,
656
+ // bandColor, bandsVisible}) — configures the RSI pane. No render; the next
657
+ // render() picks it up.
524
658
  return jsi::Function::createFromHostFunction(
525
659
  rt,
526
660
  jsi::PropNameID::forAscii(rt, "setRSI"),
527
- 6,
528
- [this](jsi::Runtime& /*rt2*/,
661
+ 1,
662
+ [this](jsi::Runtime& rt2,
529
663
  const jsi::Value& /*thisVal*/,
530
664
  const jsi::Value* args,
531
665
  size_t count) -> jsi::Value {
532
- if (count < 6) return jsi::Value::undefined();
533
- const bool enabled = args[0].asBool();
534
- const int period = static_cast<int>(args[1].asNumber());
535
- const double upper = args[2].asNumber();
536
- const double lower = args[3].asNumber();
537
- const bool ma_enabled = args[4].asBool();
538
- const int ma_period = static_cast<int>(args[5].asNumber());
539
- vroom_chart_set_rsi(chart_, enabled, period, upper, lower, ma_enabled,
540
- ma_period);
666
+ if (count < 1 || !args[0].isObject()) return jsi::Value::undefined();
667
+ auto s = args[0].asObject(rt2);
668
+ VroomRSI cfg{};
669
+ cfg.enabled = s.getProperty(rt2, "enabled").asBool() ? 1 : 0;
670
+ cfg.period = static_cast<int32_t>(
671
+ s.getProperty(rt2, "period").asNumber());
672
+ cfg.upper_band = s.getProperty(rt2, "upperBand").asNumber();
673
+ cfg.lower_band = s.getProperty(rt2, "lowerBand").asNumber();
674
+ cfg.ma_period = static_cast<int32_t>(
675
+ s.getProperty(rt2, "maPeriod").asNumber());
676
+ cfg.ma_kind = static_cast<int32_t>(
677
+ s.getProperty(rt2, "maKind").asNumber());
678
+ cfg.ma_visible = s.getProperty(rt2, "maVisible").asBool() ? 1 : 0;
679
+ cfg.line_color = static_cast<uint32_t>(
680
+ s.getProperty(rt2, "lineColor").asNumber());
681
+ cfg.line_width = static_cast<float>(
682
+ s.getProperty(rt2, "lineWidth").asNumber());
683
+ cfg.line_visible = s.getProperty(rt2, "lineVisible").asBool() ? 1 : 0;
684
+ cfg.ma_color = static_cast<uint32_t>(
685
+ s.getProperty(rt2, "maColor").asNumber());
686
+ cfg.ma_width = static_cast<float>(
687
+ s.getProperty(rt2, "maWidth").asNumber());
688
+ cfg.band_color = static_cast<uint32_t>(
689
+ s.getProperty(rt2, "bandColor").asNumber());
690
+ cfg.bands_visible =
691
+ s.getProperty(rt2, "bandsVisible").asBool() ? 1 : 0;
692
+ vroom_chart_set_rsi(chart_, &cfg);
541
693
  return jsi::Value::undefined();
542
694
  });
543
695
  }
544
696
 
545
697
  if (name == "setMACD") {
546
- // setMACD(enabled, fast, slow, signal) configures the MACD pane. No
547
- // render; the next render() picks it up.
698
+ // setMACD({enabled, fast, slow, signal, source, maKind, signalMaKind,
699
+ // lineColor, lineWidth, lineVisible, signalColor, signalWidth,
700
+ // signalVisible, histVisible, histUpColor, histUpFadingColor,
701
+ // histDownColor, histDownFadingColor, zeroColor, zeroVisible}) — configures
702
+ // the MACD pane. No render; the next render() picks it up.
548
703
  return jsi::Function::createFromHostFunction(
549
704
  rt,
550
705
  jsi::PropNameID::forAscii(rt, "setMACD"),
551
- 4,
552
- [this](jsi::Runtime& /*rt2*/,
706
+ 1,
707
+ [this](jsi::Runtime& rt2,
553
708
  const jsi::Value& /*thisVal*/,
554
709
  const jsi::Value* args,
555
710
  size_t count) -> jsi::Value {
556
- if (count < 4) return jsi::Value::undefined();
557
- const bool enabled = args[0].asBool();
558
- const int fast = static_cast<int>(args[1].asNumber());
559
- const int slow = static_cast<int>(args[2].asNumber());
560
- const int signal = static_cast<int>(args[3].asNumber());
561
- vroom_chart_set_macd(chart_, enabled, fast, slow, signal);
711
+ if (count < 1 || !args[0].isObject()) return jsi::Value::undefined();
712
+ auto s = args[0].asObject(rt2);
713
+ VroomMACD cfg{};
714
+ cfg.enabled = s.getProperty(rt2, "enabled").asBool() ? 1 : 0;
715
+ cfg.fast = static_cast<int32_t>(
716
+ s.getProperty(rt2, "fast").asNumber());
717
+ cfg.slow = static_cast<int32_t>(
718
+ s.getProperty(rt2, "slow").asNumber());
719
+ cfg.signal = static_cast<int32_t>(
720
+ s.getProperty(rt2, "signal").asNumber());
721
+ cfg.source = static_cast<int32_t>(
722
+ s.getProperty(rt2, "source").asNumber());
723
+ cfg.ma_kind = static_cast<int32_t>(
724
+ s.getProperty(rt2, "maKind").asNumber());
725
+ cfg.signal_ma_kind = static_cast<int32_t>(
726
+ s.getProperty(rt2, "signalMaKind").asNumber());
727
+ cfg.line_color = static_cast<uint32_t>(
728
+ s.getProperty(rt2, "lineColor").asNumber());
729
+ cfg.line_width = static_cast<float>(
730
+ s.getProperty(rt2, "lineWidth").asNumber());
731
+ cfg.line_visible =
732
+ s.getProperty(rt2, "lineVisible").asBool() ? 1 : 0;
733
+ cfg.signal_color = static_cast<uint32_t>(
734
+ s.getProperty(rt2, "signalColor").asNumber());
735
+ cfg.signal_width = static_cast<float>(
736
+ s.getProperty(rt2, "signalWidth").asNumber());
737
+ cfg.signal_visible =
738
+ s.getProperty(rt2, "signalVisible").asBool() ? 1 : 0;
739
+ cfg.hist_visible =
740
+ s.getProperty(rt2, "histVisible").asBool() ? 1 : 0;
741
+ cfg.hist_up_color = static_cast<uint32_t>(
742
+ s.getProperty(rt2, "histUpColor").asNumber());
743
+ cfg.hist_up_fading_color = static_cast<uint32_t>(
744
+ s.getProperty(rt2, "histUpFadingColor").asNumber());
745
+ cfg.hist_down_color = static_cast<uint32_t>(
746
+ s.getProperty(rt2, "histDownColor").asNumber());
747
+ cfg.hist_down_fading_color = static_cast<uint32_t>(
748
+ s.getProperty(rt2, "histDownFadingColor").asNumber());
749
+ cfg.zero_color = static_cast<uint32_t>(
750
+ s.getProperty(rt2, "zeroColor").asNumber());
751
+ cfg.zero_visible =
752
+ s.getProperty(rt2, "zeroVisible").asBool() ? 1 : 0;
753
+ vroom_chart_set_macd(chart_, &cfg);
562
754
  return jsi::Value::undefined();
563
755
  });
564
756
  }
@@ -602,21 +794,26 @@ jsi::Value ChartHostObject::get(jsi::Runtime& rt,
602
794
  }
603
795
 
604
796
  if (name == "setVWAP") {
605
- // setVWAP(enabled, resetOffsetMin, color, width) — session VWAP overlay.
797
+ // setVWAP({enabled, resetOffsetMin, color, width}) — session VWAP overlay.
606
798
  return jsi::Function::createFromHostFunction(
607
799
  rt,
608
800
  jsi::PropNameID::forAscii(rt, "setVWAP"),
609
- 4,
610
- [this](jsi::Runtime& /*rt2*/,
801
+ 1,
802
+ [this](jsi::Runtime& rt2,
611
803
  const jsi::Value& /*thisVal*/,
612
804
  const jsi::Value* args,
613
805
  size_t count) -> jsi::Value {
614
- if (count < 4) return jsi::Value::undefined();
615
- const bool enabled = args[0].asBool();
616
- const int reset = static_cast<int>(args[1].asNumber());
617
- const uint32_t color = static_cast<uint32_t>(args[2].asNumber());
618
- const float width = static_cast<float>(args[3].asNumber());
619
- vroom_chart_set_vwap(chart_, enabled, reset, color, width);
806
+ if (count < 1 || !args[0].isObject()) return jsi::Value::undefined();
807
+ auto s = args[0].asObject(rt2);
808
+ VroomVWAP cfg{};
809
+ cfg.enabled = s.getProperty(rt2, "enabled").asBool() ? 1 : 0;
810
+ cfg.reset_offset_min = static_cast<int32_t>(
811
+ s.getProperty(rt2, "resetOffsetMin").asNumber());
812
+ cfg.color = static_cast<uint32_t>(
813
+ s.getProperty(rt2, "color").asNumber());
814
+ cfg.width = static_cast<float>(
815
+ s.getProperty(rt2, "width").asNumber());
816
+ vroom_chart_set_vwap(chart_, &cfg);
620
817
  return jsi::Value::undefined();
621
818
  });
622
819
  }
@@ -667,6 +864,57 @@ jsi::Value ChartHostObject::get(jsi::Runtime& rt,
667
864
  });
668
865
  }
669
866
 
867
+ if (name == "setVolume") {
868
+ // setVolume({enabled, heightFrac, opacity, radiusPx, upColor, downColor})
869
+ // — the volume bars. Negative floats / zero colors inherit the theme. No
870
+ // render; the next render() picks it up.
871
+ return jsi::Function::createFromHostFunction(
872
+ rt,
873
+ jsi::PropNameID::forAscii(rt, "setVolume"),
874
+ 1,
875
+ [this](jsi::Runtime& rt2,
876
+ const jsi::Value& /*thisVal*/,
877
+ const jsi::Value* args,
878
+ size_t count) -> jsi::Value {
879
+ if (count < 1 || !args[0].isObject()) return jsi::Value::undefined();
880
+ auto s = args[0].asObject(rt2);
881
+ VroomVolume cfg{};
882
+ cfg.enabled = s.getProperty(rt2, "enabled").asBool() ? 1 : 0;
883
+ cfg.height_frac = static_cast<float>(
884
+ s.getProperty(rt2, "heightFrac").asNumber());
885
+ cfg.opacity = static_cast<float>(
886
+ s.getProperty(rt2, "opacity").asNumber());
887
+ cfg.radius_px = static_cast<float>(
888
+ s.getProperty(rt2, "radiusPx").asNumber());
889
+ cfg.up_color = static_cast<uint32_t>(
890
+ s.getProperty(rt2, "upColor").asNumber());
891
+ cfg.down_color = static_cast<uint32_t>(
892
+ s.getProperty(rt2, "downColor").asNumber());
893
+ vroom_chart_set_volume(chart_, &cfg);
894
+ return jsi::Value::undefined();
895
+ });
896
+ }
897
+
898
+ if (name == "setVolumeCollapse") {
899
+ // setVolumeCollapse(t, easing) — staggered collapse of the volume bars. `t`
900
+ // is LINEAR progress; the core eases each bar over its own window.
901
+ return jsi::Function::createFromHostFunction(
902
+ rt,
903
+ jsi::PropNameID::forAscii(rt, "setVolumeCollapse"),
904
+ 2,
905
+ [this](jsi::Runtime& /*rt2*/,
906
+ const jsi::Value& /*thisVal*/,
907
+ const jsi::Value* args,
908
+ size_t count) -> jsi::Value {
909
+ if (count < 2) return jsi::Value::undefined();
910
+ vroom_chart_set_volume_collapse(
911
+ chart_,
912
+ static_cast<float>(args[0].asNumber()),
913
+ static_cast<int32_t>(args[1].asNumber()));
914
+ return jsi::Value::undefined();
915
+ });
916
+ }
917
+
670
918
  if (name == "coordAt") {
671
919
  // coordAt(x, y) -> { timeMs, price } | null. The continuous data coordinate
672
920
  // at a pixel — not snapped to a candle slot. Null when there are no candles