wickchart 2.0.0 → 2.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wickchart",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "<wick-chart> — a modern, dependency-free financial charting web component. Candles, line & area charts, crosshair, zoom/pan, indicators (incl. a safe expression mini-language), live streaming via <wick-feed> (incl. tick/volume/dollar bars), a worker compute path for 1M-bar histories, report export, theming.",
5
5
  "type": "module",
6
6
  "main": "src/wick-chart.js",
package/src/wick-chart.js CHANGED
@@ -238,6 +238,8 @@ class WickChart extends HTMLElementBase {
238
238
  this._hover = null; // { index, x, y }
239
239
  this._dt = HOUR; // median bar interval (ms)
240
240
  this._ly = null; // last layout
241
+ this._priceW = null; // settled price-axis width (see _axisWidth)
242
+ this._pwNarrow = null; // pending axis shrink { want, t }
241
243
  this._cache = { v: -1, map: {} };
242
244
  this._pal = null; // palette cache
243
245
  this._palKey = '';
@@ -624,6 +626,9 @@ class WickChart extends HTMLElementBase {
624
626
  this._version++;
625
627
  this._epoch++;
626
628
  this._computeDt();
629
+ // a replacement dataset is a new instrument regime — re-measure the
630
+ // axis from its own prices instead of debouncing down from the old one
631
+ this._priceW = this._pwNarrow = null;
627
632
  // history is not a live signal: re-baseline so close-mode alerts only
628
633
  // fire on candles that close from here on
629
634
  this._syncClosedIdx();
@@ -685,6 +690,7 @@ class WickChart extends HTMLElementBase {
685
690
  this._data = [];
686
691
  this._version++;
687
692
  this._epoch++;
693
+ this._priceW = this._pwNarrow = null;
688
694
  this._syncClosedIdx();
689
695
  this._hover = null;
690
696
  this._needsFit = true;
@@ -1310,6 +1316,32 @@ class WickChart extends HTMLElementBase {
1310
1316
  this._raf = requestAnimationFrame(() => this._render());
1311
1317
  }
1312
1318
 
1319
+ /**
1320
+ * Price-axis width with tick-noise immunity. The width is measured from
1321
+ * the live last close, and digits in a proportional font measure
1322
+ * differently ("1" is narrower than "8") — so on every tick the ceil()
1323
+ * can flip a pixel, dragging the axis separator and with it every candle
1324
+ * sideways (visibly shaking on high-frequency pairs). Grow at once so a
1325
+ * wider label never clips; adopt a narrower width only after it has held
1326
+ * for 750ms, and only when it's a real change (≥2px) rather than
1327
+ * digit-width noise, so a flapping price can never wobble the layout.
1328
+ */
1329
+ _axisWidth(want) {
1330
+ const prev = this._priceW;
1331
+ if (prev == null || want >= prev) {
1332
+ this._priceW = want;
1333
+ this._pwNarrow = null;
1334
+ } else if (want <= prev - 2) {
1335
+ if (this._pwNarrow == null || this._pwNarrow.want !== want) {
1336
+ this._pwNarrow = { want, t: performance.now() };
1337
+ } else if (performance.now() - this._pwNarrow.t >= 750) {
1338
+ this._priceW = want;
1339
+ this._pwNarrow = null;
1340
+ }
1341
+ }
1342
+ return this._priceW;
1343
+ }
1344
+
1313
1345
  _prec(v) {
1314
1346
  return this._precision != null ? this._precision : autoPrecision(v);
1315
1347
  }
@@ -1839,14 +1871,16 @@ class WickChart extends HTMLElementBase {
1839
1871
  const sample = d.length ? d[d.length - 1].close : 0;
1840
1872
  const p = this._prec(sample || 1);
1841
1873
  const f = numberFmt(p);
1842
- priceW = Math.max(
1843
- 52,
1844
- Math.ceil(
1845
- Math.max(
1846
- measure(f.format(sample || 1000)),
1847
- measure(fmtCompact(1234567))
1848
- )
1849
- ) + 16
1874
+ priceW = this._axisWidth(
1875
+ Math.max(
1876
+ 52,
1877
+ Math.ceil(
1878
+ Math.max(
1879
+ measure(f.format(sample || 1000)),
1880
+ measure(fmtCompact(1234567))
1881
+ )
1882
+ ) + 16
1883
+ )
1850
1884
  );
1851
1885
  }
1852
1886
  const timeH = 26;
@@ -1879,6 +1913,10 @@ class WickChart extends HTMLElementBase {
1879
1913
  });
1880
1914
 
1881
1915
  /* background */
1916
+ // Clear explicitly: the fill below is also the only clear, and with
1917
+ // --wick-bg: transparent it paints nothing — without this every redraw
1918
+ // stacks on the previous frame's pixels.
1919
+ ctx.clearRect(0, 0, W, H);
1882
1920
  ctx.fillStyle = pal.bg;
1883
1921
  ctx.fillRect(0, 0, W, H);
1884
1922
  this._nodata.hidden = d.length > 0;
@@ -46,6 +46,11 @@ declare class WickChart extends HTMLElementBase {
46
46
  h: number;
47
47
  };
48
48
  };
49
+ _priceW: any;
50
+ _pwNarrow: {
51
+ want: any;
52
+ t: number;
53
+ };
49
54
  _cache: {
50
55
  v: number;
51
56
  map: {};
@@ -675,6 +680,17 @@ declare class WickChart extends HTMLElementBase {
675
680
  _computeDt(): void;
676
681
  _updateAria(): void;
677
682
  _invalidate(): void;
683
+ /**
684
+ * Price-axis width with tick-noise immunity. The width is measured from
685
+ * the live last close, and digits in a proportional font measure
686
+ * differently ("1" is narrower than "8") — so on every tick the ceil()
687
+ * can flip a pixel, dragging the axis separator and with it every candle
688
+ * sideways (visibly shaking on high-frequency pairs). Grow at once so a
689
+ * wider label never clips; adopt a narrower width only after it has held
690
+ * for 750ms, and only when it's a real change (≥2px) rather than
691
+ * digit-width noise, so a flapping price can never wobble the layout.
692
+ */
693
+ _axisWidth(want: any): any;
678
694
  _prec(v: any): any;
679
695
  _palette(): {
680
696
  overlay: any;