@tradecanvas/svelte 1.3.9 → 1.3.11

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.
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { onMount, onDestroy } from 'svelte';
2
+ import { onMount, onDestroy, untrack } from 'svelte';
3
3
  import {
4
4
  Chart,
5
5
  BinanceAdapter,
@@ -30,7 +30,12 @@
30
30
  chartType?: ChartType;
31
31
  /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */
32
32
  indicators?: IndicatorSpec[];
33
- /** Static bars: the chart shows these, and opens no stream of its own when it has them at mount. */
33
+ /**
34
+ * Bars: the chart shows these, and opens no stream of its own when it has
35
+ * them at mount. A bar pushed onto the same array, or its last bar changed,
36
+ * goes in as a live tick (the view stays where it is); a new array is a new
37
+ * series. An older bar changed in place needs a new array.
38
+ */
34
39
  data?: OHLCBar[];
35
40
  adapter?: DataAdapter;
36
41
  /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */
@@ -91,6 +96,8 @@
91
96
  const indicatorIds = new Map<string, string>();
92
97
  /** The stream open now (`symbol|timeframe`), or null. */
93
98
  let streamKey: string | null = null;
99
+ /** The bars last given to the chart: the array, how many, and the last one as text. */
100
+ let fed: { bars: OHLCBar[]; length: number; last: string } | null = null;
94
101
  /** The features last applied, as text. */
95
102
  let featuresKey: string | null = null;
96
103
 
@@ -126,7 +133,7 @@
126
133
  chart = instance;
127
134
 
128
135
  if (data) {
129
- instance.setData(data);
136
+ feed(instance, data);
130
137
  } else if (stream) {
131
138
  const dataAdapter = adapter ?? new BinanceAdapter();
132
139
  instance.connect({ adapter: dataAdapter, symbol, timeframe, historyLimit });
@@ -175,7 +182,42 @@
175
182
 
176
183
  $effect(() => { instance?.setTheme(resolveTheme(theme)); });
177
184
  $effect(() => { instance?.setChartType(chartType); });
178
- $effect(() => { if (data) instance?.setData(data); });
185
+ const barKey = (b: OHLCBar | undefined) => (b ? `${b.time},${b.open},${b.high},${b.low},${b.close},${b.volume}` : '');
186
+ const plain = (b: OHLCBar) => $state.snapshot(b) as OHLCBar;
187
+
188
+ /**
189
+ * Bars into the chart: on the same array, a bar pushed or the last one
190
+ * changed goes in as a tick, so the view stays put and only the end is
191
+ * recalculated; anything else is a new series. The chart gets plain copies,
192
+ * not $state proxies, to read in its frames.
193
+ */
194
+ function feed(target: Chart, bars: OHLCBar[]): void {
195
+ const n = bars.length;
196
+ const last = barKey(bars[n - 1]);
197
+ const prev = fed;
198
+ fed = { bars, length: n, last };
199
+ if (prev && prev.bars === bars && prev.length > 0) {
200
+ if (n === prev.length) {
201
+ if (last !== prev.last) target.updateLastBar(plain(bars[n - 1]));
202
+ return;
203
+ }
204
+ if (n === prev.length + 1) {
205
+ target.updateLastBar(plain(bars[n - 2]));
206
+ target.appendBar(plain(bars[n - 1]));
207
+ return;
208
+ }
209
+ }
210
+ target.setData($state.snapshot(bars) as OHLCBar[]);
211
+ }
212
+
213
+ // Follows the array, its length and the last bar's fields: a bar pushed onto
214
+ // $state data or the forming bar changed, without walking every bar.
215
+ $effect(() => {
216
+ const bars = data;
217
+ if (!bars) return;
218
+ void barKey(bars[bars.length - 1]);
219
+ untrack(() => { if (instance) feed(instance, bars); });
220
+ });
179
221
 
180
222
  $effect(() => {
181
223
  const specs = $state.snapshot(indicators) as IndicatorSpec[];
@@ -7,7 +7,12 @@ interface Props {
7
7
  chartType?: ChartType;
8
8
  /** Indicators by id (`'rsi'`), or with their inputs (`{ id: 'ema', params: { period: 50 } }`). */
9
9
  indicators?: IndicatorSpec[];
10
- /** Static bars: the chart shows these, and opens no stream of its own when it has them at mount. */
10
+ /**
11
+ * Bars: the chart shows these, and opens no stream of its own when it has
12
+ * them at mount. A bar pushed onto the same array, or its last bar changed,
13
+ * goes in as a live tick (the view stays where it is); a new array is a new
14
+ * series. An older bar changed in place needs a new array.
15
+ */
11
16
  data?: OHLCBar[];
12
17
  adapter?: DataAdapter;
13
18
  /** `false`: no stream until you say so (no Binance by default); the chart waits for `data`. Default `true`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradecanvas/svelte",
3
- "version": "1.3.9",
3
+ "version": "1.3.11",
4
4
  "type": "module",
5
5
  "description": "Svelte 5 component for @tradecanvas/chart — reactive props, runes, zero boilerplate.",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "README.md"
40
40
  ],
41
41
  "dependencies": {
42
- "@tradecanvas/chart": "1.27.0"
42
+ "@tradecanvas/chart": "1.29.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "svelte": ">=5.0.0"