react-native-vroom-chart 0.14.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 +289 -2
- package/cpp/_core_include/vroom/vroom_chart.h +221 -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 +477 -172
- package/cpp/_core_src/chart.h +173 -1
- package/cpp/_core_src/chart_facade.cpp +317 -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/footprints.cpp +226 -0
- package/cpp/_core_src/footprints.h +45 -0
- package/cpp/_core_src/footprints_layout.cpp +140 -0
- package/cpp/_core_src/footprints_layout.h +94 -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/tip_pulse.h +4 -4
- package/cpp/_core_src/viewport.h +35 -0
- package/lib/index.d.mts +385 -3
- package/lib/index.d.ts +385 -3
- package/lib/index.js +305 -7
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +305 -7
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/VroomChart.tsx +108 -7
- package/src/dataTransitions.ts +47 -0
- package/src/index.ts +10 -0
- package/src/jsi.d.ts +136 -1
- package/src/types.ts +10 -0
- package/src/useChartCore.ts +330 -5
package/src/VroomChart.tsx
CHANGED
|
@@ -36,9 +36,12 @@ import { useReducedMotion, useSharedValue } from 'react-native-reanimated';
|
|
|
36
36
|
import { useChartCore } from './useChartCore';
|
|
37
37
|
import { ease, easingIndex } from './easing';
|
|
38
38
|
import type { ChartFrame } from './jsi.d';
|
|
39
|
-
import type { VroomChartProps } from './types';
|
|
39
|
+
import type { Footprint, VroomChartProps } from './types';
|
|
40
40
|
import './jsi.d';
|
|
41
41
|
|
|
42
|
+
// Mirrors VroomFootprintSide in packages/core/include/vroom/vroom_chart.h.
|
|
43
|
+
const FOOTPRINT_SELL = 1;
|
|
44
|
+
|
|
42
45
|
function isSkImage(frame: ChartFrame): frame is SkImage {
|
|
43
46
|
return typeof (frame as SkImage).getImageInfo === 'function';
|
|
44
47
|
}
|
|
@@ -47,8 +50,9 @@ function isSkImage(frame: ChartFrame): frame is SkImage {
|
|
|
47
50
|
* Skia-rendered candlestick chart. Pass OHLCV `candles` and size it via `style`
|
|
48
51
|
* (it fills its parent by default). Pan to scroll, pinch to zoom, drag the
|
|
49
52
|
* price/time axes to rescale, and long-press for the crosshair. Optional
|
|
50
|
-
* indicators (`rsi`, `macd`, `movingAverages`, `vwap
|
|
51
|
-
*
|
|
53
|
+
* indicators (`rsi`, `macd`, `movingAverages`, `vwap`, `bollingerBands`,
|
|
54
|
+
* `ichimoku`, and more), colors (`theme`), and events (`onCrosshair`,
|
|
55
|
+
* `onViewportChange`) are configured through props.
|
|
52
56
|
*
|
|
53
57
|
* @see {@link VroomChartProps} for the full prop reference.
|
|
54
58
|
*/
|
|
@@ -65,12 +69,17 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
65
69
|
transitionMs,
|
|
66
70
|
transitionEasing,
|
|
67
71
|
intervalTransition,
|
|
72
|
+
streamTransition,
|
|
73
|
+
streamTransitionMs,
|
|
68
74
|
theme,
|
|
69
75
|
rsi,
|
|
70
76
|
macd,
|
|
77
|
+
atr,
|
|
71
78
|
movingAverages,
|
|
72
79
|
vwap,
|
|
73
80
|
bollingerBands,
|
|
81
|
+
ichimoku,
|
|
82
|
+
fairValueGaps,
|
|
74
83
|
volume,
|
|
75
84
|
crosshairOffset = 40,
|
|
76
85
|
onCrosshair,
|
|
@@ -80,6 +89,9 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
80
89
|
onPriceLineDrag,
|
|
81
90
|
onPriceLineDragEnd,
|
|
82
91
|
onPriceLineClose,
|
|
92
|
+
footprints,
|
|
93
|
+
footprintsStyle,
|
|
94
|
+
onFootprint,
|
|
83
95
|
} = props;
|
|
84
96
|
|
|
85
97
|
// Fill the parent by default: measure via onLayout. Explicit width/height
|
|
@@ -111,6 +123,11 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
111
123
|
[priceLines, priceLinesStyle, onPriceLineClose],
|
|
112
124
|
);
|
|
113
125
|
|
|
126
|
+
const footprintsProp = useMemo(
|
|
127
|
+
() => (footprints ? { prints: footprints, style: footprintsStyle } : undefined),
|
|
128
|
+
[footprints, footprintsStyle],
|
|
129
|
+
);
|
|
130
|
+
|
|
114
131
|
// RN-Skia's recorder reads these SharedValues on the UI/render runtime, a
|
|
115
132
|
// beat behind JS-thread writes. If it ever reads null it throws ("Invalid
|
|
116
133
|
// prop value for SkTextBlob received" — RN-Skia's mislabeled SkPicture
|
|
@@ -168,12 +185,25 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
168
185
|
theme,
|
|
169
186
|
rsi,
|
|
170
187
|
macd,
|
|
188
|
+
atr,
|
|
171
189
|
movingAverages,
|
|
172
190
|
vwap,
|
|
173
191
|
bollingerBands,
|
|
192
|
+
ichimoku,
|
|
193
|
+
fairValueGaps,
|
|
174
194
|
volume,
|
|
175
195
|
priceLinesProp,
|
|
176
|
-
|
|
196
|
+
footprintsProp,
|
|
197
|
+
{
|
|
198
|
+
seriesKey,
|
|
199
|
+
transitionMs,
|
|
200
|
+
transitionEasing,
|
|
201
|
+
intervalTransition,
|
|
202
|
+
streamTransition,
|
|
203
|
+
streamTransitionMs,
|
|
204
|
+
reduceMotion,
|
|
205
|
+
onFrame,
|
|
206
|
+
},
|
|
177
207
|
);
|
|
178
208
|
|
|
179
209
|
// When the crosshair is showing, pan moves it (instead of scrolling) and
|
|
@@ -181,6 +211,11 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
181
211
|
// synchronously without re-subscribing. Tap dismisses it.
|
|
182
212
|
const crosshairActive = useRef(false);
|
|
183
213
|
|
|
214
|
+
// Whether a footprint badge is currently open, so a tap that misses every badge
|
|
215
|
+
// knows whether it has a tooltip to dismiss. A ref for the same reason as
|
|
216
|
+
// crosshairActive: gesture callbacks read it synchronously.
|
|
217
|
+
const footprintActive = useRef(false);
|
|
218
|
+
|
|
184
219
|
// timeMs of the candle last reported through onCrosshair, so a drag fires a
|
|
185
220
|
// 'move' event only when it crosses into a *different* candle (one per
|
|
186
221
|
// candle, not per frame). Null while the crosshair is hidden.
|
|
@@ -539,6 +574,31 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
539
574
|
'chart' | 'price-axis' | 'time-axis' | 'indicator' | 'price-line'
|
|
540
575
|
>('chart');
|
|
541
576
|
|
|
577
|
+
// Closes an open footprint tooltip. Any viewport change slides the candles out
|
|
578
|
+
// from under it and the crosshair replaces it outright, so the host is told to
|
|
579
|
+
// take it down rather than left holding a position the badge has moved away
|
|
580
|
+
// from. `redraw` is false for callers that render a frame of their own right
|
|
581
|
+
// after — on Android that render rasterizes pixels, so the duplicate is worth
|
|
582
|
+
// skipping.
|
|
583
|
+
const dismissFootprint = (redraw = true) => {
|
|
584
|
+
if (!handle || !footprintActive.current) return;
|
|
585
|
+
footprintActive.current = false;
|
|
586
|
+
handle.setFootprintHover(0, -1);
|
|
587
|
+
if (redraw) {
|
|
588
|
+
const frame = handle.render();
|
|
589
|
+
if (frame) applyFrame(frame);
|
|
590
|
+
}
|
|
591
|
+
onFootprint?.({
|
|
592
|
+
active: false,
|
|
593
|
+
reason: 'hide',
|
|
594
|
+
side: null,
|
|
595
|
+
timeMs: null,
|
|
596
|
+
footprints: [],
|
|
597
|
+
badge: null,
|
|
598
|
+
pane: null,
|
|
599
|
+
});
|
|
600
|
+
};
|
|
601
|
+
|
|
542
602
|
const pan = Gesture.Pan()
|
|
543
603
|
.runOnJS(true)
|
|
544
604
|
.maxPointers(1) // don't fight Pinch's two-finger gesture
|
|
@@ -561,6 +621,10 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
561
621
|
if (p) applyFrame(p);
|
|
562
622
|
}
|
|
563
623
|
}
|
|
624
|
+
// Every mode but a price-line drag moves the viewport, and this one call
|
|
625
|
+
// covers the momentum fling too — decay only ever starts from a pan that
|
|
626
|
+
// already began here.
|
|
627
|
+
if (panMode.current !== 'price-line') dismissFootprint();
|
|
564
628
|
})
|
|
565
629
|
.onChange((e) => {
|
|
566
630
|
if (!handle) return;
|
|
@@ -684,6 +748,7 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
684
748
|
.runOnJS(true)
|
|
685
749
|
.onTouchesDown((e) => {
|
|
686
750
|
if (e.numberOfTouches < 2) return;
|
|
751
|
+
dismissFootprint();
|
|
687
752
|
const [a, b] = e.allTouches;
|
|
688
753
|
const spanX = Math.abs(a.x - b.x);
|
|
689
754
|
const spanY = Math.abs(a.y - b.y);
|
|
@@ -739,6 +804,10 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
739
804
|
// close button — so it must not raise the crosshair over the top.
|
|
740
805
|
if (hitPriceLine(e.x, e.y)) return;
|
|
741
806
|
cancelDecay();
|
|
807
|
+
// The crosshair takes the pane over, so it can't share it with a tooltip.
|
|
808
|
+
// No redraw: setCrosshair below returns a frame that already has the badge
|
|
809
|
+
// un-highlighted.
|
|
810
|
+
dismissFootprint(false);
|
|
742
811
|
crosshairActive.current = true;
|
|
743
812
|
const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);
|
|
744
813
|
if (ch) applyFrame(ch);
|
|
@@ -753,13 +822,45 @@ export function VroomChart(props: VroomChartProps) {
|
|
|
753
822
|
});
|
|
754
823
|
});
|
|
755
824
|
|
|
756
|
-
// A tap activates a price line's close button,
|
|
757
|
-
// crosshair while it's up. Any other tap is a
|
|
758
|
-
// with normal pan/pinch.
|
|
825
|
+
// A tap activates a price line's close button, selects or dismisses a footprint
|
|
826
|
+
// badge, and otherwise dismisses the crosshair while it's up. Any other tap is a
|
|
827
|
+
// no-op, so it never interferes with normal pan/pinch.
|
|
759
828
|
const tap = Gesture.Tap()
|
|
760
829
|
.runOnJS(true)
|
|
761
830
|
.onStart((e) => {
|
|
762
831
|
if (!handle) return;
|
|
832
|
+
|
|
833
|
+
// Badges get first refusal: one is a ~9px circle, while a price line's grab
|
|
834
|
+
// band spans the pane and would otherwise swallow any badge it crosses.
|
|
835
|
+
// Touch has no hover, so a tap is what opens a footprint here, and the next
|
|
836
|
+
// tap anywhere closes it.
|
|
837
|
+
const prints = footprints ?? [];
|
|
838
|
+
const fp = prints.length ? handle.hitTestFootprint(e.x, e.y) : null;
|
|
839
|
+
if (fp) {
|
|
840
|
+
handle.setFootprintHover(fp.candleTimeMs, fp.side);
|
|
841
|
+
const frame = handle.render();
|
|
842
|
+
if (frame) applyFrame(frame);
|
|
843
|
+
const wasActive = footprintActive.current;
|
|
844
|
+
footprintActive.current = true;
|
|
845
|
+
onFootprint?.({
|
|
846
|
+
active: true,
|
|
847
|
+
reason: wasActive ? 'move' : 'show',
|
|
848
|
+
side: fp.side === FOOTPRINT_SELL ? 'sell' : 'buy',
|
|
849
|
+
timeMs: fp.candleTimeMs,
|
|
850
|
+
// The core reports indices into the array we last pushed, which is this
|
|
851
|
+
// same prop — so this rejoins each badge to the consumer's own objects.
|
|
852
|
+
footprints: fp.indices
|
|
853
|
+
.map((i) => prints[i])
|
|
854
|
+
.filter((f): f is Footprint => f != null),
|
|
855
|
+
badge: { x: fp.x, y: fp.y, radius: fp.radius },
|
|
856
|
+
pane: fp.pane,
|
|
857
|
+
});
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
// A tap that missed every badge dismisses the open one, so the host tooltip
|
|
861
|
+
// goes away the same way the crosshair does.
|
|
862
|
+
dismissFootprint();
|
|
863
|
+
|
|
763
864
|
// The close button is a tap target whether or not the crosshair is up.
|
|
764
865
|
const pl = hitPriceLine(e.x, e.y);
|
|
765
866
|
if (pl && pl.part === 1) {
|
package/src/dataTransitions.ts
CHANGED
|
@@ -126,6 +126,53 @@ export function classifyTransition(
|
|
|
126
126
|
return closeRatio <= MAX_SAME_ASSET_CLOSE_RATIO && endsTogether ? 'timeframe' : 'reset';
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* What a `'stream'` update did to the series: `'tick'` revised the bar already
|
|
131
|
+
* on screen, `'append'` brought at least one new one.
|
|
132
|
+
*
|
|
133
|
+
* The two animate by different means. A tick keeps the bar count, so the morph
|
|
134
|
+
* capture's slots still pair one-to-one and the last bar can reshape in place.
|
|
135
|
+
* An append can't use that capture at all — slots pair from the right edge, so
|
|
136
|
+
* a new bar shifts every candle onto its neighbour's geometry — and instead
|
|
137
|
+
* advances the visible window, which translates the series left and lets the
|
|
138
|
+
* new bar in at the right edge.
|
|
139
|
+
*/
|
|
140
|
+
export type StreamKind = 'tick' | 'append';
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Which of the two a `'stream'` transition is. Read from the newest timestamp
|
|
144
|
+
* rather than a length comparison, so a rolling buffer that drops a bar from
|
|
145
|
+
* the front as it adds one to the back still reads as an append.
|
|
146
|
+
*
|
|
147
|
+
* An update that both appends and revises the bar that just closed counts as an
|
|
148
|
+
* append: the translation is the dominant motion, and the revision is a final
|
|
149
|
+
* print that has nowhere to slot-pair to.
|
|
150
|
+
*/
|
|
151
|
+
export function classifyStream(prev: Candle[], next: Candle[]): StreamKind {
|
|
152
|
+
if (prev.length === 0 || next.length === 0) return 'tick';
|
|
153
|
+
return next[next.length - 1].timeMs > prev[prev.length - 1].timeMs
|
|
154
|
+
? 'append'
|
|
155
|
+
: 'tick';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Whether the view is still following the newest bar, which is what decides if
|
|
160
|
+
* an appended bar should pull the window along with it.
|
|
161
|
+
*
|
|
162
|
+
* True when the right edge sits at or past the newest bar's slot *end* — where
|
|
163
|
+
* the default framing leaves it, plus whatever gap it reserved. Someone who has
|
|
164
|
+
* panned back into history falls below that and is left where they are: nothing
|
|
165
|
+
* is more disorienting than the chart walking out from under you while you read
|
|
166
|
+
* it.
|
|
167
|
+
*/
|
|
168
|
+
export function isPinnedToLatest(
|
|
169
|
+
window: VisibleRange,
|
|
170
|
+
lastMs: number,
|
|
171
|
+
stepMs: number,
|
|
172
|
+
): boolean {
|
|
173
|
+
return window.endMs >= lastMs + stepMs;
|
|
174
|
+
}
|
|
175
|
+
|
|
129
176
|
/**
|
|
130
177
|
* The visible window to apply after a timeframe switch so each candle keeps
|
|
131
178
|
* the exact pixel width it had before: the visible slot count is preserved and
|
package/src/index.ts
CHANGED
|
@@ -14,16 +14,26 @@ export type {
|
|
|
14
14
|
VisibleRange,
|
|
15
15
|
RSIConfig,
|
|
16
16
|
MACDConfig,
|
|
17
|
+
ATRConfig,
|
|
18
|
+
ATRSmoothing,
|
|
17
19
|
MASource,
|
|
18
20
|
MAKind,
|
|
19
21
|
MovingAverageOverlay,
|
|
20
22
|
VWAPConfig,
|
|
21
23
|
BollingerBandsConfig,
|
|
24
|
+
IchimokuConfig,
|
|
25
|
+
FairValueGapsConfig,
|
|
22
26
|
VolumeConfig,
|
|
23
27
|
ChartType,
|
|
24
28
|
TransitionEasing,
|
|
25
29
|
IntervalTransition,
|
|
30
|
+
StreamTransition,
|
|
26
31
|
PriceLine,
|
|
27
32
|
PriceLinesStyle,
|
|
33
|
+
Footprint,
|
|
34
|
+
FootprintSide,
|
|
35
|
+
FootprintsStyle,
|
|
36
|
+
FootprintEvent,
|
|
37
|
+
PlotRect,
|
|
28
38
|
DefaultDrawingStyle,
|
|
29
39
|
} from './types';
|
package/src/jsi.d.ts
CHANGED
|
@@ -73,7 +73,20 @@ export interface ChartHandle {
|
|
|
73
73
|
*/
|
|
74
74
|
beginIntervalMorph(mode?: IntervalTransition): void;
|
|
75
75
|
/**
|
|
76
|
-
*
|
|
76
|
+
* Capture the visible geometry so the next setCandles can ease a live tick
|
|
77
|
+
* into place. Always a transform, and unlike beginIntervalMorph it leaves the
|
|
78
|
+
* axes alone — the interval hasn't changed, so its ticks must not fade.
|
|
79
|
+
* Restarting one still in flight continues from the shape on screen, so ticks
|
|
80
|
+
* arriving faster than the animation lands stay smooth. Call before
|
|
81
|
+
* setCandles, then drive setIntervalMorph from 0 to 1.
|
|
82
|
+
*
|
|
83
|
+
* Not for an update that appends a bar: slots pair from the right edge, so a
|
|
84
|
+
* new bar would shift every candle onto its neighbour's geometry. Advance the
|
|
85
|
+
* visible range instead and let the series translate.
|
|
86
|
+
*/
|
|
87
|
+
beginStreamMorph(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Advance the morph started by either begin method above. `t` (clamped to
|
|
77
90
|
* 0..1) is the eased progress: 0 renders the captured geometry pixel-
|
|
78
91
|
* identically to the pre-swap frame, 1 renders the new candles and releases
|
|
79
92
|
* the capture. Driven per-frame by the host animation loop.
|
|
@@ -173,6 +186,7 @@ export interface ChartHandle {
|
|
|
173
186
|
maWidth: number;
|
|
174
187
|
bandColor: number;
|
|
175
188
|
bandsVisible: boolean;
|
|
189
|
+
extremeFill: boolean;
|
|
176
190
|
}): void;
|
|
177
191
|
/**
|
|
178
192
|
* Configures the MACD pane. source/maKind mirror setOverlays' encodings;
|
|
@@ -201,6 +215,18 @@ export interface ChartHandle {
|
|
|
201
215
|
zeroColor: number;
|
|
202
216
|
zeroVisible: boolean;
|
|
203
217
|
}): void;
|
|
218
|
+
/**
|
|
219
|
+
* Configures the ATR pane. smoothing: 0=RMA (Wilder), 1=SMA, 2=EMA;
|
|
220
|
+
* lineColor is packed 0xAARRGGBB where 0 means inherit, and a non-positive
|
|
221
|
+
* width inherits the default stroke.
|
|
222
|
+
*/
|
|
223
|
+
setATR(spec: {
|
|
224
|
+
enabled: boolean;
|
|
225
|
+
period: number;
|
|
226
|
+
smoothing: number;
|
|
227
|
+
lineColor: number;
|
|
228
|
+
lineWidth: number;
|
|
229
|
+
}): void;
|
|
204
230
|
/**
|
|
205
231
|
* Replaces the full set of MA/EMA overlay lines drawn on the price pane.
|
|
206
232
|
* kind: 0=SMA, 1=EMA; source: 0=close,1=open,2=high,3=low,4=hl2,5=hlc3,6=ohlc4;
|
|
@@ -245,6 +271,76 @@ export interface ChartHandle {
|
|
|
245
271
|
fillEnabled: boolean;
|
|
246
272
|
fillOpacity: number;
|
|
247
273
|
}): void;
|
|
274
|
+
/**
|
|
275
|
+
* Configures the Ichimoku overlay (five price-pane lines + the cloud between
|
|
276
|
+
* the leading spans). Colors are packed 0xAARRGGBB; cloudOpacity is 0..1.
|
|
277
|
+
*
|
|
278
|
+
* `displacement` is in candle slots and applies at draw time: the leading
|
|
279
|
+
* spans plot that many slots ahead of the bar they came from, past the newest
|
|
280
|
+
* candle, and chikou that many behind. Enabling the overlay also pulls the
|
|
281
|
+
* view forward far enough to show them.
|
|
282
|
+
*/
|
|
283
|
+
setIchimoku(spec: {
|
|
284
|
+
enabled: boolean;
|
|
285
|
+
tenkanPeriod: number;
|
|
286
|
+
kijunPeriod: number;
|
|
287
|
+
senkouBPeriod: number;
|
|
288
|
+
displacement: number;
|
|
289
|
+
tenkanColor: number;
|
|
290
|
+
tenkanWidth: number;
|
|
291
|
+
tenkanEnabled: boolean;
|
|
292
|
+
kijunColor: number;
|
|
293
|
+
kijunWidth: number;
|
|
294
|
+
kijunEnabled: boolean;
|
|
295
|
+
senkouAColor: number;
|
|
296
|
+
senkouAWidth: number;
|
|
297
|
+
senkouAEnabled: boolean;
|
|
298
|
+
senkouBColor: number;
|
|
299
|
+
senkouBWidth: number;
|
|
300
|
+
senkouBEnabled: boolean;
|
|
301
|
+
chikouColor: number;
|
|
302
|
+
chikouWidth: number;
|
|
303
|
+
chikouEnabled: boolean;
|
|
304
|
+
cloudEnabled: boolean;
|
|
305
|
+
bullishCloudColor: number;
|
|
306
|
+
bearishCloudColor: number;
|
|
307
|
+
cloudOpacity: number;
|
|
308
|
+
}): void;
|
|
309
|
+
/**
|
|
310
|
+
* Configures the Fair Value Gap overlay (shaded imbalance boxes on the price
|
|
311
|
+
* pane). Colors are packed 0xAARRGGBB; opacity is 0..1.
|
|
312
|
+
*
|
|
313
|
+
* `maxBarsBack`, `boxLength` and `labelDistance` are all counted in candle
|
|
314
|
+
* slots. `fillType` is 0 for a close past the far edge or 1 for a wick
|
|
315
|
+
* reaching it, and `borderStyle` is 0 solid / 1 dotted / 2 dashed. Only
|
|
316
|
+
* enabled, maxBarsBack, waitForClose and fillType rescan for gaps.
|
|
317
|
+
*/
|
|
318
|
+
setFairValueGaps(spec: {
|
|
319
|
+
enabled: boolean;
|
|
320
|
+
maxBarsBack: number;
|
|
321
|
+
waitForClose: boolean;
|
|
322
|
+
fillType: number;
|
|
323
|
+
deleteAfterFill: boolean;
|
|
324
|
+
extendBoxes: boolean;
|
|
325
|
+
boxLength: number;
|
|
326
|
+
bullishColor: number;
|
|
327
|
+
bearishColor: number;
|
|
328
|
+
opacity: number;
|
|
329
|
+
borderEnabled: boolean;
|
|
330
|
+
borderStyle: number;
|
|
331
|
+
borderWidth: number;
|
|
332
|
+
bullishBorderColor: number;
|
|
333
|
+
bearishBorderColor: number;
|
|
334
|
+
labelsEnabled: boolean;
|
|
335
|
+
label: string;
|
|
336
|
+
labelDistance: number;
|
|
337
|
+
labelColor: number;
|
|
338
|
+
labelFontSize: number;
|
|
339
|
+
showInverse: boolean;
|
|
340
|
+
inverseBullishColor: number;
|
|
341
|
+
inverseBearishColor: number;
|
|
342
|
+
inverseLabel: string;
|
|
343
|
+
}): void;
|
|
248
344
|
/**
|
|
249
345
|
* Configures the volume bars under the candles. `heightFrac` is the tallest
|
|
250
346
|
* bar as a fraction of the price pane. The style fields carry an inherit
|
|
@@ -325,6 +421,45 @@ export interface ChartHandle {
|
|
|
325
421
|
* committed price is untouched — restate setPriceLines to apply the move.
|
|
326
422
|
*/
|
|
327
423
|
setPriceLineDrag(index: number, price: number): void;
|
|
424
|
+
/**
|
|
425
|
+
* Replaces the full set of footprints (plus their shared style). `side` is
|
|
426
|
+
* 0=buy, 1=sell; `timeMs` is the raw execution time — the core buckets each
|
|
427
|
+
* trade onto whichever candle's window contains it and regroups whenever the
|
|
428
|
+
* candles change. Geometry fields at 0 take the core's defaults. Pass an empty
|
|
429
|
+
* `prints` array to clear.
|
|
430
|
+
*/
|
|
431
|
+
setFootprints(spec: {
|
|
432
|
+
prints: { timeMs: number; side: number }[];
|
|
433
|
+
radiusPx: number;
|
|
434
|
+
gapPx: number;
|
|
435
|
+
marginPx: number;
|
|
436
|
+
hoverBoost: number;
|
|
437
|
+
}): void;
|
|
438
|
+
/**
|
|
439
|
+
* Hit-tests pixel (x, y) against the footprint badges; null on a miss, nearest
|
|
440
|
+
* center wins when two overlap. `indices` addresses the array last passed to
|
|
441
|
+
* setFootprints and covers *both* sides of that candle, ascending by time, so
|
|
442
|
+
* one call is enough to fill a tooltip; `pane` is the plot rect, for deciding
|
|
443
|
+
* which side of the badge that tooltip fits on. Cheap to call at gesture rate.
|
|
444
|
+
*/
|
|
445
|
+
hitTestFootprint(
|
|
446
|
+
x: number,
|
|
447
|
+
y: number,
|
|
448
|
+
): {
|
|
449
|
+
side: number;
|
|
450
|
+
candleTimeMs: number;
|
|
451
|
+
x: number;
|
|
452
|
+
y: number;
|
|
453
|
+
radius: number;
|
|
454
|
+
pane: { left: number; top: number; right: number; bottom: number };
|
|
455
|
+
indices: number[];
|
|
456
|
+
} | null;
|
|
457
|
+
/**
|
|
458
|
+
* Marks a footprint badge as hovered so it renders highlighted; side -1 clears.
|
|
459
|
+
* The arguments match hitTestFootprint. Touch has no hover, so on RN this
|
|
460
|
+
* tracks the badge the user last tapped.
|
|
461
|
+
*/
|
|
462
|
+
setFootprintHover(candleTimeMs: number, side: number): void;
|
|
328
463
|
/** True while any axis-label fade is still in progress. Drives a RAF loop. */
|
|
329
464
|
isAnimating(): boolean;
|
|
330
465
|
render(): ChartFrame | null;
|
package/src/types.ts
CHANGED
|
@@ -16,13 +16,23 @@ export type {
|
|
|
16
16
|
MovingAverageOverlay,
|
|
17
17
|
VWAPConfig,
|
|
18
18
|
BollingerBandsConfig,
|
|
19
|
+
IchimokuConfig,
|
|
20
|
+
FairValueGapsConfig,
|
|
19
21
|
VolumeConfig,
|
|
20
22
|
MACDConfig,
|
|
23
|
+
ATRConfig,
|
|
24
|
+
ATRSmoothing,
|
|
21
25
|
ChartType,
|
|
22
26
|
TransitionEasing,
|
|
23
27
|
IntervalTransition,
|
|
28
|
+
StreamTransition,
|
|
24
29
|
PriceLine,
|
|
25
30
|
PriceLinesStyle,
|
|
31
|
+
Footprint,
|
|
32
|
+
FootprintSide,
|
|
33
|
+
FootprintsStyle,
|
|
34
|
+
FootprintEvent,
|
|
35
|
+
PlotRect,
|
|
26
36
|
DefaultDrawingStyle,
|
|
27
37
|
} from '@vroomchart/types';
|
|
28
38
|
|