@trdrs/quickcharts 5.0.1 → 5.1.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/CHANGELOG.md +4 -0
- package/README.md +3 -0
- package/dist/feature-manifest.json +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +71 -31
- 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,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 5.1.0
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
5
9
|
## 5.0.1
|
|
6
10
|
|
|
7
11
|
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;
|
|
@@ -23124,6 +23135,7 @@ function createChartInstance(deps) {
|
|
|
23124
23135
|
bars = [];
|
|
23125
23136
|
paging = false;
|
|
23126
23137
|
historyPainted = false;
|
|
23138
|
+
initialHistoryPending = true;
|
|
23127
23139
|
if (holdFrame !== null) window.cancelAnimationFrame(holdFrame);
|
|
23128
23140
|
holdFrame = null;
|
|
23129
23141
|
mainScale().applyOptions({ autoScale: true });
|
|
@@ -23169,49 +23181,72 @@ function createChartInstance(deps) {
|
|
|
23169
23181
|
}).catch(() => {
|
|
23170
23182
|
});
|
|
23171
23183
|
}
|
|
23172
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
|
|
23176
|
-
|
|
23177
|
-
|
|
23178
|
-
|
|
23179
|
-
|
|
23180
|
-
|
|
23181
|
-
|
|
23182
|
-
|
|
23183
|
-
|
|
23184
|
-
|
|
23185
|
-
|
|
23186
|
-
|
|
23187
|
-
|
|
23184
|
+
let firstFrameSize = 0;
|
|
23185
|
+
let frameNavigation = -1;
|
|
23186
|
+
const firstPaint = (complete = false) => {
|
|
23187
|
+
if (complete) initialHistoryPending = false;
|
|
23188
|
+
const grow = complete && firstFrameSize < firstPage && bars.length > firstFrameSize && frameNavigation === navigationEpoch;
|
|
23189
|
+
if (bars.length > 0 && (!historyPainted || grow)) {
|
|
23190
|
+
historyPainted = true;
|
|
23191
|
+
const framing = pendingFrame?.epoch === myEpoch ? pendingFrame : null;
|
|
23192
|
+
pendingFrame = null;
|
|
23193
|
+
const edge = pendingLeftEdge?.epoch === myEpoch ? pendingLeftEdge : null;
|
|
23194
|
+
pendingLeftEdge = null;
|
|
23195
|
+
if (framing) {
|
|
23196
|
+
frameRange(chart, anchor, framing.span, framing.tf);
|
|
23197
|
+
fillSpan(framing.span, framing.tf);
|
|
23198
|
+
} else if (edge) keepLeftEdge(edge);
|
|
23199
|
+
else chart.timeScale().fitContent();
|
|
23200
|
+
firstFrameSize = bars.length;
|
|
23201
|
+
frameNavigation = framing || edge ? -1 : navigationEpoch;
|
|
23202
|
+
holdAxisAfterFrame();
|
|
23203
|
+
refreshMarks();
|
|
23204
|
+
}
|
|
23188
23205
|
if (!ready) {
|
|
23189
23206
|
ready = true;
|
|
23190
23207
|
deps.onReady();
|
|
23191
23208
|
}
|
|
23192
|
-
|
|
23209
|
+
};
|
|
23210
|
+
queueMicrotask(() => openSubscription(myEpoch, firstPaint));
|
|
23211
|
+
void datafeed.history(symbol, tf, { countBack: firstPage }).then((page) => {
|
|
23212
|
+
if (disposed || myEpoch !== epoch) return;
|
|
23213
|
+
const merged2 = new Map(page.bars.map((bar) => [bar.t, bar]));
|
|
23214
|
+
for (const bar of bars) merged2.set(bar.t, bar);
|
|
23215
|
+
const write = () => {
|
|
23216
|
+
bars = [...merged2.values()].sort((a, b) => a.t - b.t);
|
|
23217
|
+
paintAll();
|
|
23218
|
+
};
|
|
23219
|
+
if (historyPainted) maintainTimeline(write);
|
|
23220
|
+
else write();
|
|
23221
|
+
firstPaint(true);
|
|
23193
23222
|
}).catch((e) => {
|
|
23194
23223
|
if (disposed || myEpoch !== epoch) return;
|
|
23195
|
-
historyPainted = true;
|
|
23196
|
-
pendingFrame = null;
|
|
23197
23224
|
if (e instanceof FeedUnavailableError) {
|
|
23225
|
+
unsubscribe?.();
|
|
23226
|
+
unsubscribe = null;
|
|
23227
|
+
bars = [];
|
|
23228
|
+
paintAll();
|
|
23198
23229
|
feedStatus = "feed_unavailable";
|
|
23199
23230
|
events.emit("feedStatus", "feed_unavailable");
|
|
23200
|
-
return;
|
|
23201
23231
|
}
|
|
23202
|
-
|
|
23232
|
+
}).finally(() => {
|
|
23233
|
+
if (myEpoch === epoch) initialHistoryPending = false;
|
|
23203
23234
|
});
|
|
23204
23235
|
}
|
|
23205
|
-
function openSubscription(myEpoch) {
|
|
23236
|
+
function openSubscription(myEpoch, firstPaint) {
|
|
23206
23237
|
if (disposed || myEpoch !== epoch) return;
|
|
23207
|
-
|
|
23238
|
+
let active = true;
|
|
23239
|
+
const off = datafeed.subscribeBars(symbol, tf, {
|
|
23208
23240
|
onBars: (e) => {
|
|
23209
|
-
if (disposed || myEpoch !== epoch) return;
|
|
23241
|
+
if (!active || disposed || myEpoch !== epoch) return;
|
|
23210
23242
|
const replaying = replay2.absorb(e);
|
|
23211
23243
|
if (e.kind === "snapshot") {
|
|
23212
|
-
const
|
|
23213
|
-
|
|
23214
|
-
|
|
23244
|
+
const write = () => {
|
|
23245
|
+
bars = mergeBarSnapshot(bars, e.bars, e.backfill);
|
|
23246
|
+
if (!replaying) paintAll();
|
|
23247
|
+
};
|
|
23248
|
+
if (!replaying && historyPainted) maintainTimeline(write);
|
|
23249
|
+
else write();
|
|
23215
23250
|
} else {
|
|
23216
23251
|
const next = applyBar(bars, e.bar);
|
|
23217
23252
|
if (next) {
|
|
@@ -23219,14 +23254,19 @@ function createChartInstance(deps) {
|
|
|
23219
23254
|
if (!replaying) paintLast(e.bar);
|
|
23220
23255
|
}
|
|
23221
23256
|
}
|
|
23257
|
+
if (!replaying) firstPaint(e.kind === "snapshot" && !e.backfill && e.bars.length >= SNAPSHOT_BARS);
|
|
23222
23258
|
},
|
|
23223
23259
|
onStatus: (status2) => {
|
|
23224
|
-
if (disposed || myEpoch !== epoch) return;
|
|
23260
|
+
if (!active || disposed || myEpoch !== epoch) return;
|
|
23225
23261
|
feedStatus = status2;
|
|
23226
23262
|
events.emit("feedStatus", status2);
|
|
23227
23263
|
countdown?.refresh();
|
|
23228
23264
|
}
|
|
23229
23265
|
});
|
|
23266
|
+
unsubscribe = () => {
|
|
23267
|
+
active = false;
|
|
23268
|
+
off();
|
|
23269
|
+
};
|
|
23230
23270
|
}
|
|
23231
23271
|
const LIVE_EDGE_SLACK_BARS = 1;
|
|
23232
23272
|
let awayFromLive = false;
|