@trdrs/quickcharts 2.3.0 → 2.4.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 +14 -0
- package/README.md +42 -0
- package/dist/feature-manifest.json +25 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +200 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3082,7 +3082,8 @@ var FEATURE_KEYS = {
|
|
|
3082
3082
|
replay: "flag",
|
|
3083
3083
|
history: "flag",
|
|
3084
3084
|
sessions: "flag",
|
|
3085
|
-
crosshair: "flag"
|
|
3085
|
+
crosshair: "flag",
|
|
3086
|
+
navigation: "flag"
|
|
3086
3087
|
};
|
|
3087
3088
|
var TOP_BAR_KEYS = {
|
|
3088
3089
|
symbol: "flag",
|
|
@@ -3111,7 +3112,9 @@ var UI_KEYS = {
|
|
|
3111
3112
|
toasts: "flag",
|
|
3112
3113
|
symbolSearch: "flag",
|
|
3113
3114
|
indicatorPicker: "flag",
|
|
3114
|
-
indicatorSettings: "flag"
|
|
3115
|
+
indicatorSettings: "flag",
|
|
3116
|
+
priceScale: "flag",
|
|
3117
|
+
crosshair: { horizontal: "flag", labels: "flag", solid: "flag" }
|
|
3115
3118
|
};
|
|
3116
3119
|
function checkKeys(path, value, keys) {
|
|
3117
3120
|
if (value === void 0) return;
|
|
@@ -3139,7 +3142,8 @@ function resolveFeatures(config) {
|
|
|
3139
3142
|
replay: on(config?.replay),
|
|
3140
3143
|
history: on(config?.history),
|
|
3141
3144
|
sessions: on(config?.sessions),
|
|
3142
|
-
crosshair: on(config?.crosshair)
|
|
3145
|
+
crosshair: on(config?.crosshair),
|
|
3146
|
+
navigation: on(config?.navigation)
|
|
3143
3147
|
};
|
|
3144
3148
|
}
|
|
3145
3149
|
var shown = (value) => value !== false;
|
|
@@ -3155,6 +3159,9 @@ function resolveUi(config, features, offered = {}) {
|
|
|
3155
3159
|
const inLegend = (key) => legend2 && (typeof legendConfig !== "object" || shown(legendConfig[key]));
|
|
3156
3160
|
const symbolSearch = shown(config?.symbolSearch);
|
|
3157
3161
|
const indicatorPicker = shown(config?.indicatorPicker);
|
|
3162
|
+
const crosshairConfig = config?.crosshair;
|
|
3163
|
+
const crosshair = features.crosshair && shown(crosshairConfig);
|
|
3164
|
+
const inCrosshair = (key) => crosshair && (typeof crosshairConfig !== "object" || shown(crosshairConfig[key]));
|
|
3158
3165
|
return {
|
|
3159
3166
|
topBar,
|
|
3160
3167
|
symbolPill: inBar("symbol") && symbolSearch,
|
|
@@ -3178,13 +3185,19 @@ function resolveUi(config, features, offered = {}) {
|
|
|
3178
3185
|
legend: legend2,
|
|
3179
3186
|
legendValues: inLegend("values"),
|
|
3180
3187
|
marketStatus: inLegend("marketStatus"),
|
|
3181
|
-
navigation: shown(config?.navigation),
|
|
3188
|
+
navigation: features.navigation && shown(config?.navigation),
|
|
3182
3189
|
contextMenu: shown(config?.contextMenu),
|
|
3183
3190
|
replayTransport: features.replay && shown(config?.replayTransport),
|
|
3184
3191
|
toasts: shown(config?.toasts),
|
|
3185
3192
|
symbolSearch,
|
|
3186
3193
|
indicatorPicker,
|
|
3187
|
-
indicatorSettings: shown(config?.indicatorSettings)
|
|
3194
|
+
indicatorSettings: shown(config?.indicatorSettings),
|
|
3195
|
+
priceScale: shown(config?.priceScale),
|
|
3196
|
+
crosshair,
|
|
3197
|
+
crosshairHorizontal: inCrosshair("horizontal"),
|
|
3198
|
+
crosshairLabels: inCrosshair("labels"),
|
|
3199
|
+
// Solid is the one part that is off unless named: a crosshair is dashed by default.
|
|
3200
|
+
crosshairSolid: crosshair && typeof crosshairConfig === "object" && crosshairConfig.solid === true
|
|
3188
3201
|
};
|
|
3189
3202
|
}
|
|
3190
3203
|
function canCopyImage() {
|
|
@@ -3313,6 +3326,29 @@ function styleOptions(style, paint) {
|
|
|
3313
3326
|
return candleOptions(paint);
|
|
3314
3327
|
}
|
|
3315
3328
|
}
|
|
3329
|
+
function fadedStyleOptions(style, paint, alpha) {
|
|
3330
|
+
const a = Math.min(1, Math.max(0, alpha));
|
|
3331
|
+
const up = paint.appearance.upColor;
|
|
3332
|
+
const down = paint.appearance.downColor;
|
|
3333
|
+
switch (style) {
|
|
3334
|
+
case "line":
|
|
3335
|
+
case "stepline":
|
|
3336
|
+
return { color: withAlpha2(paint.canvas.neutral, a) };
|
|
3337
|
+
case "area":
|
|
3338
|
+
return { lineColor: withAlpha2(up, a), topColor: withAlpha2(up, 0.28 * a), bottomColor: withAlpha2(up, 0.04 * a) };
|
|
3339
|
+
case "baseline":
|
|
3340
|
+
return {
|
|
3341
|
+
topLineColor: withAlpha2(up, a),
|
|
3342
|
+
bottomLineColor: withAlpha2(down, a),
|
|
3343
|
+
topFillColor1: withAlpha2(up, 0.28 * a),
|
|
3344
|
+
topFillColor2: withAlpha2(up, 0.04 * a),
|
|
3345
|
+
bottomFillColor1: withAlpha2(down, 0.04 * a),
|
|
3346
|
+
bottomFillColor2: withAlpha2(down, 0.28 * a)
|
|
3347
|
+
};
|
|
3348
|
+
default:
|
|
3349
|
+
return styleOptions(style, paint);
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3316
3352
|
function lineOptions(paint) {
|
|
3317
3353
|
return { color: paint.canvas.neutral, lineWidth: 2 };
|
|
3318
3354
|
}
|
|
@@ -4963,6 +4999,7 @@ import {
|
|
|
4963
4999
|
createChart as createRenderer,
|
|
4964
5000
|
HistogramSeries as HistogramSeries2,
|
|
4965
5001
|
LineSeries as LineSeries4,
|
|
5002
|
+
LineStyle as LineStyle3,
|
|
4966
5003
|
TrackingModeExitMode
|
|
4967
5004
|
} from "lightweight-charts";
|
|
4968
5005
|
|
|
@@ -5017,6 +5054,59 @@ function coerceScaleMode(raw) {
|
|
|
5017
5054
|
return SCALE_MODES.includes(raw ?? "") ? raw : "normal";
|
|
5018
5055
|
}
|
|
5019
5056
|
|
|
5057
|
+
// src/widget/styleMorph.ts
|
|
5058
|
+
var STYLE_MORPH_MS = 500;
|
|
5059
|
+
function morphEase(t) {
|
|
5060
|
+
const clamped = Math.min(1, Math.max(0, t));
|
|
5061
|
+
return (1 - Math.cos(Math.PI * clamped)) / 2;
|
|
5062
|
+
}
|
|
5063
|
+
function foldBar(bar, fold) {
|
|
5064
|
+
const keep = 1 - Math.min(1, Math.max(0, fold));
|
|
5065
|
+
return {
|
|
5066
|
+
time: bar.t,
|
|
5067
|
+
open: bar.c + (bar.o - bar.c) * keep,
|
|
5068
|
+
high: bar.c + (bar.h - bar.c) * keep,
|
|
5069
|
+
low: bar.c + (bar.l - bar.c) * keep,
|
|
5070
|
+
close: bar.c
|
|
5071
|
+
};
|
|
5072
|
+
}
|
|
5073
|
+
function startStyleMorph(deps) {
|
|
5074
|
+
const frame = deps.frame ?? ((tick2) => requestAnimationFrame(tick2));
|
|
5075
|
+
const cancel = deps.cancelFrame ?? ((handle2) => cancelAnimationFrame(handle2));
|
|
5076
|
+
const now = deps.now ?? (() => performance.now());
|
|
5077
|
+
const start = now();
|
|
5078
|
+
let handle = null;
|
|
5079
|
+
let ended = false;
|
|
5080
|
+
const draw = (t) => {
|
|
5081
|
+
const p = morphEase(t);
|
|
5082
|
+
const fold = deps.direction === "fold" ? p : 1 - p;
|
|
5083
|
+
deps.bars.setData(deps.shown().map((bar) => foldBar(bar, fold)));
|
|
5084
|
+
deps.fadeLine(fold);
|
|
5085
|
+
};
|
|
5086
|
+
const finish = () => {
|
|
5087
|
+
if (ended) return;
|
|
5088
|
+
ended = true;
|
|
5089
|
+
if (handle !== null) cancel(handle);
|
|
5090
|
+
handle = null;
|
|
5091
|
+
draw(1);
|
|
5092
|
+
deps.done();
|
|
5093
|
+
};
|
|
5094
|
+
const tick = () => {
|
|
5095
|
+
handle = null;
|
|
5096
|
+
if (ended) return;
|
|
5097
|
+
const t = (now() - start) / STYLE_MORPH_MS;
|
|
5098
|
+
if (t >= 1) {
|
|
5099
|
+
finish();
|
|
5100
|
+
return;
|
|
5101
|
+
}
|
|
5102
|
+
draw(t);
|
|
5103
|
+
handle = frame(tick);
|
|
5104
|
+
};
|
|
5105
|
+
draw(0);
|
|
5106
|
+
handle = frame(tick);
|
|
5107
|
+
return { running: () => !ended, finish };
|
|
5108
|
+
}
|
|
5109
|
+
|
|
5020
5110
|
// src/widget/baselineLevel.ts
|
|
5021
5111
|
var BASELINE_SCREEN_PERCENT = 50;
|
|
5022
5112
|
var BASELINE_DRIFT_PX = 0.5;
|
|
@@ -5710,8 +5800,8 @@ function bundledGlyphSource(glyph2) {
|
|
|
5710
5800
|
}
|
|
5711
5801
|
|
|
5712
5802
|
// src/pointerInput.ts
|
|
5713
|
-
function pointerLock(locked) {
|
|
5714
|
-
const on = !locked;
|
|
5803
|
+
function pointerLock(locked, navigable = true) {
|
|
5804
|
+
const on = !locked && navigable;
|
|
5715
5805
|
return {
|
|
5716
5806
|
handleScroll: on,
|
|
5717
5807
|
handleScale: { mouseWheel: on, pinch: false, axisPressedMouseMove: on, axisDoubleClickReset: on },
|
|
@@ -6825,7 +6915,7 @@ function attachDrawings(options) {
|
|
|
6825
6915
|
const locked = () => allLocked || workflow().allLocked === true;
|
|
6826
6916
|
const changed = () => events.onChange?.();
|
|
6827
6917
|
const lockPointer = (locked2) => {
|
|
6828
|
-
const lock = pointerLock(locked2);
|
|
6918
|
+
const lock = pointerLock(locked2, options.navigable ?? true);
|
|
6829
6919
|
chart.applyOptions({ handleScroll: lock.handleScroll, handleScale: lock.handleScale });
|
|
6830
6920
|
container.style.touchAction = lock.touchAction;
|
|
6831
6921
|
};
|
|
@@ -10339,6 +10429,7 @@ function attachDrawingsPlane(deps) {
|
|
|
10339
10429
|
const handle = attachDrawings({
|
|
10340
10430
|
chart: deps.chart,
|
|
10341
10431
|
series: deps.series,
|
|
10432
|
+
navigable: deps.navigable,
|
|
10342
10433
|
container: deps.container,
|
|
10343
10434
|
symbol: deps.symbol,
|
|
10344
10435
|
timeframe: deps.timeframe,
|
|
@@ -12754,6 +12845,7 @@ function composeFormingBar(parent, subs, k) {
|
|
|
12754
12845
|
}
|
|
12755
12846
|
|
|
12756
12847
|
// src/widget/replay.ts
|
|
12848
|
+
var START_HOLD_MS = 250;
|
|
12757
12849
|
function coerceReplaySpeed(raw) {
|
|
12758
12850
|
const n = Number(raw);
|
|
12759
12851
|
return REPLAY_SPEEDS.includes(n) ? n : 10;
|
|
@@ -12772,6 +12864,13 @@ function attachReplayPlane(deps) {
|
|
|
12772
12864
|
let stepping = null;
|
|
12773
12865
|
let generation = 0;
|
|
12774
12866
|
let destroyed = false;
|
|
12867
|
+
let glide = null;
|
|
12868
|
+
const stopGlide = () => {
|
|
12869
|
+
if (glide) {
|
|
12870
|
+
clearTimeout(glide);
|
|
12871
|
+
glide = null;
|
|
12872
|
+
}
|
|
12873
|
+
};
|
|
12775
12874
|
const invalidateStep = () => {
|
|
12776
12875
|
generation += 1;
|
|
12777
12876
|
stepping = null;
|
|
@@ -12792,15 +12891,34 @@ function attachReplayPlane(deps) {
|
|
|
12792
12891
|
const currentGrain = () => autoGrain ? "auto" : manualGrain ?? "auto";
|
|
12793
12892
|
const paintCursor = () => {
|
|
12794
12893
|
if (!master) return;
|
|
12894
|
+
stopGlide();
|
|
12795
12895
|
deps.paint(master.slice(0, cursor));
|
|
12796
12896
|
deps.chart.timeScale().scrollToRealTime();
|
|
12797
12897
|
};
|
|
12798
12898
|
const paintForming = () => {
|
|
12799
12899
|
if (!master || !subs) return;
|
|
12900
|
+
stopGlide();
|
|
12800
12901
|
const parent = master[cursor - 1];
|
|
12801
12902
|
deps.paint([...master.slice(0, cursor - 1), composeFormingBar(parent, subs, formK)]);
|
|
12802
12903
|
deps.chart.timeScale().scrollToRealTime();
|
|
12803
12904
|
};
|
|
12905
|
+
const paintStart = () => {
|
|
12906
|
+
if (!master) return;
|
|
12907
|
+
const scale = deps.chart.timeScale();
|
|
12908
|
+
const shown2 = scale.getVisibleRange();
|
|
12909
|
+
const view = scale.getVisibleLogicalRange();
|
|
12910
|
+
const chosen = master[cursor - 1].t;
|
|
12911
|
+
const from = shown2?.from;
|
|
12912
|
+
const to = shown2?.to;
|
|
12913
|
+
if (!view || typeof from !== "number" || typeof to !== "number" || chosen < from || chosen > to) return paintCursor();
|
|
12914
|
+
stopGlide();
|
|
12915
|
+
deps.paint(master.slice(0, cursor));
|
|
12916
|
+
scale.setVisibleLogicalRange(view);
|
|
12917
|
+
glide = setTimeout(() => {
|
|
12918
|
+
glide = null;
|
|
12919
|
+
if (master && !destroyed && !deps.disposed()) scale.scrollToRealTime();
|
|
12920
|
+
}, START_HOLD_MS);
|
|
12921
|
+
};
|
|
12804
12922
|
const stopTimer = () => {
|
|
12805
12923
|
if (timer) {
|
|
12806
12924
|
clearInterval(timer);
|
|
@@ -12884,6 +13002,7 @@ function attachReplayPlane(deps) {
|
|
|
12884
13002
|
};
|
|
12885
13003
|
function abandon() {
|
|
12886
13004
|
invalidateStep();
|
|
13005
|
+
stopGlide();
|
|
12887
13006
|
if (!master) return;
|
|
12888
13007
|
stopTimer();
|
|
12889
13008
|
playing = false;
|
|
@@ -12911,7 +13030,7 @@ function attachReplayPlane(deps) {
|
|
|
12911
13030
|
const idx = master.findIndex((b) => b.t >= atSec);
|
|
12912
13031
|
cursor = Math.max(2, (idx === -1 ? master.length - 1 : idx) + 1);
|
|
12913
13032
|
deps.setHeader(true);
|
|
12914
|
-
|
|
13033
|
+
paintStart();
|
|
12915
13034
|
sync();
|
|
12916
13035
|
},
|
|
12917
13036
|
exit() {
|
|
@@ -13434,7 +13553,7 @@ function attachExtensionsPlane(deps) {
|
|
|
13434
13553
|
},
|
|
13435
13554
|
lockPanZoom: (locked) => {
|
|
13436
13555
|
if (deps.disposed()) return;
|
|
13437
|
-
const state = pointerLock(locked);
|
|
13556
|
+
const state = pointerLock(locked, deps.navigable);
|
|
13438
13557
|
deps.chart.applyOptions({ handleScroll: state.handleScroll, handleScale: state.handleScale });
|
|
13439
13558
|
deps.setTouchAction(state.touchAction);
|
|
13440
13559
|
}
|
|
@@ -15943,10 +16062,11 @@ function registerChartCommands(deps) {
|
|
|
15943
16062
|
});
|
|
15944
16063
|
add({ id: "chart.view.reset", scope: "chart", label: "command.viewReset", shortcut: "Alt+KeyR", available: always, execute: () => handle.reset() });
|
|
15945
16064
|
add({ id: "chart.view.goLive", scope: "chart", label: "command.viewGoLive", shortcut: "Alt+KeyL", available: always, execute: () => handle.goLive() });
|
|
15946
|
-
|
|
15947
|
-
add({ id: "chart.view.
|
|
15948
|
-
add({ id: "chart.view.
|
|
15949
|
-
add({ id: "chart.view.
|
|
16065
|
+
const navigable = () => features.navigation;
|
|
16066
|
+
add({ id: "chart.view.zoomIn", scope: "chart", label: "command.viewZoomIn", shortcut: "Equal", available: navigable, execute: () => deps.zoom("in") });
|
|
16067
|
+
add({ id: "chart.view.zoomOut", scope: "chart", label: "command.viewZoomOut", shortcut: "Minus", available: navigable, execute: () => deps.zoom("out") });
|
|
16068
|
+
add({ id: "chart.view.scrollLeft", scope: "chart", label: "command.viewScrollLeft", shortcut: "ArrowLeft", available: navigable, execute: () => deps.scroll("left") });
|
|
16069
|
+
add({ id: "chart.view.scrollRight", scope: "chart", label: "command.viewScrollRight", shortcut: "ArrowRight", available: navigable, execute: () => deps.scroll("right") });
|
|
15950
16070
|
add({
|
|
15951
16071
|
id: "chart.data.download",
|
|
15952
16072
|
scope: "chart",
|
|
@@ -16750,14 +16870,21 @@ function createChartInstance(deps) {
|
|
|
16750
16870
|
vertLines: { color: canvas().grid, visible: eff.appearance.grid },
|
|
16751
16871
|
horzLines: { color: canvas().grid, visible: eff.appearance.grid }
|
|
16752
16872
|
},
|
|
16753
|
-
crosshair: {
|
|
16873
|
+
crosshair: {
|
|
16874
|
+
mode: deps.ui.crosshair ? CrosshairMode.Normal : CrosshairMode.Hidden,
|
|
16875
|
+
vertLine: { labelVisible: deps.ui.crosshairLabels, ...deps.ui.crosshairSolid ? { style: LineStyle3.Solid } : {} },
|
|
16876
|
+
horzLine: { visible: deps.ui.crosshairHorizontal, labelVisible: deps.ui.crosshairLabels, ...deps.ui.crosshairSolid ? { style: LineStyle3.Solid } : {} }
|
|
16877
|
+
},
|
|
16754
16878
|
// A finger held on the plot scrubs the crosshair for as long as it stays down, and lifting it
|
|
16755
16879
|
// takes the crosshair away, so the next one-finger drag pans: the way a native chart reads.
|
|
16756
16880
|
trackingMode: { exitMode: TrackingModeExitMode.OnTouchEnd },
|
|
16757
16881
|
// The renderer's own momentum throws a flick as fast as seven pixels a millisecond and coasts
|
|
16758
16882
|
// it thousands of pixels; the chart coasts a flick itself, calmly.
|
|
16759
16883
|
kineticScroll: { touch: false, mouse: false },
|
|
16760
|
-
|
|
16884
|
+
// A chart that holds its view takes no drag, wheel, pinch or scale gesture from the renderer.
|
|
16885
|
+
handleScroll: deps.features.navigation,
|
|
16886
|
+
handleScale: deps.features.navigation,
|
|
16887
|
+
rightPriceScale: { visible: deps.ui.priceScale, borderVisible: false, scaleMargins: { top: 0.08, bottom: 0.08 } },
|
|
16761
16888
|
timeScale: { borderVisible: false, timeVisible: true, secondsVisible: false, rightOffset: 4, barSpacing: 8, minBarSpacing: 0.5 }
|
|
16762
16889
|
});
|
|
16763
16890
|
const anchor = chart.addSeries(LineSeries4, {
|
|
@@ -16766,7 +16893,13 @@ function createChartInstance(deps) {
|
|
|
16766
16893
|
priceLineVisible: false,
|
|
16767
16894
|
crosshairMarkerVisible: false
|
|
16768
16895
|
});
|
|
16769
|
-
|
|
16896
|
+
const addMainSeries = (id) => {
|
|
16897
|
+
const added = addStyleSeries(chart, id, paint());
|
|
16898
|
+
if (!deps.ui.priceScale) added.applyOptions({ priceLineVisible: false, lastValueVisible: false });
|
|
16899
|
+
return added;
|
|
16900
|
+
};
|
|
16901
|
+
let series2 = addMainSeries(style);
|
|
16902
|
+
let morph = null;
|
|
16770
16903
|
const baselineLevel = createBaselineLevel({ paneHeight: () => chart.paneSize().height });
|
|
16771
16904
|
if (style === "baseline") baselineLevel.follow(series2);
|
|
16772
16905
|
const volume2 = chart.addSeries(HistogramSeries2, {
|
|
@@ -16897,15 +17030,17 @@ function createChartInstance(deps) {
|
|
|
16897
17030
|
const crosshairSubs = /* @__PURE__ */ new Set();
|
|
16898
17031
|
const timeClickSubs = /* @__PURE__ */ new Set();
|
|
16899
17032
|
const rangeSubs = /* @__PURE__ */ new Set();
|
|
17033
|
+
const reducedMotion = () => gestures.ownerDocument.defaultView?.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
16900
17034
|
const ranges = createRangeApi({
|
|
16901
17035
|
chart,
|
|
16902
17036
|
disposed: disposedFn,
|
|
16903
17037
|
muted,
|
|
16904
17038
|
mirrored,
|
|
16905
17039
|
onGlide: () => followLiveEdge(),
|
|
16906
|
-
reducedMotion
|
|
17040
|
+
reducedMotion
|
|
16907
17041
|
});
|
|
16908
|
-
const
|
|
17042
|
+
const still = { stop: () => void 0, destroy: () => void 0 };
|
|
17043
|
+
const fling = deps.features.navigation ? attachFling({ chart, target: gestures }) : still;
|
|
16909
17044
|
let unregisterRangeMirror = () => void 0;
|
|
16910
17045
|
function applyTimezone() {
|
|
16911
17046
|
if (disposed) return;
|
|
@@ -17013,6 +17148,7 @@ function createChartInstance(deps) {
|
|
|
17013
17148
|
const drawings2 = attachDrawingsPlane({
|
|
17014
17149
|
chart,
|
|
17015
17150
|
series: anchor,
|
|
17151
|
+
navigable: deps.features.navigation,
|
|
17016
17152
|
container: gestures,
|
|
17017
17153
|
chrome: chrome2,
|
|
17018
17154
|
chartId: deps.id,
|
|
@@ -17086,7 +17222,7 @@ function createChartInstance(deps) {
|
|
|
17086
17222
|
setHeader: () => legend2.setHeader(symbol, tf),
|
|
17087
17223
|
// A chart whose crosshair the host switched OFF keeps it off: replay may take the crosshair
|
|
17088
17224
|
// away for the length of a question, never hand one back that was never there.
|
|
17089
|
-
setCrosshair: (visible) => chart.applyOptions({ crosshair: { mode: visible && deps.
|
|
17225
|
+
setCrosshair: (visible) => chart.applyOptions({ crosshair: { mode: visible && deps.ui.crosshair ? CrosshairMode.Normal : CrosshairMode.Hidden } }),
|
|
17090
17226
|
// The feed's own grains: a chart never offers, or fetches, a timeframe its feed cannot serve.
|
|
17091
17227
|
resolutions: () => deps.capabilities().resolutions,
|
|
17092
17228
|
persist: (key, value) => storage.set(key === "speed" ? REPLAY_SPEED_KEY : REPLAY_TIMEFRAME_KEY, value),
|
|
@@ -17120,6 +17256,7 @@ function createChartInstance(deps) {
|
|
|
17120
17256
|
const extensions = attachExtensionsPlane({
|
|
17121
17257
|
chartId: deps.id,
|
|
17122
17258
|
chart,
|
|
17259
|
+
navigable: deps.features.navigation,
|
|
17123
17260
|
series: () => anchor,
|
|
17124
17261
|
visible: () => series2,
|
|
17125
17262
|
gestures,
|
|
@@ -17227,8 +17364,8 @@ function createChartInstance(deps) {
|
|
|
17227
17364
|
navigationRoot.addEventListener("mouseup", onNativeDragEnd, { passive: true });
|
|
17228
17365
|
navigationRoot.addEventListener("pointerup", onNativeDragEnd, { passive: true });
|
|
17229
17366
|
navigationRoot.addEventListener("pointercancel", onNativeDragEnd, { passive: true });
|
|
17230
|
-
const pinch = attachPinch({ chart, target: gestures });
|
|
17231
|
-
const freePan = deps.freePan ? attachFreePan({
|
|
17367
|
+
const pinch = deps.features.navigation ? attachPinch({ chart, target: gestures }) : null;
|
|
17368
|
+
const freePan = deps.freePan && deps.features.navigation ? attachFreePan({
|
|
17232
17369
|
chart,
|
|
17233
17370
|
target: gestures,
|
|
17234
17371
|
framing: () => priceAxisPolicy() === "auto",
|
|
@@ -17252,9 +17389,11 @@ function createChartInstance(deps) {
|
|
|
17252
17389
|
const painted = shownBars();
|
|
17253
17390
|
const values = painted.map((b) => ({ time: b.t, value: b.c }));
|
|
17254
17391
|
anchor.setData(values);
|
|
17255
|
-
series2
|
|
17256
|
-
|
|
17257
|
-
|
|
17392
|
+
if (morph?.bars !== series2) {
|
|
17393
|
+
series2.setData(
|
|
17394
|
+
shaped ? values : painted.map((b) => ({ time: b.t, open: b.o, high: b.h, low: b.l, close: b.c }))
|
|
17395
|
+
);
|
|
17396
|
+
}
|
|
17258
17397
|
if (volumeInstance()) paintVolume();
|
|
17259
17398
|
indicators2.recompute();
|
|
17260
17399
|
compare?.sync();
|
|
@@ -17580,20 +17719,48 @@ function createChartInstance(deps) {
|
|
|
17580
17719
|
function setStyle(next) {
|
|
17581
17720
|
if (disposed || next === style || !deps.styles.includes(next)) return;
|
|
17582
17721
|
const keep = chart.timeScale().getVisibleLogicalRange();
|
|
17722
|
+
morph?.run.finish();
|
|
17583
17723
|
const previous = series2;
|
|
17724
|
+
const previousStyle = style;
|
|
17584
17725
|
style = next;
|
|
17585
17726
|
storage.set(STYLE_KEY, next);
|
|
17586
|
-
series2 =
|
|
17727
|
+
series2 = addMainSeries(next);
|
|
17587
17728
|
baselineLevel.follow(next === "baseline" ? series2 : null);
|
|
17588
17729
|
countdown?.seriesChanged(previous);
|
|
17589
17730
|
extensions.visibleSeriesReplaced();
|
|
17590
17731
|
applyPriceFormat();
|
|
17591
|
-
|
|
17592
|
-
|
|
17593
|
-
|
|
17594
|
-
|
|
17732
|
+
const remove = (leaving) => {
|
|
17733
|
+
try {
|
|
17734
|
+
chart.removeSeries(leaving);
|
|
17735
|
+
} catch {
|
|
17736
|
+
}
|
|
17737
|
+
};
|
|
17738
|
+
const folding = valueShaped(next) && !valueShaped(previousStyle);
|
|
17739
|
+
const unfolding = !valueShaped(next) && valueShaped(previousStyle);
|
|
17740
|
+
const morphing = !!deps.styleMorph && (folding || unfolding) && !reducedMotion();
|
|
17741
|
+
if (!morphing) remove(previous);
|
|
17595
17742
|
paintAll();
|
|
17596
17743
|
if (keep) chart.timeScale().setVisibleLogicalRange(keep);
|
|
17744
|
+
if (morphing) {
|
|
17745
|
+
const bars2 = folding ? previous : series2;
|
|
17746
|
+
const line2 = folding ? series2 : previous;
|
|
17747
|
+
const lineStyle2 = folding ? next : previousStyle;
|
|
17748
|
+
const entry = {
|
|
17749
|
+
bars: bars2,
|
|
17750
|
+
run: startStyleMorph({
|
|
17751
|
+
bars: bars2,
|
|
17752
|
+
fadeLine: (alpha) => line2.applyOptions(fadedStyleOptions(lineStyle2, paint(), alpha)),
|
|
17753
|
+
shown: shownBars,
|
|
17754
|
+
direction: folding ? "fold" : "unfold",
|
|
17755
|
+
done: () => {
|
|
17756
|
+
if (morph === entry) morph = null;
|
|
17757
|
+
remove(previous);
|
|
17758
|
+
if (folding) line2.applyOptions(styleOptions(lineStyle2, paint()));
|
|
17759
|
+
}
|
|
17760
|
+
})
|
|
17761
|
+
};
|
|
17762
|
+
morph = entry;
|
|
17763
|
+
}
|
|
17597
17764
|
events.emit("style", next);
|
|
17598
17765
|
}
|
|
17599
17766
|
function content() {
|
|
@@ -18005,8 +18172,9 @@ function createChartInstance(deps) {
|
|
|
18005
18172
|
countdownClock.destroy();
|
|
18006
18173
|
pointer?.destroy();
|
|
18007
18174
|
ranges.stopGlide();
|
|
18175
|
+
morph?.run.finish();
|
|
18008
18176
|
fling.destroy();
|
|
18009
|
-
pinch
|
|
18177
|
+
pinch?.destroy();
|
|
18010
18178
|
freePan?.destroy();
|
|
18011
18179
|
plotArea.destroy();
|
|
18012
18180
|
extensions.destroy();
|
|
@@ -23100,6 +23268,7 @@ function createChart(options) {
|
|
|
23100
23268
|
container: element,
|
|
23101
23269
|
hostContainer: options.container,
|
|
23102
23270
|
freePan: options.touch?.freePan === true,
|
|
23271
|
+
styleMorph: options.transitions?.style === true,
|
|
23103
23272
|
layer,
|
|
23104
23273
|
datafeed: options.datafeed,
|
|
23105
23274
|
externalDrawingToolbar: !!options.drawingToolbarContainer,
|