@trdrs/quickcharts 5.0.1 → 5.1.1
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/CHANGELOG.md +8 -0
- package/README.md +3 -0
- package/dist/feature-manifest.json +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +82 -37
- package/dist/index.js.map +1 -1
- package/dist/{symbols-DdHLHQFC.d.ts → symbols-CHJGWrf-.d.ts} +3 -1
- package/dist/symbols.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 5.1.1
|
|
6
|
+
|
|
7
|
+
Range presets reconcile overlapping history pages with streamed bars and preserve a newer navigation while a page is pending.
|
|
8
|
+
|
|
9
|
+
## 5.1.0
|
|
10
|
+
|
|
11
|
+
Charts open live subscriptions alongside history, frame the first arriving data, and retain newer streamed prices when history arrives later. A snapshot with `backfill: true` adds missing history without replacing bars already held.
|
|
12
|
+
|
|
5
13
|
## 5.0.1
|
|
6
14
|
|
|
7
15
|
Drawing gestures respect presses handled by host overlays and leave presses outside the plot to the chart scales.
|
package/README.md
CHANGED
|
@@ -143,6 +143,9 @@ export const myFeed: ChartDatafeed = {
|
|
|
143
143
|
4. **Live updates mutate the last bar or append.** `subscribeBars` emits `{ kind: 'snapshot', bars }` on
|
|
144
144
|
connect and after every reconnect (the self-healing re-sync), then `{ kind: 'bar', bar }` per update.
|
|
145
145
|
A bar's `t` is its **bucket-open** epoch-seconds time, never the update's wall-clock time.
|
|
146
|
+
The chart opens the subscription alongside history. The first data frames the chart; history
|
|
147
|
+
arriving later adds older bars and retains newer stream readings. Mark a preliminary history
|
|
148
|
+
snapshot with `backfill: true`: it fills missing timestamps without replacing bars already held.
|
|
146
149
|
5. **Bar time is epoch SECONDS.** Not milliseconds.
|
|
147
150
|
6. **No feed for a symbol is terminal.** Throw `FeedUnavailableError` from `history` when no feed serves
|
|
148
151
|
the symbol; the chart shows "market data unavailable" and stops. A transient fetch failure should
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ChartDatafeed, M as MarkIconId, F as FeedBar, S as SymbolRow, D as DatafeedSearchOptions, a as SearchPage, b as SearchClassNode } from './symbols-
|
|
2
|
-
export { B as BarMark, c as BarsEvent, d as DatafeedConfig, e as FeedUnavailableError, H as HistoryPage, f as MarkColor, g as MarkColorPair, h as MarkColorRole, i as MarkLine, j as MarkLineStyle, k as MarkPlacement, l as MarkShape, O as OlderPageVerdict, P as PricesHandlers, m as SubscribeHandlers, n as SymbolNames, o as SymbolPrices, T as TimescaleMark, p as olderPageVerdict, s as symbolNames } from './symbols-
|
|
1
|
+
import { C as ChartDatafeed, M as MarkIconId, F as FeedBar, S as SymbolRow, D as DatafeedSearchOptions, a as SearchPage, b as SearchClassNode } from './symbols-CHJGWrf-.js';
|
|
2
|
+
export { B as BarMark, c as BarsEvent, d as DatafeedConfig, e as FeedUnavailableError, H as HistoryPage, f as MarkColor, g as MarkColorPair, h as MarkColorRole, i as MarkLine, j as MarkLineStyle, k as MarkPlacement, l as MarkShape, O as OlderPageVerdict, P as PricesHandlers, m as SubscribeHandlers, n as SymbolNames, o as SymbolPrices, T as TimescaleMark, p as olderPageVerdict, s as symbolNames } from './symbols-CHJGWrf-.js';
|
|
3
3
|
import { ao as en, C as ChartMessageKey, G as GlyphSourcePort, M as MagnetMode, d as CursorMode, Q as TextEditFrame, N as TextDraft, L as LineStyle, I as IDrawing, m as DrawingCounts, D as DrawingStyle, $ as VisibilityPreset, X as ToolPreset, Y as ToolTemplate, S as SerializedDrawing, o as DrawingPreferences, l as DrawingAssetPort } from './assets-DF3nozNV.js';
|
|
4
4
|
import { b as ResourceRef, C as ChartSaveLoadAdapter, q as ChartMeta, t as ChartBody, h as DrawingResourceContext, R as ResourceStore, u as DrawingsMeta, j as DrawingsBody, T as TemplateMeta, a as TemplateBody, v as LayoutMeta, w as LayoutBody, e as DrawingContextKind } from './resources-XglhzzW0.js';
|
|
5
5
|
export { c as ChartLocalDrawingContext, D as DRAWING_CONTEXT_VERSION, d as DRAWING_DOCUMENT_VERSION, f as DrawingEntry, g as DrawingGroup, i as DrawingTombstone, L as LayoutSharedDrawingContext, M as MemoryResourcesOptions, x as ResourceAbortError, S as SymbolGlobalDrawingContext, y as TemplateKind, W as WriteOutcome, k as drawingContextKey, l as emptyDrawingDocument, m as liveDrawingEntries, n as liveDrawingGroups, z as memorySaveLoadAdapter, o as mergeDrawingDocuments, p as parseDrawingDocument, r as reviseDrawingDocument, s as sameDrawingContext } from './resources-XglhzzW0.js';
|
package/dist/index.js
CHANGED
|
@@ -4912,6 +4912,17 @@ function layoutChoices(offered) {
|
|
|
4912
4912
|
return (arrangementOf(offered.arrangements[0])?.count ?? 1) > 1 && offered.sync.length > 0;
|
|
4913
4913
|
}
|
|
4914
4914
|
|
|
4915
|
+
// src/widget/barSnapshot.ts
|
|
4916
|
+
function mergeBarSnapshot(held, incoming, backfill = false) {
|
|
4917
|
+
if (backfill) {
|
|
4918
|
+
const merged2 = new Map(incoming.map((bar) => [bar.t, bar]));
|
|
4919
|
+
for (const bar of held) merged2.set(bar.t, bar);
|
|
4920
|
+
return [...merged2.values()].sort((a, b) => a.t - b.t);
|
|
4921
|
+
}
|
|
4922
|
+
const first = incoming[0]?.t;
|
|
4923
|
+
return first === void 0 ? [...incoming] : [...held.filter((bar) => bar.t < first), ...incoming];
|
|
4924
|
+
}
|
|
4925
|
+
|
|
4915
4926
|
// src/widget/chart.ts
|
|
4916
4927
|
import {
|
|
4917
4928
|
CrosshairMode as CrosshairMode2,
|
|
@@ -16653,8 +16664,7 @@ function attachReplayPlane(deps) {
|
|
|
16653
16664
|
if (master === null) return false;
|
|
16654
16665
|
if (event.kind === "snapshot") {
|
|
16655
16666
|
const fresh = event.bars.filter((b) => deps.visible(b.t));
|
|
16656
|
-
|
|
16657
|
-
master = first === void 0 ? fresh : [...master.filter((b) => b.t < first), ...fresh];
|
|
16667
|
+
master = mergeBarSnapshot(master, fresh, event.backfill);
|
|
16658
16668
|
} else if (deps.visible(event.bar.t)) {
|
|
16659
16669
|
const last = master[master.length - 1];
|
|
16660
16670
|
if (!last || event.bar.t > last.t) master = [...master, event.bar];
|
|
@@ -21961,6 +21971,7 @@ function createChartInstance(deps) {
|
|
|
21961
21971
|
let symbolFormatter = createPriceFormatter(UNRESOLVED_PRICE_FORMAT, { locale: i18n.tag() });
|
|
21962
21972
|
let epoch = 0;
|
|
21963
21973
|
let historyPainted = false;
|
|
21974
|
+
let initialHistoryPending = false;
|
|
21964
21975
|
let pendingFrame = null;
|
|
21965
21976
|
let pendingLeftEdge = null;
|
|
21966
21977
|
let menuLevel = null;
|
|
@@ -22995,7 +23006,7 @@ function createChartInstance(deps) {
|
|
|
22995
23006
|
}
|
|
22996
23007
|
function maybePageBack(runway = PAGE_RUNWAY) {
|
|
22997
23008
|
if (replay2.active()) return;
|
|
22998
|
-
if (paging || noMoreHistory || bars.length === 0) return;
|
|
23009
|
+
if (initialHistoryPending || paging || noMoreHistory || bars.length === 0) return;
|
|
22999
23010
|
const range2 = chart.timeScale().getVisibleLogicalRange();
|
|
23000
23011
|
if (!range2 || range2.from > PAGE_TRIGGER_BARS) return;
|
|
23001
23012
|
paging = true;
|
|
@@ -23032,17 +23043,22 @@ function createChartInstance(deps) {
|
|
|
23032
23043
|
if (short <= 0) return;
|
|
23033
23044
|
paging = true;
|
|
23034
23045
|
const myEpoch = epoch;
|
|
23046
|
+
const myNavigation = navigationEpoch;
|
|
23035
23047
|
const oldest = bars[0].t;
|
|
23036
23048
|
void fetchOlder(oldest - 1, short).then(({ olderBars, end }) => {
|
|
23037
23049
|
if (disposed || myEpoch !== epoch) return;
|
|
23038
23050
|
if (end) noMoreHistory = true;
|
|
23039
|
-
const
|
|
23040
|
-
if (
|
|
23041
|
-
|
|
23042
|
-
|
|
23043
|
-
|
|
23044
|
-
|
|
23051
|
+
const merged2 = mergeBarSnapshot(bars, olderBars.filter((bar) => bar.t < oldest), true);
|
|
23052
|
+
if (merged2.length > bars.length) {
|
|
23053
|
+
maintainTimeline(() => {
|
|
23054
|
+
bars = merged2;
|
|
23055
|
+
paintAll();
|
|
23056
|
+
});
|
|
23057
|
+
refreshMarks();
|
|
23058
|
+
}
|
|
23059
|
+
if (myNavigation === navigationEpoch) frameRange(chart, anchor, span, spanTf);
|
|
23045
23060
|
}).catch(() => {
|
|
23061
|
+
if (!disposed && myEpoch === epoch && myNavigation === navigationEpoch) frameRange(chart, anchor, span, spanTf);
|
|
23046
23062
|
}).finally(() => {
|
|
23047
23063
|
if (myEpoch === epoch) paging = false;
|
|
23048
23064
|
});
|
|
@@ -23124,6 +23140,7 @@ function createChartInstance(deps) {
|
|
|
23124
23140
|
bars = [];
|
|
23125
23141
|
paging = false;
|
|
23126
23142
|
historyPainted = false;
|
|
23143
|
+
initialHistoryPending = true;
|
|
23127
23144
|
if (holdFrame !== null) window.cancelAnimationFrame(holdFrame);
|
|
23128
23145
|
holdFrame = null;
|
|
23129
23146
|
mainScale().applyOptions({ autoScale: true });
|
|
@@ -23169,49 +23186,72 @@ function createChartInstance(deps) {
|
|
|
23169
23186
|
}).catch(() => {
|
|
23170
23187
|
});
|
|
23171
23188
|
}
|
|
23172
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
|
|
23176
|
-
|
|
23177
|
-
|
|
23178
|
-
|
|
23179
|
-
|
|
23180
|
-
|
|
23181
|
-
|
|
23182
|
-
|
|
23183
|
-
|
|
23184
|
-
|
|
23185
|
-
|
|
23186
|
-
|
|
23187
|
-
|
|
23189
|
+
let firstFrameSize = 0;
|
|
23190
|
+
let frameNavigation = -1;
|
|
23191
|
+
const firstPaint = (complete = false) => {
|
|
23192
|
+
if (complete) initialHistoryPending = false;
|
|
23193
|
+
const grow = complete && firstFrameSize < firstPage && bars.length > firstFrameSize && frameNavigation === navigationEpoch;
|
|
23194
|
+
if (bars.length > 0 && (!historyPainted || grow)) {
|
|
23195
|
+
historyPainted = true;
|
|
23196
|
+
const framing = pendingFrame?.epoch === myEpoch ? pendingFrame : null;
|
|
23197
|
+
pendingFrame = null;
|
|
23198
|
+
const edge = pendingLeftEdge?.epoch === myEpoch ? pendingLeftEdge : null;
|
|
23199
|
+
pendingLeftEdge = null;
|
|
23200
|
+
if (framing) {
|
|
23201
|
+
frameRange(chart, anchor, framing.span, framing.tf);
|
|
23202
|
+
fillSpan(framing.span, framing.tf);
|
|
23203
|
+
} else if (edge) keepLeftEdge(edge);
|
|
23204
|
+
else chart.timeScale().fitContent();
|
|
23205
|
+
firstFrameSize = bars.length;
|
|
23206
|
+
frameNavigation = framing || edge ? -1 : navigationEpoch;
|
|
23207
|
+
holdAxisAfterFrame();
|
|
23208
|
+
refreshMarks();
|
|
23209
|
+
}
|
|
23188
23210
|
if (!ready) {
|
|
23189
23211
|
ready = true;
|
|
23190
23212
|
deps.onReady();
|
|
23191
23213
|
}
|
|
23192
|
-
|
|
23214
|
+
};
|
|
23215
|
+
queueMicrotask(() => openSubscription(myEpoch, firstPaint));
|
|
23216
|
+
void datafeed.history(symbol, tf, { countBack: firstPage }).then((page) => {
|
|
23217
|
+
if (disposed || myEpoch !== epoch) return;
|
|
23218
|
+
const merged2 = new Map(page.bars.map((bar) => [bar.t, bar]));
|
|
23219
|
+
for (const bar of bars) merged2.set(bar.t, bar);
|
|
23220
|
+
const write = () => {
|
|
23221
|
+
bars = [...merged2.values()].sort((a, b) => a.t - b.t);
|
|
23222
|
+
paintAll();
|
|
23223
|
+
};
|
|
23224
|
+
if (historyPainted) maintainTimeline(write);
|
|
23225
|
+
else write();
|
|
23226
|
+
firstPaint(true);
|
|
23193
23227
|
}).catch((e) => {
|
|
23194
23228
|
if (disposed || myEpoch !== epoch) return;
|
|
23195
|
-
historyPainted = true;
|
|
23196
|
-
pendingFrame = null;
|
|
23197
23229
|
if (e instanceof FeedUnavailableError) {
|
|
23230
|
+
unsubscribe?.();
|
|
23231
|
+
unsubscribe = null;
|
|
23232
|
+
bars = [];
|
|
23233
|
+
paintAll();
|
|
23198
23234
|
feedStatus = "feed_unavailable";
|
|
23199
23235
|
events.emit("feedStatus", "feed_unavailable");
|
|
23200
|
-
return;
|
|
23201
23236
|
}
|
|
23202
|
-
|
|
23237
|
+
}).finally(() => {
|
|
23238
|
+
if (myEpoch === epoch) initialHistoryPending = false;
|
|
23203
23239
|
});
|
|
23204
23240
|
}
|
|
23205
|
-
function openSubscription(myEpoch) {
|
|
23241
|
+
function openSubscription(myEpoch, firstPaint) {
|
|
23206
23242
|
if (disposed || myEpoch !== epoch) return;
|
|
23207
|
-
|
|
23243
|
+
let active = true;
|
|
23244
|
+
const off = datafeed.subscribeBars(symbol, tf, {
|
|
23208
23245
|
onBars: (e) => {
|
|
23209
|
-
if (disposed || myEpoch !== epoch) return;
|
|
23246
|
+
if (!active || disposed || myEpoch !== epoch) return;
|
|
23210
23247
|
const replaying = replay2.absorb(e);
|
|
23211
23248
|
if (e.kind === "snapshot") {
|
|
23212
|
-
const
|
|
23213
|
-
|
|
23214
|
-
|
|
23249
|
+
const write = () => {
|
|
23250
|
+
bars = mergeBarSnapshot(bars, e.bars, e.backfill);
|
|
23251
|
+
if (!replaying) paintAll();
|
|
23252
|
+
};
|
|
23253
|
+
if (!replaying && historyPainted) maintainTimeline(write);
|
|
23254
|
+
else write();
|
|
23215
23255
|
} else {
|
|
23216
23256
|
const next = applyBar(bars, e.bar);
|
|
23217
23257
|
if (next) {
|
|
@@ -23219,14 +23259,19 @@ function createChartInstance(deps) {
|
|
|
23219
23259
|
if (!replaying) paintLast(e.bar);
|
|
23220
23260
|
}
|
|
23221
23261
|
}
|
|
23262
|
+
if (!replaying) firstPaint(e.kind === "snapshot" && !e.backfill && e.bars.length >= SNAPSHOT_BARS);
|
|
23222
23263
|
},
|
|
23223
23264
|
onStatus: (status2) => {
|
|
23224
|
-
if (disposed || myEpoch !== epoch) return;
|
|
23265
|
+
if (!active || disposed || myEpoch !== epoch) return;
|
|
23225
23266
|
feedStatus = status2;
|
|
23226
23267
|
events.emit("feedStatus", status2);
|
|
23227
23268
|
countdown?.refresh();
|
|
23228
23269
|
}
|
|
23229
23270
|
});
|
|
23271
|
+
unsubscribe = () => {
|
|
23272
|
+
active = false;
|
|
23273
|
+
off();
|
|
23274
|
+
};
|
|
23230
23275
|
}
|
|
23231
23276
|
const LIVE_EDGE_SLACK_BARS = 1;
|
|
23232
23277
|
let awayFromLive = false;
|