@wick-charts/vue 0.4.1 → 0.5.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/README.md +5 -3
- package/dist/BarSeries.vue.js +44 -0
- package/dist/BarSeries.vue2.js +4 -0
- package/dist/CandlestickSeries.vue.js +45 -0
- package/dist/CandlestickSeries.vue2.js +4 -0
- package/dist/ChartContainer.vue.js +168 -0
- package/dist/ChartContainer.vue2.js +4 -0
- package/dist/LineSeries.vue.js +44 -0
- package/dist/LineSeries.vue2.js +4 -0
- package/dist/PieSeries.vue.js +34 -0
- package/dist/PieSeries.vue2.js +4 -0
- package/dist/composables.js +44 -0
- package/dist/context.js +25 -0
- package/dist/core/dist/animation/animator.js +72 -0
- package/dist/core/dist/animation/config.js +145 -0
- package/dist/core/dist/animation/easing.js +4 -0
- package/dist/core/dist/animation/scalar-spring.js +57 -0
- package/dist/core/dist/animation/spring.js +11 -0
- package/dist/core/dist/animation/time.js +19 -0
- package/dist/core/dist/animation/viewport-engine.js +174 -0
- package/dist/core/dist/animation/visible-range-spring.js +64 -0
- package/dist/core/dist/animation/y-range-hermite.js +72 -0
- package/dist/core/dist/animation/y-range-snap.js +31 -0
- package/dist/core/dist/animation/y-range-spring.js +59 -0
- package/dist/core/dist/axis/dom-labels.js +60 -0
- package/dist/core/dist/canvas-manager.js +109 -0
- package/dist/core/dist/chart/edge-indicators.js +26 -0
- package/dist/core/dist/chart/fit-to-data.js +9 -0
- package/dist/core/dist/chart/last-value.js +31 -0
- package/dist/core/dist/chart/options.js +35 -0
- package/dist/core/dist/chart/pan-zoom-math.js +66 -0
- package/dist/core/dist/chart/streaming-cadence.js +70 -0
- package/dist/core/dist/chart/streaming-target.js +22 -0
- package/dist/core/dist/chart/viewport-padding.js +6 -0
- package/dist/core/dist/chart/y-target.js +24 -0
- package/dist/core/dist/chart.js +1495 -0
- package/dist/core/dist/components/crosshair.js +9 -0
- package/dist/core/dist/components/edge-indicator.js +36 -0
- package/dist/core/dist/components/grid.js +22 -0
- package/dist/core/dist/components/marker.js +41 -0
- package/dist/core/dist/components/reference-line.js +48 -0
- package/dist/core/dist/components/time-region.js +35 -0
- package/dist/core/dist/data/decimation.js +54 -0
- package/dist/core/dist/data/store.js +76 -0
- package/dist/core/dist/data/sync.js +47 -0
- package/dist/core/dist/events.js +19 -0
- package/dist/core/dist/interactions/handler.js +84 -0
- package/dist/core/dist/interactions/pan.js +26 -0
- package/dist/core/dist/interactions/zoom.js +21 -0
- package/dist/core/dist/navigator/controller.js +374 -0
- package/dist/core/dist/navigator/decimate.js +44 -0
- package/dist/core/dist/navigator/interactions.js +28 -0
- package/dist/core/dist/navigator/render.js +68 -0
- package/dist/core/dist/perf/counting-context.js +19 -0
- package/dist/core/dist/perf/perf-hud.js +453 -0
- package/dist/core/dist/perf/perf-monitor.js +132 -0
- package/dist/core/dist/render-scheduler.js +31 -0
- package/dist/core/dist/scales/tick-tracker.js +110 -0
- package/dist/core/dist/scales/x-scale.js +145 -0
- package/dist/core/dist/scales/y-scale.js +156 -0
- package/dist/core/dist/series/bar.js +341 -0
- package/dist/core/dist/series/base-multi-layer.js +438 -0
- package/dist/core/dist/series/candlestick.js +481 -0
- package/dist/core/dist/series/definition.js +11 -0
- package/dist/core/dist/series/line.js +446 -0
- package/dist/core/dist/series/painters/builtins.js +36 -0
- package/dist/core/dist/series/painters/canvas-path.js +79 -0
- package/dist/core/dist/series/painters/resolve.js +32 -0
- package/dist/core/dist/series/pie.js +545 -0
- package/dist/core/dist/series/register-builtins.js +11 -0
- package/dist/core/dist/series/stack-math.js +17 -0
- package/dist/core/dist/snapshots.js +107 -0
- package/dist/core/dist/theme/create.js +176 -0
- package/dist/core/dist/theme/resolve.js +14 -0
- package/dist/core/dist/theme/themes/andromeda.js +33 -0
- package/dist/core/dist/theme/themes/ayu-mirage.js +33 -0
- package/dist/core/dist/theme/themes/catppuccin.js +33 -0
- package/dist/core/dist/theme/themes/dracula.js +35 -0
- package/dist/core/dist/theme/themes/github-light.js +34 -0
- package/dist/core/dist/theme/themes/gruvbox.js +33 -0
- package/dist/core/dist/theme/themes/handwritten.js +101 -0
- package/dist/core/dist/theme/themes/high-contrast.js +33 -0
- package/dist/core/dist/theme/themes/lavender-mist.js +33 -0
- package/dist/core/dist/theme/themes/light-pink.js +34 -0
- package/dist/core/dist/theme/themes/material-palenight.js +33 -0
- package/dist/core/dist/theme/themes/minimal-light.js +34 -0
- package/dist/core/dist/theme/themes/mint-breeze.js +33 -0
- package/dist/core/dist/theme/themes/monokai-pro.js +33 -0
- package/dist/core/dist/theme/themes/night-owl.js +35 -0
- package/dist/core/dist/theme/themes/one-dark-pro.js +33 -0
- package/dist/core/dist/theme/themes/panda.js +33 -0
- package/dist/core/dist/theme/themes/peach-cream.js +33 -0
- package/dist/core/dist/theme/themes/quiet-light.js +37 -0
- package/dist/core/dist/theme/themes/rose-pine-dawn.js +33 -0
- package/dist/core/dist/theme/themes/sand-dune.js +33 -0
- package/dist/core/dist/theme/themes/solarized-light.js +34 -0
- package/dist/core/dist/tooltip-position.js +10 -0
- package/dist/core/dist/utils/color.js +37 -0
- package/dist/core/dist/utils/format.js +29 -0
- package/dist/core/dist/utils/math.js +26 -0
- package/dist/core/dist/utils/poisoned-data-reporter.js +15 -0
- package/dist/core/dist/utils/time.js +41 -0
- package/dist/index.d.ts +1096 -63
- package/dist/index.js +142 -7754
- package/dist/ui/Crosshair.vue.js +53 -0
- package/dist/ui/Crosshair.vue2.js +4 -0
- package/dist/ui/InfoBar.vue.js +143 -0
- package/dist/ui/InfoBar.vue2.js +4 -0
- package/dist/ui/Legend.vue.js +212 -0
- package/dist/ui/Legend.vue2.js +4 -0
- package/dist/ui/Marker.vue.js +47 -0
- package/dist/ui/Marker.vue2.js +4 -0
- package/dist/ui/Navigator.vue.js +58 -0
- package/dist/ui/Navigator.vue2.js +4 -0
- package/dist/ui/NumberFlow.vue.js +69 -0
- package/dist/ui/NumberFlow.vue2.js +4 -0
- package/dist/ui/PieLegend.vue.js +132 -0
- package/dist/ui/PieLegend.vue2.js +4 -0
- package/dist/ui/PieTooltip.vue.js +135 -0
- package/dist/ui/PieTooltip.vue2.js +4 -0
- package/dist/ui/ReferenceLine.vue.js +44 -0
- package/dist/ui/ReferenceLine.vue2.js +4 -0
- package/dist/ui/TimeAxis.vue.js +43 -0
- package/dist/ui/TimeAxis.vue2.js +4 -0
- package/dist/ui/TimeRegion.vue.js +41 -0
- package/dist/ui/TimeRegion.vue2.js +4 -0
- package/dist/ui/Title.vue.js +54 -0
- package/dist/ui/Title.vue2.js +4 -0
- package/dist/ui/Tooltip.vue.js +195 -0
- package/dist/ui/Tooltip.vue2.js +4 -0
- package/dist/ui/YAxis.vue.js +42 -0
- package/dist/ui/YAxis.vue2.js +4 -0
- package/dist/ui/YLabel.vue.js +105 -0
- package/dist/ui/YLabel.vue2.js +4 -0
- package/package.json +2 -2
- package/src/BarSeries.vue +12 -13
- package/src/CandlestickSeries.vue +17 -6
- package/src/LineSeries.vue +12 -13
- package/src/PieSeries.vue +2 -1
- package/src/composables.ts +12 -2
- package/src/index.ts +42 -0
- package/src/ui/Crosshair.vue +28 -3
- package/src/ui/Legend.vue +1 -2
- package/src/ui/Marker.vue +62 -0
- package/src/ui/ReferenceLine.vue +58 -0
- package/src/ui/TimeRegion.vue +54 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { DEFAULT_LINE_ENTRY as w } from "../animation/config.js";
|
|
2
|
+
import { XScale as T } from "../scales/x-scale.js";
|
|
3
|
+
import { YScale as R } from "../scales/y-scale.js";
|
|
4
|
+
import { decimateCandles as k, decimateLinear as C } from "./decimate.js";
|
|
5
|
+
import { hitTest as y, computeSnapCenter as E, computePan as I, computeResize as M } from "./interactions.js";
|
|
6
|
+
import { computeWindowGeometry as $, renderBackground as V, renderMiniCandlestick as L, renderMiniBar as N, renderMiniLine as P } from "./render.js";
|
|
7
|
+
import { Animator as S } from "../animation/animator.js";
|
|
8
|
+
import { easeOutCubic as z } from "../animation/easing.js";
|
|
9
|
+
class G {
|
|
10
|
+
#s;
|
|
11
|
+
#t;
|
|
12
|
+
#z;
|
|
13
|
+
#e;
|
|
14
|
+
#o;
|
|
15
|
+
#d;
|
|
16
|
+
#r;
|
|
17
|
+
#l;
|
|
18
|
+
#a;
|
|
19
|
+
#c;
|
|
20
|
+
#x;
|
|
21
|
+
#v;
|
|
22
|
+
// Own scales — both cover the full data span. The main chart's scales move
|
|
23
|
+
// with the viewport; these don't.
|
|
24
|
+
#u = new T();
|
|
25
|
+
#F = new R();
|
|
26
|
+
#A = 0;
|
|
27
|
+
#m = 0;
|
|
28
|
+
#n = 1;
|
|
29
|
+
#p = null;
|
|
30
|
+
/** A full canvas render is owed. A queued frame with `#dirty === false`
|
|
31
|
+
* came from {@link #markWindowDirty} and only repositions the window DOM. */
|
|
32
|
+
#T = !0;
|
|
33
|
+
/**
|
|
34
|
+
* Memoized decimation results keyed by source array ref. Cleared on
|
|
35
|
+
* `setData` (guards in-place mutation of a re-passed array); a buckets
|
|
36
|
+
* mismatch (resize) recomputes per entry.
|
|
37
|
+
*/
|
|
38
|
+
#R = /* @__PURE__ */ new Map();
|
|
39
|
+
/**
|
|
40
|
+
* Eases the alpha of the trailing bar/candle/line-segment from 0 → 1 over
|
|
41
|
+
* `DEFAULT_LINE_ENTRY` whenever {@link setData} reports a new last point
|
|
42
|
+
* (a `time` we haven't seen before). Mirrors the per-point entrance
|
|
43
|
+
* animation that the main chart's series renderers run, so a streaming
|
|
44
|
+
* tick reads as a smooth fade-in here too instead of a redraw pop.
|
|
45
|
+
*
|
|
46
|
+
* `null` means "no entrance in flight, draw the tail at full alpha".
|
|
47
|
+
*/
|
|
48
|
+
#h = null;
|
|
49
|
+
/** `time` of the last point we've ever seen — initialises after the first
|
|
50
|
+
* `setData`/render so the first paint doesn't trigger a fade-in. */
|
|
51
|
+
#k = null;
|
|
52
|
+
/** Series index in `lineSeriesList(data)` that owns the newest last-time,
|
|
53
|
+
* so the tail fade applies to the series that actually grew — not always
|
|
54
|
+
* the last entry in the stack. -1 for candlestick (single-series). */
|
|
55
|
+
#C = -1;
|
|
56
|
+
#E;
|
|
57
|
+
// Active-drag state — null when idle.
|
|
58
|
+
#g = null;
|
|
59
|
+
// Bound listeners so we can remove the same references on destroy.
|
|
60
|
+
#I;
|
|
61
|
+
#M;
|
|
62
|
+
#$;
|
|
63
|
+
#V;
|
|
64
|
+
#L;
|
|
65
|
+
#b;
|
|
66
|
+
#N;
|
|
67
|
+
constructor(t) {
|
|
68
|
+
this.#s = t.container, this.#e = t.chart, this.#x = t.data, this.#v = t.options ?? {}, window.getComputedStyle(this.#s).position === "static" && (this.#s.style.position = "relative"), this.#t = document.createElement("canvas"), this.#t.style.position = "absolute", this.#t.style.left = "0", this.#t.style.top = "0", this.#t.style.height = "100%", this.#t.style.touchAction = "none", this.#s.appendChild(this.#t);
|
|
69
|
+
const e = this.#t.getContext("2d", { alpha: !0 });
|
|
70
|
+
if (!e) throw new Error("NavigatorController: failed to acquire 2D context");
|
|
71
|
+
this.#z = e, this.#o = document.createElement("div"), this.#o.dataset.chartNavigatorOverlay = "", this.#o.style.cssText = "position:absolute;left:0;top:0;height:100%;pointer-events:none;", this.#d = document.createElement("div"), this.#d.style.cssText = "position:absolute;left:0;top:0;bottom:0;", this.#r = document.createElement("div"), this.#r.style.cssText = "position:absolute;top:0;bottom:0;", this.#l = document.createElement("div"), this.#l.style.cssText = "position:absolute;top:0;bottom:0;box-sizing:border-box;", this.#a = b(), this.#c = b(), this.#o.append(this.#d, this.#r, this.#l, this.#a, this.#c), this.#s.appendChild(this.#o), this.#I = () => this.#B(), this.#M = () => this.#f(), this.#$ = () => this.#B(), this.#e.on("viewportChange", this.#I), this.#e.on("overlayChange", this.#M), this.#e.on("tickFrame", this.#$), this.#V = (s) => this.#H(s), this.#L = (s) => this.#J(s), this.#b = (s) => this.#K(s), this.#N = () => {
|
|
72
|
+
this.#g === null && (this.#t.style.cursor = "default");
|
|
73
|
+
}, this.#t.addEventListener("pointerdown", this.#V), this.#t.addEventListener("pointermove", this.#L), this.#t.addEventListener("pointerup", this.#b), this.#t.addEventListener("pointercancel", this.#b), this.#t.addEventListener("pointerleave", this.#N), this.#E = new ResizeObserver((s) => this.#U(s[0])), this.#E.observe(this.#s), this.#D();
|
|
74
|
+
const i = this.#s.getBoundingClientRect();
|
|
75
|
+
i.width > 0 && i.height > 0 && this.#W(i.width, i.height), this.#f();
|
|
76
|
+
}
|
|
77
|
+
setData(t) {
|
|
78
|
+
const e = F(t), i = e?.time ?? null;
|
|
79
|
+
if (i !== null && this.#k !== null && i !== this.#k) {
|
|
80
|
+
const s = this.#h?.current ?? 0;
|
|
81
|
+
this.#h = new S({
|
|
82
|
+
initial: s,
|
|
83
|
+
duration: w,
|
|
84
|
+
easing: z,
|
|
85
|
+
lerp: (n, h, l) => n + (h - n) * l
|
|
86
|
+
}), this.#h.setTarget(1);
|
|
87
|
+
}
|
|
88
|
+
this.#k = i, this.#C = e?.seriesIndex ?? -1, this.#x = t, this.#R.clear(), this.#f();
|
|
89
|
+
}
|
|
90
|
+
setOptions(t) {
|
|
91
|
+
this.#v = t, this.#D(), this.#f();
|
|
92
|
+
}
|
|
93
|
+
/** Push `options.height` (when set) onto the container's CSS height so
|
|
94
|
+
* direct core consumers see the option take effect. When the option is
|
|
95
|
+
* absent we leave the container alone — framework wrappers manage their
|
|
96
|
+
* own inline height via JSX, and overwriting it here would clobber the
|
|
97
|
+
* caller's value during the first layout effect. */
|
|
98
|
+
#D() {
|
|
99
|
+
const t = this.#v.height;
|
|
100
|
+
t !== void 0 && (this.#s.style.height = `${t}px`);
|
|
101
|
+
}
|
|
102
|
+
destroy() {
|
|
103
|
+
this.#e.off("viewportChange", this.#I), this.#e.off("overlayChange", this.#M), this.#e.off("tickFrame", this.#$), this.#t.removeEventListener("pointerdown", this.#V), this.#t.removeEventListener("pointermove", this.#L), this.#t.removeEventListener("pointerup", this.#b), this.#t.removeEventListener("pointercancel", this.#b), this.#t.removeEventListener("pointerleave", this.#N), this.#E.disconnect(), this.#p !== null && (cancelAnimationFrame(this.#p), this.#p = null), this.#t.remove(), this.#o.remove();
|
|
104
|
+
}
|
|
105
|
+
/** CSS pixel height of the strip — theme default unless overridden. */
|
|
106
|
+
get height() {
|
|
107
|
+
return this.#v.height ?? this.#e.getTheme().navigator.height;
|
|
108
|
+
}
|
|
109
|
+
// --- internals ---------------------------------------------------------
|
|
110
|
+
/** Effective drawing width — the navigator reserves the main chart's
|
|
111
|
+
* `yAxisWidth` on the right so its active zone lines up with the plot area. */
|
|
112
|
+
get #i() {
|
|
113
|
+
return Math.max(0, this.#A - this.#e.yAxisWidth);
|
|
114
|
+
}
|
|
115
|
+
#U(t) {
|
|
116
|
+
if (!t) return;
|
|
117
|
+
const e = t.contentBoxSize?.[0], i = e?.inlineSize ?? t.contentRect.width, s = e?.blockSize ?? t.contentRect.height;
|
|
118
|
+
i <= 0 || s <= 0 || (this.#W(i, s), this.#f());
|
|
119
|
+
}
|
|
120
|
+
#W(t, e) {
|
|
121
|
+
this.#A = t, this.#m = e, this.#n = window.devicePixelRatio || 1, this.#X();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Write canvas backing-store / CSS sizes only when they actually changed —
|
|
125
|
+
* any assignment to `canvas.width`/`height`, even with the same value,
|
|
126
|
+
* resets the backing store (full clear + realloc), which is pure waste on
|
|
127
|
+
* a repaint where nothing resized.
|
|
128
|
+
*/
|
|
129
|
+
#X() {
|
|
130
|
+
const t = Math.round(this.#i * this.#n), e = Math.round(this.#m * this.#n);
|
|
131
|
+
this.#t.width !== t && (this.#t.width = t), this.#t.height !== e && (this.#t.height = e);
|
|
132
|
+
const i = `${this.#i}px`;
|
|
133
|
+
this.#t.style.width !== i && (this.#t.style.width = i, this.#o.style.width = i);
|
|
134
|
+
}
|
|
135
|
+
#f() {
|
|
136
|
+
this.#T = !0, this.#O();
|
|
137
|
+
}
|
|
138
|
+
/** Queue a window-DOM-only frame — a queued full render takes precedence. */
|
|
139
|
+
#B() {
|
|
140
|
+
this.#O();
|
|
141
|
+
}
|
|
142
|
+
#O() {
|
|
143
|
+
this.#p === null && (this.#p = requestAnimationFrame(() => {
|
|
144
|
+
this.#p = null;
|
|
145
|
+
const t = this.#T;
|
|
146
|
+
this.#T = !1, t ? this.#_() : this.#Q();
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
// --- input -------------------------------------------------------------
|
|
150
|
+
/** Extract media-x from a pointer event, relative to the canvas. */
|
|
151
|
+
#w(t) {
|
|
152
|
+
const e = this.#t.getBoundingClientRect();
|
|
153
|
+
return t.clientX - e.left;
|
|
154
|
+
}
|
|
155
|
+
/** Keep scales synced with current data bounds + size. Safe to call ahead of
|
|
156
|
+
* the first RAF-driven render — pointer handlers rely on this so hit-tests
|
|
157
|
+
* compute against primed scales even on the opening gesture. */
|
|
158
|
+
#P() {
|
|
159
|
+
const t = this.#y(), e = this.#Z();
|
|
160
|
+
return this.#u.update(t, this.#i, this.#n), this.#F.update(e, this.#m, this.#n), { xRange: t, yRange: e };
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* X range for the brush window. While the user drags the brush we track the
|
|
164
|
+
* committed logical target so the window follows the cursor 1:1; otherwise we
|
|
165
|
+
* follow the engine's eased visual so the window glides with the canvas
|
|
166
|
+
* instead of snapping to a wheel-zoom / pan destination while the chart eases.
|
|
167
|
+
*/
|
|
168
|
+
#Y() {
|
|
169
|
+
return this.#g !== null ? this.#e.getVisibleRange() : this.#e.getAnimationState().xRange;
|
|
170
|
+
}
|
|
171
|
+
#S() {
|
|
172
|
+
return this.#P(), $(this.#u, this.#Y(), this.#y());
|
|
173
|
+
}
|
|
174
|
+
#j() {
|
|
175
|
+
const t = this.#y(), e = t.to - t.from;
|
|
176
|
+
return e <= 0 || this.#i <= 0 ? 0 : this.#i / e;
|
|
177
|
+
}
|
|
178
|
+
#H(t) {
|
|
179
|
+
if (t.button !== void 0 && t.button !== 0) return;
|
|
180
|
+
const e = this.#w(t), i = this.#y();
|
|
181
|
+
if (i.to <= i.from) return;
|
|
182
|
+
const s = this.#S(), n = y(e, s), h = this.#j();
|
|
183
|
+
if (h === 0) return;
|
|
184
|
+
let l = this.#e.getVisibleRange();
|
|
185
|
+
if (n.snapToCenter) {
|
|
186
|
+
const r = this.#u.xToTime(e), a = E({ time: r, startVisible: l, xRange: i });
|
|
187
|
+
this.#e.setVisibleRange(a), l = a;
|
|
188
|
+
}
|
|
189
|
+
this.#g = {
|
|
190
|
+
pointerId: t.pointerId,
|
|
191
|
+
gesture: n.gesture,
|
|
192
|
+
startX: e,
|
|
193
|
+
startVisible: l,
|
|
194
|
+
pixelsPerTime: h
|
|
195
|
+
}, this.#t.setPointerCapture(t.pointerId), this.#t.style.cursor = v(
|
|
196
|
+
n.gesture,
|
|
197
|
+
/*dragging*/
|
|
198
|
+
!0
|
|
199
|
+
), t.preventDefault();
|
|
200
|
+
}
|
|
201
|
+
#J(t) {
|
|
202
|
+
const e = this.#g;
|
|
203
|
+
if (e === null) {
|
|
204
|
+
this.#t.style.cursor = x(this.#w(t), this.#S());
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (t.pointerId !== e.pointerId) return;
|
|
208
|
+
const i = this.#w(t) - e.startX, s = this.#y();
|
|
209
|
+
let n;
|
|
210
|
+
if (e.gesture === "pan")
|
|
211
|
+
n = I({
|
|
212
|
+
startVisible: e.startVisible,
|
|
213
|
+
deltaPx: i,
|
|
214
|
+
pixelsPerTime: e.pixelsPerTime,
|
|
215
|
+
dataRange: s
|
|
216
|
+
});
|
|
217
|
+
else {
|
|
218
|
+
const h = e.gesture === "resize-left" ? "left" : "right";
|
|
219
|
+
n = M({
|
|
220
|
+
edge: h,
|
|
221
|
+
startVisible: e.startVisible,
|
|
222
|
+
deltaPx: i,
|
|
223
|
+
pixelsPerTime: e.pixelsPerTime,
|
|
224
|
+
dataRange: s,
|
|
225
|
+
minSpan: 2 * this.#e.getDataInterval()
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
this.#e.setVisibleRange(n);
|
|
229
|
+
}
|
|
230
|
+
#K(t) {
|
|
231
|
+
const e = this.#g;
|
|
232
|
+
e === null || t.pointerId !== e.pointerId || (this.#g = null, this.#t.hasPointerCapture(t.pointerId) && this.#t.releasePointerCapture(t.pointerId), this.#t.style.cursor = x(this.#w(t), this.#S()));
|
|
233
|
+
}
|
|
234
|
+
// --- render ------------------------------------------------------------
|
|
235
|
+
#_() {
|
|
236
|
+
if (this.#i <= 0 || this.#m <= 0) return;
|
|
237
|
+
const t = this.#e.getTheme().navigator, { xRange: e } = this.#P();
|
|
238
|
+
this.#X();
|
|
239
|
+
const i = this.#z, s = this.#t.width, n = this.#t.height;
|
|
240
|
+
i.save(), i.clearRect(0, 0, s, n), i.scale(this.#n, this.#n);
|
|
241
|
+
const h = {
|
|
242
|
+
ctx: i,
|
|
243
|
+
timeScale: this.#u,
|
|
244
|
+
yScale: this.#F,
|
|
245
|
+
mediaWidth: this.#i,
|
|
246
|
+
mediaHeight: this.#m,
|
|
247
|
+
theme: t
|
|
248
|
+
};
|
|
249
|
+
this.#t.style.boxShadow = `inset 0 1px 0 ${t.borderColor}, inset 0 -1px 0 ${t.borderColor}`, V(h);
|
|
250
|
+
let l = 1;
|
|
251
|
+
this.#h !== null && (this.#h.tick(performance.now()), l = this.#h.current, this.#h.animating ? this.#f() : this.#h = null);
|
|
252
|
+
const r = Math.max(1, Math.round(this.#i)), a = this.#x;
|
|
253
|
+
if (a.type === "candlestick")
|
|
254
|
+
L(h, this.#q(a.points, r, k), l);
|
|
255
|
+
else {
|
|
256
|
+
const c = f(a), g = c.length === 1, d = this.#C >= 0 ? this.#C : c.length - 1;
|
|
257
|
+
for (let u = 0; u < c.length; u++) {
|
|
258
|
+
const p = this.#q(c[u], r, C), m = u === d ? l : 1;
|
|
259
|
+
a.type === "bar" ? N(h, p, m) : P(h, p, g, m);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
i.restore(), this.#G(t, e);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Light per-frame path — reposition the window / masks / handles against
|
|
266
|
+
* the eased viewport without touching the canvas. Escalates to a full
|
|
267
|
+
* render when the canvas size went stale (e.g. `yAxisWidth` changed without
|
|
268
|
+
* a resize event).
|
|
269
|
+
*/
|
|
270
|
+
#Q() {
|
|
271
|
+
if (this.#i <= 0 || this.#m <= 0) return;
|
|
272
|
+
const t = Math.round(this.#i * this.#n);
|
|
273
|
+
if (this.#t.width !== t) {
|
|
274
|
+
this.#_();
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const e = this.#e.getTheme().navigator, { xRange: i } = this.#P();
|
|
278
|
+
this.#G(e, i);
|
|
279
|
+
}
|
|
280
|
+
/** Decimate `points` into `buckets`, reusing the cached result while the
|
|
281
|
+
* source array ref and bucket count are unchanged. */
|
|
282
|
+
#q(t, e, i) {
|
|
283
|
+
const s = this.#R.get(t);
|
|
284
|
+
if (s !== void 0 && s.buckets === e)
|
|
285
|
+
return s.result;
|
|
286
|
+
const n = i(t, e);
|
|
287
|
+
return this.#R.set(t, { buckets: e, result: n }), n;
|
|
288
|
+
}
|
|
289
|
+
#G(t, e) {
|
|
290
|
+
if (e.to <= e.from) return;
|
|
291
|
+
const i = this.#Y(), s = Math.max(e.from, Math.min(e.to, i.from)), n = Math.max(e.from, Math.min(e.to, i.to)), h = this.#u.timeToX(s), l = this.#u.timeToX(n), r = Math.min(h, l), a = Math.max(h, l), c = Math.max(1, a - r);
|
|
292
|
+
this.#d.style.width = `${r}px`, this.#d.style.background = t.mask.fill, this.#d.style.display = r > 0 ? "block" : "none";
|
|
293
|
+
const g = Math.max(0, this.#i - (r + c));
|
|
294
|
+
this.#r.style.left = `${r + c}px`, this.#r.style.width = `${g}px`, this.#r.style.background = t.mask.fill, this.#r.style.display = g > 0 ? "block" : "none", this.#l.style.left = `${r}px`, this.#l.style.width = `${c}px`, this.#l.style.background = t.window.fill, this.#l.style.border = t.window.borderWidth > 0 ? `${t.window.borderWidth}px solid ${t.window.border}` : "none";
|
|
295
|
+
const d = t.handle.width, u = Math.max(1, d / 2), p = this.#e.getTheme().background;
|
|
296
|
+
this.#a.style.left = `${r - d / 2}px`, this.#a.style.width = `${d}px`, this.#a.style.background = t.handle.color, this.#a.style.borderRadius = `${u}px`, this.#c.style.left = `${r + c - d / 2}px`, this.#c.style.width = `${d}px`, this.#c.style.background = t.handle.color, this.#c.style.borderRadius = `${u}px`;
|
|
297
|
+
for (const m of this.#a.children)
|
|
298
|
+
m.style.background = p;
|
|
299
|
+
for (const m of this.#c.children)
|
|
300
|
+
m.style.background = p;
|
|
301
|
+
}
|
|
302
|
+
#y() {
|
|
303
|
+
const t = this.#x;
|
|
304
|
+
let e = Number.POSITIVE_INFINITY, i = Number.NEGATIVE_INFINITY, s = 0;
|
|
305
|
+
if (t.type === "candlestick")
|
|
306
|
+
s = t.points.length, s > 0 && (e = t.points[0].time, i = t.points[s - 1].time);
|
|
307
|
+
else
|
|
308
|
+
for (const h of f(t))
|
|
309
|
+
h.length !== 0 && (s += h.length, h[0].time < e && (e = h[0].time), h[h.length - 1].time > i && (i = h[h.length - 1].time));
|
|
310
|
+
if (s >= 2 && i > e)
|
|
311
|
+
return { from: e, to: i };
|
|
312
|
+
if (s === 1)
|
|
313
|
+
return { ...this.#e.getVisibleRange() };
|
|
314
|
+
const n = this.#e.getDataRange();
|
|
315
|
+
return n && n.to > n.from ? n : { ...this.#e.getVisibleRange() };
|
|
316
|
+
}
|
|
317
|
+
#Z() {
|
|
318
|
+
const t = this.#x;
|
|
319
|
+
let e = 1 / 0, i = -1 / 0;
|
|
320
|
+
if (t.type === "candlestick")
|
|
321
|
+
for (const n of t.points)
|
|
322
|
+
n.low < e && (e = n.low), n.high > i && (i = n.high);
|
|
323
|
+
else
|
|
324
|
+
for (const n of f(t))
|
|
325
|
+
for (const h of n)
|
|
326
|
+
h.value < e && (e = h.value), h.value > i && (i = h.value);
|
|
327
|
+
if (!Number.isFinite(e) || !Number.isFinite(i)) return { min: 0, max: 1 };
|
|
328
|
+
if (e === i) {
|
|
329
|
+
const n = Math.abs(e) * 0.05 || 1;
|
|
330
|
+
return { min: e - n, max: i + n };
|
|
331
|
+
}
|
|
332
|
+
const s = (i - e) * 0.2;
|
|
333
|
+
return { min: e - s, max: i + s };
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function f(o) {
|
|
337
|
+
return "series" in o ? o.series : [o.points];
|
|
338
|
+
}
|
|
339
|
+
function F(o) {
|
|
340
|
+
if (o.type === "candlestick") {
|
|
341
|
+
const s = o.points.length;
|
|
342
|
+
return s === 0 ? null : { time: o.points[s - 1].time, seriesIndex: -1 };
|
|
343
|
+
}
|
|
344
|
+
const t = "series" in o ? o.series : [o.points];
|
|
345
|
+
let e = null, i = -1;
|
|
346
|
+
for (let s = 0; s < t.length; s++) {
|
|
347
|
+
const n = t[s];
|
|
348
|
+
if (n.length === 0) continue;
|
|
349
|
+
const h = n[n.length - 1].time;
|
|
350
|
+
(e === null || h > e) && (e = h, i = s);
|
|
351
|
+
}
|
|
352
|
+
return e === null ? null : { time: e, seriesIndex: i };
|
|
353
|
+
}
|
|
354
|
+
function v(o, t) {
|
|
355
|
+
return o === "resize-left" || o === "resize-right" ? "ew-resize" : t ? "grabbing" : "grab";
|
|
356
|
+
}
|
|
357
|
+
function x(o, t) {
|
|
358
|
+
return v(A(o, t), !1);
|
|
359
|
+
}
|
|
360
|
+
function A(o, t) {
|
|
361
|
+
return y(o, t).gesture;
|
|
362
|
+
}
|
|
363
|
+
function b() {
|
|
364
|
+
const o = document.createElement("div");
|
|
365
|
+
o.style.cssText = "position:absolute;top:0;bottom:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;";
|
|
366
|
+
for (let t = 0; t < 3; t++) {
|
|
367
|
+
const e = document.createElement("div");
|
|
368
|
+
e.style.cssText = "width:2px;height:2px;border-radius:50%;flex-shrink:0;", o.appendChild(e);
|
|
369
|
+
}
|
|
370
|
+
return o;
|
|
371
|
+
}
|
|
372
|
+
export {
|
|
373
|
+
G as NavigatorController
|
|
374
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function m(e, i) {
|
|
2
|
+
if (e.length <= i || i <= 0) return e;
|
|
3
|
+
const h = e[0].time, c = e[e.length - 1].time, r = c - h;
|
|
4
|
+
if (r <= 0) return e;
|
|
5
|
+
const f = r / i, u = [];
|
|
6
|
+
let o = 0;
|
|
7
|
+
for (let l = 0; l < i; l++) {
|
|
8
|
+
const g = l === i - 1 ? c + 1 : h + (l + 1) * f;
|
|
9
|
+
let t = null, n = null;
|
|
10
|
+
for (; o < e.length && e[o].time < g; ) {
|
|
11
|
+
const s = e[o];
|
|
12
|
+
(t === null || s.value < t.value) && (t = s), (n === null || s.value > n.value) && (n = s), o++;
|
|
13
|
+
}
|
|
14
|
+
if (!(t === null || n === null)) {
|
|
15
|
+
if (t === n) {
|
|
16
|
+
u.push(t);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
t.time < n.time ? u.push(t, n) : u.push(n, t);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return u;
|
|
23
|
+
}
|
|
24
|
+
function a(e, i) {
|
|
25
|
+
if (e.length <= i || i <= 0) return e;
|
|
26
|
+
const h = e[0].time, c = e[e.length - 1].time, r = c - h;
|
|
27
|
+
if (r <= 0) return e;
|
|
28
|
+
const f = r / i, u = [];
|
|
29
|
+
let o = 0;
|
|
30
|
+
for (let l = 0; l < i; l++) {
|
|
31
|
+
const g = l === i - 1 ? c + 1 : h + (l + 1) * f;
|
|
32
|
+
let t = null;
|
|
33
|
+
for (; o < e.length && e[o].time < g; ) {
|
|
34
|
+
const n = e[o];
|
|
35
|
+
t === null ? t = { time: n.time, open: n.open, high: n.high, low: n.low, close: n.close } : (n.high > t.high && (t.high = n.high), n.low < t.low && (t.low = n.low), t.close = n.close), o++;
|
|
36
|
+
}
|
|
37
|
+
t !== null && u.push(t);
|
|
38
|
+
}
|
|
39
|
+
return u;
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
a as decimateCandles,
|
|
43
|
+
m as decimateLinear
|
|
44
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function p(a, o) {
|
|
2
|
+
return Math.abs(a - o.left) <= 8 ? { gesture: "resize-left", snapToCenter: !1 } : Math.abs(a - o.right) <= 8 ? { gesture: "resize-right", snapToCenter: !1 } : a > o.left && a < o.right ? { gesture: "pan", snapToCenter: !1 } : { gesture: "pan", snapToCenter: !0 };
|
|
3
|
+
}
|
|
4
|
+
function g(a) {
|
|
5
|
+
const { startVisible: o, deltaPx: f, pixelsPerTime: n, dataRange: r } = a, t = o.to - o.from, e = f / n;
|
|
6
|
+
let s = o.from + e, m = o.to + e;
|
|
7
|
+
return s < r.from && (s = r.from, m = s + t), m > r.to && (m = r.to, s = m - t), s < r.from && (s = r.from), { from: s, to: m };
|
|
8
|
+
}
|
|
9
|
+
function c(a) {
|
|
10
|
+
const { edge: o, startVisible: f, deltaPx: n, pixelsPerTime: r, dataRange: t, minSpan: e } = a, s = n / r;
|
|
11
|
+
if (o === "left") {
|
|
12
|
+
let l = f.from + s, u = f.to;
|
|
13
|
+
return l < t.from && (l = t.from), u - l < e && (l = u - e), l < t.from && (l = t.from, u = Math.min(t.to, l + e)), { from: l, to: u };
|
|
14
|
+
}
|
|
15
|
+
let m = f.from, i = f.to + s;
|
|
16
|
+
return i > t.to && (i = t.to), i - m < e && (i = m + e), i > t.to && (i = t.to, m = Math.max(t.from, i - e)), { from: m, to: i };
|
|
17
|
+
}
|
|
18
|
+
function h(a) {
|
|
19
|
+
const { time: o, startVisible: f, xRange: n } = a, r = f.to - f.from;
|
|
20
|
+
let t = o - r / 2, e = t + r;
|
|
21
|
+
return t < n.from && (t = n.from, e = t + r), e > n.to && (e = n.to, t = e - r), t < n.from && (t = n.from), { from: t, to: e };
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
g as computePan,
|
|
25
|
+
c as computeResize,
|
|
26
|
+
h as computeSnapCenter,
|
|
27
|
+
p as hitTest
|
|
28
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { resolveCandlestickBodyColor as x } from "../theme/resolve.js";
|
|
2
|
+
function k(d) {
|
|
3
|
+
const { ctx: o, theme: r, mediaWidth: t, mediaHeight: e } = d;
|
|
4
|
+
o.fillStyle = r.background, o.fillRect(0, 0, t, e);
|
|
5
|
+
}
|
|
6
|
+
function p(d, o, r = !0, t = 1) {
|
|
7
|
+
if (o.length < 2) return;
|
|
8
|
+
const { ctx: e, timeScale: a, yScale: h, mediaHeight: s, theme: n } = d, g = t < 1 && o.length >= 2, T = g ? o.length - 2 : o.length - 1;
|
|
9
|
+
if (r) {
|
|
10
|
+
const l = e.createLinearGradient(0, 0, 0, s);
|
|
11
|
+
l.addColorStop(0, n.line.areaTopColor), l.addColorStop(1, n.line.areaBottomColor), e.beginPath();
|
|
12
|
+
for (let i = 0; i <= T; i++) {
|
|
13
|
+
const c = o[i], m = a.timeToX(c.time), u = h.valueToY(c.value);
|
|
14
|
+
i === 0 ? e.moveTo(m, u) : e.lineTo(m, u);
|
|
15
|
+
}
|
|
16
|
+
if (e.lineTo(a.timeToX(o[T].time), s), e.lineTo(a.timeToX(o[0].time), s), e.closePath(), e.fillStyle = l, e.fill(), g) {
|
|
17
|
+
e.save(), e.globalAlpha = t, e.beginPath();
|
|
18
|
+
const i = o[T], c = o[o.length - 1], m = a.timeToX(i.time), u = a.timeToX(c.time);
|
|
19
|
+
e.moveTo(m, h.valueToY(i.value)), e.lineTo(u, h.valueToY(c.value)), e.lineTo(u, s), e.lineTo(m, s), e.closePath(), e.fillStyle = l, e.fill(), e.restore();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
e.beginPath();
|
|
23
|
+
for (let l = 0; l <= T; l++) {
|
|
24
|
+
const i = o[l], c = a.timeToX(i.time), m = h.valueToY(i.value);
|
|
25
|
+
l === 0 ? e.moveTo(c, m) : e.lineTo(c, m);
|
|
26
|
+
}
|
|
27
|
+
if (e.strokeStyle = n.line.color, e.lineWidth = n.line.width, e.stroke(), g) {
|
|
28
|
+
e.save(), e.globalAlpha = t, e.beginPath();
|
|
29
|
+
const l = o[T], i = o[o.length - 1];
|
|
30
|
+
e.moveTo(a.timeToX(l.time), h.valueToY(l.value)), e.lineTo(a.timeToX(i.time), h.valueToY(i.value)), e.strokeStyle = n.line.color, e.lineWidth = n.line.width, e.stroke(), e.restore();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function Y(d, o, r = 1) {
|
|
34
|
+
if (o.length === 0) return;
|
|
35
|
+
const { ctx: t, timeScale: e, yScale: a, mediaHeight: h, theme: s } = d, n = Math.max(
|
|
36
|
+
1,
|
|
37
|
+
o.length > 1 ? Math.abs(e.timeToX(o[1].time) - e.timeToX(o[0].time)) * 0.8 : 2
|
|
38
|
+
), g = r < 1, T = o.length - 1;
|
|
39
|
+
t.fillStyle = s.line.color;
|
|
40
|
+
for (let l = 0; l < o.length; l++) {
|
|
41
|
+
const i = o[l], c = e.timeToX(i.time), m = a.valueToY(i.value), u = Math.max(1, h - m);
|
|
42
|
+
g && l === T ? (t.save(), t.globalAlpha = r, t.fillRect(c - n / 2, m, n, u), t.restore()) : t.fillRect(c - n / 2, m, n, u);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function w(d, o, r = 1) {
|
|
46
|
+
if (o.length === 0) return;
|
|
47
|
+
const { ctx: t, timeScale: e, yScale: a, theme: h } = d, s = Math.max(
|
|
48
|
+
1,
|
|
49
|
+
o.length > 1 ? Math.abs(e.timeToX(o[1].time) - e.timeToX(o[0].time)) * 0.75 : 2
|
|
50
|
+
), n = r < 1, g = o.length - 1;
|
|
51
|
+
for (let T = 0; T < o.length; T++) {
|
|
52
|
+
const l = o[T], i = l.close >= l.open ? h.candlestick.up : h.candlestick.down, c = x(i.body), m = e.timeToX(l.time), u = a.valueToY(l.open), f = a.valueToY(l.close), M = a.valueToY(l.high), S = a.valueToY(l.low), v = n && T === g;
|
|
53
|
+
v && (t.save(), t.globalAlpha = r), t.strokeStyle = i.wick, t.lineWidth = 1, t.beginPath(), t.moveTo(m, M), t.lineTo(m, S), t.stroke();
|
|
54
|
+
const X = Math.min(u, f), b = Math.max(1, Math.abs(f - u));
|
|
55
|
+
t.fillStyle = c, t.fillRect(m - s / 2, X, s, b), v && t.restore();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function C(d, o, r) {
|
|
59
|
+
const t = Math.max(r.from, Math.min(r.to, o.from)), e = Math.max(r.from, Math.min(r.to, o.to)), a = d.timeToX(t), h = d.timeToX(e), s = Math.min(a, h), n = Math.max(a, h);
|
|
60
|
+
return { left: s, right: n, width: Math.max(1, n - s) };
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
C as computeWindowGeometry,
|
|
64
|
+
k as renderBackground,
|
|
65
|
+
Y as renderMiniBar,
|
|
66
|
+
w as renderMiniCandlestick,
|
|
67
|
+
p as renderMiniLine
|
|
68
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function p(c, r) {
|
|
2
|
+
const o = /* @__PURE__ */ new Map();
|
|
3
|
+
return new Proxy(c, {
|
|
4
|
+
get(n, t) {
|
|
5
|
+
const e = Reflect.get(n, t, n);
|
|
6
|
+
if (typeof e != "function") return e;
|
|
7
|
+
const s = o.get(t);
|
|
8
|
+
if (s) return s;
|
|
9
|
+
const f = typeof t == "string" ? t : String(t), g = e, u = (...i) => (r.set(f, (r.get(f) ?? 0) + 1), g.apply(n, i));
|
|
10
|
+
return o.set(t, u), u;
|
|
11
|
+
},
|
|
12
|
+
set(n, t, e) {
|
|
13
|
+
return Reflect.set(n, t, e, n);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
p as createCountingContext
|
|
19
|
+
};
|