traderead-charts 1.3.1 → 1.3.3
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 +22 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/traderead-charts.js +30 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.3.3 — 2026-09-29
|
|
4
|
+
|
|
5
|
+
- **The view can be dragged past the last bar by half the plot**, not by ten
|
|
6
|
+
bars. On a phone at 2 px a bar ten bars were 20 px: the latest candles
|
|
7
|
+
stayed pinned to the price axis and could not be brought to the middle to
|
|
8
|
+
zoom on them. The limit is now in pixels; wide bars keep the old ten.
|
|
9
|
+
- **Pinch zooms around the fingers**, and the bar under them stays under
|
|
10
|
+
them. It used to zoom from the right edge only.
|
|
11
|
+
- **Pinch measures the real distance between the fingers.** A pinch made
|
|
12
|
+
with one finger above the other has almost no horizontal spread; measuring
|
|
13
|
+
only that made the zoom jump.
|
|
14
|
+
- **A pinch on the chart never zooms the page instead.** iOS ignores
|
|
15
|
+
`user-scalable=no`: the touch handler now claims the gesture, and Safari's
|
|
16
|
+
own `gesturestart` / `gesturechange` are cancelled on the chart.
|
|
17
|
+
|
|
18
|
+
## 1.3.2 — 2026-09-20
|
|
19
|
+
|
|
20
|
+
- **README install example unpinned from 1.2.0.** The copy-paste snippet on
|
|
21
|
+
the npm page still pointed at an old build, so anyone following it landed
|
|
22
|
+
three releases back, without the measure tool. It now pins 1.3.1. No code
|
|
23
|
+
change; the engine is byte-identical to 1.3.0.
|
|
24
|
+
|
|
3
25
|
## 1.3.1 — 2026-09-20
|
|
4
26
|
|
|
5
27
|
- **`homepage` now points at traderead.ai**, not at the GitHub Pages docs
|
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ npm install traderead-charts
|
|
|
58
58
|
or straight from a CDN, no build step:
|
|
59
59
|
|
|
60
60
|
```html
|
|
61
|
-
<script src="https://cdn.jsdelivr.net/npm/traderead-charts@1.
|
|
61
|
+
<script src="https://cdn.jsdelivr.net/npm/traderead-charts@1.3.1/src/traderead-charts.js"></script>
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
## Quick start
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "traderead-charts",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "Complete financial charting widget — candlesticks, indicators with a pro-style panel, drawing tools, symbol search, themes. Batteries included, zero dependencies, in production on traderead.ai.",
|
|
5
5
|
"main": "src/traderead-charts.js",
|
|
6
6
|
"files": [
|
package/src/traderead-charts.js
CHANGED
|
@@ -758,6 +758,14 @@
|
|
|
758
758
|
Chart.prototype.xToIndex = function (x) {
|
|
759
759
|
return this.rightIndex + this.opt.rightPadBars - (this._plotW() - x) / this.barSpacing;
|
|
760
760
|
};
|
|
761
|
+
// How far past the last bar the view may be dragged: the pad, or half the
|
|
762
|
+
// plot, whichever is more — in pixels, not bars. Ten bars of slack was 20 px
|
|
763
|
+
// on a phone at 2 px a bar: the latest candles stayed pinned to the price
|
|
764
|
+
// axis and could not be brought to the middle to zoom on them (owner's
|
|
765
|
+
// find, 29 Sep 2026).
|
|
766
|
+
Chart.prototype._maxRight = function () {
|
|
767
|
+
return this.bars.length - 1 + Math.max(this.opt.rightPadBars * 2, (this._plotW() * 0.5) / (this.barSpacing || 1));
|
|
768
|
+
};
|
|
761
769
|
Chart.prototype._visibleRange = function () {
|
|
762
770
|
var lo = Math.floor(this.xToIndex(0)), hi = Math.ceil(this.xToIndex(this._plotW()));
|
|
763
771
|
return [clamp(lo, 0, this.bars.length - 1), clamp(hi, 0, this.bars.length - 1)];
|
|
@@ -1938,7 +1946,7 @@
|
|
|
1938
1946
|
function step(now) {
|
|
1939
1947
|
var dt = now - last; last = now;
|
|
1940
1948
|
self.rightIndex = clamp(self.rightIndex - glide.v * dt / self.barSpacing,
|
|
1941
|
-
0, self.
|
|
1949
|
+
0, self._maxRight());
|
|
1942
1950
|
self._paint();
|
|
1943
1951
|
glide.v *= Math.pow(0.94, dt / 16.7);
|
|
1944
1952
|
if (Math.abs(glide.v) >= 0.05) glide.raf = requestAnimationFrame(step);
|
|
@@ -2003,7 +2011,7 @@
|
|
|
2003
2011
|
}
|
|
2004
2012
|
glide.lastX = nowX; glide.lastT = nowT;
|
|
2005
2013
|
self.rightIndex = drag.right0 + (drag.x0 - nowX) / self.barSpacing;
|
|
2006
|
-
self.rightIndex = clamp(self.rightIndex, 0, self.
|
|
2014
|
+
self.rightIndex = clamp(self.rightIndex, 0, self._maxRight());
|
|
2007
2015
|
if (drag.vpan) {
|
|
2008
2016
|
var us = self.panes[0].h * (1 - self.opt.volumeHeightPct * 0.35) || 1;
|
|
2009
2017
|
self._vOff = drag.off0 + (e.clientY - r.top - drag.y0) / us;
|
|
@@ -2152,7 +2160,7 @@
|
|
|
2152
2160
|
// way every charting tool treats it. Vertical wheel stays zoom.
|
|
2153
2161
|
if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) {
|
|
2154
2162
|
self.rightIndex = clamp(self.rightIndex + e.deltaX / self.barSpacing,
|
|
2155
|
-
0, self.
|
|
2163
|
+
0, self._maxRight());
|
|
2156
2164
|
self._paint();
|
|
2157
2165
|
return;
|
|
2158
2166
|
}
|
|
@@ -2209,8 +2217,12 @@
|
|
|
2209
2217
|
if (self._draft) { self.drawings.push(self._draft); self._selected = self._draft.id; self._draft = null; self._persist(); self._paintDrawings(); }
|
|
2210
2218
|
self._dragDraw = null; self._sepDrag = null; drag = null;
|
|
2211
2219
|
self._touchLock();
|
|
2212
|
-
|
|
2213
|
-
|
|
2220
|
+
// Zoom around the fingers, on their real distance: a pinch made with
|
|
2221
|
+
// one finger above the other has almost no horizontal spread, and
|
|
2222
|
+
// measuring only that made the zoom jump.
|
|
2223
|
+
var f0 = e.touches[0], f1 = e.touches[1];
|
|
2224
|
+
pinch = { d0: Math.hypot(f0.clientX - f1.clientX, f0.clientY - f1.clientY) || 1, spacing0: self.barSpacing,
|
|
2225
|
+
anchor: self.xToIndex((f0.clientX + f1.clientX) / 2 - r.left) };
|
|
2214
2226
|
}
|
|
2215
2227
|
}, { passive: true });
|
|
2216
2228
|
el.addEventListener("touchmove", function (e) {
|
|
@@ -2254,9 +2266,16 @@
|
|
|
2254
2266
|
return;
|
|
2255
2267
|
}
|
|
2256
2268
|
if (pinch && e.touches.length === 2) {
|
|
2257
|
-
var
|
|
2258
|
-
|
|
2269
|
+
var g0 = e.touches[0], g1 = e.touches[1];
|
|
2270
|
+
var pd = Math.hypot(g0.clientX - g1.clientX, g0.clientY - g1.clientY) || 1;
|
|
2271
|
+
var pmx = (g0.clientX + g1.clientX) / 2 - r.left;
|
|
2272
|
+
self.barSpacing = clamp(pinch.spacing0 * pd / pinch.d0, self.opt.minBarSpacing, self.opt.maxBarSpacing);
|
|
2273
|
+
// the bar that was under the fingers stays under them (and follows
|
|
2274
|
+
// them: two fingers also pan)
|
|
2275
|
+
self.rightIndex = clamp(pinch.anchor - (self.xToIndex(pmx) - self.rightIndex), 0, self._maxRight());
|
|
2259
2276
|
self._paint();
|
|
2277
|
+
// the page must not zoom instead: iOS ignores user-scalable=no
|
|
2278
|
+
e.preventDefault();
|
|
2260
2279
|
} else if (drag && e.touches.length === 1) {
|
|
2261
2280
|
var tNowT = performance.now(), tNowX = e.touches[0].clientX - r.left;
|
|
2262
2281
|
if (glide.lastT) {
|
|
@@ -2265,7 +2284,7 @@
|
|
|
2265
2284
|
}
|
|
2266
2285
|
glide.lastX = tNowX; glide.lastT = tNowT;
|
|
2267
2286
|
self.rightIndex = drag.right0 + (drag.x0 - tNowX) / self.barSpacing;
|
|
2268
|
-
self.rightIndex = clamp(self.rightIndex, 0, self.
|
|
2287
|
+
self.rightIndex = clamp(self.rightIndex, 0, self._maxRight());
|
|
2269
2288
|
if (drag.vpan) {
|
|
2270
2289
|
var us2 = self.panes[0].h * (1 - self.opt.volumeHeightPct * 0.35) || 1;
|
|
2271
2290
|
self._vOff = drag.off0 + (e.touches[0].clientY - r.top - drag.y0) / us2;
|
|
@@ -2291,6 +2310,9 @@
|
|
|
2291
2310
|
self._touchLock();
|
|
2292
2311
|
}
|
|
2293
2312
|
el.addEventListener("touchend", endTouch, { passive: true });
|
|
2313
|
+
// Safari's own pinch events: without this it zooms the whole page.
|
|
2314
|
+
el.addEventListener("gesturestart", function (e) { e.preventDefault(); });
|
|
2315
|
+
el.addEventListener("gesturechange", function (e) { e.preventDefault(); });
|
|
2294
2316
|
// a browser-fired cancel must COMMIT the in-flight shape, not destroy it
|
|
2295
2317
|
el.addEventListener("touchcancel", endTouch, { passive: true });
|
|
2296
2318
|
};
|