@kevinburke/flot 5.0.0 → 5.1.1

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 CHANGED
@@ -5,6 +5,135 @@ All notable changes to this project will be documented in this file.
5
5
  Starting with 5.0.0, this changelog tracks the @kevinburke/flot fork.
6
6
  For earlier upstream history, see the [flot/flot repository](https://github.com/flot/flot).
7
7
 
8
+ ## [5.1.1] - 2026-04-15
9
+
10
+ ### Fixed
11
+
12
+ All bug fixes in this release are ports or re-implementations of
13
+ existing upstream work. Thanks to the reporters and submitters
14
+ credited below.
15
+
16
+ - `jquery.flot.js`: skip the `extraDec` branch in `setupTickGeneration`
17
+ when `axis.delta` is zero. Previously, a second `setupGrid()` call
18
+ (for example from the resize plugin) on an axis with `min === max`
19
+ and another axis using `alignTicksWithAxis` produced
20
+ `extraDec = +Infinity`, left `axis.tickDecimals` as `Infinity`, and
21
+ could throw `RangeError: toFixed() digits argument must be between
22
+ 0 and 100` during tick formatting. Ports
23
+ [flot/flot#1870](https://github.com/flot/flot/pull/1870)
24
+ (@LYarnall) for
25
+ [flot/flot#1869](https://github.com/flot/flot/issues/1869).
26
+ - `jquery.flot.js`: enforce `mouseActiveRadius` in `findNearbyPoint`
27
+ even when the pre-filter is disabled. Previously, seeding
28
+ `smallestDistance` with `+Infinity` meant the hover radius was only
29
+ enforced via the `maxx`/`maxy` coordinate-space pre-filter, which
30
+ is explicitly skipped for axes with `transform` /
31
+ `inverseTransform`. As a result, hovering anywhere in the plot
32
+ could highlight an arbitrarily distant point. Seed with
33
+ `maxDistance` (or its square, matching the default squared-distance
34
+ metric) so the radius is always an upper bound. Ports
35
+ [flot/flot#1872](https://github.com/flot/flot/pull/1872)
36
+ (@ErikSievers) for
37
+ [flot/flot#1871](https://github.com/flot/flot/issues/1871).
38
+ - `jquery.flot.js`: guard `getColorOrGradient` against non-finite
39
+ coordinates. `ctx.createLinearGradient(0, top, 0, bottom)` throws
40
+ `Uncaught TypeError: Argument 4 is not finite floating-point value`
41
+ when `top` or `bottom` is `NaN` or `±Infinity`, which can happen
42
+ when the plot container has zero size or when bogus axis bounds
43
+ flow in. Fall back to `defaultColor` in that case. Fixes upstream
44
+ [flot/flot#1867](https://github.com/flot/flot/issues/1867)
45
+ (reported by @jzabate).
46
+ - `jquery.flot.navigate.js`: panning on the y-axis with
47
+ `panRange` set no longer clamps the axis origin to
48
+ `panRange[0]`. Screen y coordinates run opposite to data y, so
49
+ the `minD` / `maxD` clamp bounds in `plot.pan` and `plot.smartPan`
50
+ needed to be swapped for y-axes. Fixes upstream
51
+ [flot/flot#1789](https://github.com/flot/flot/issues/1789)
52
+ (reported by @mjmlopes, diagnosed by @ecsv); ports the minimal
53
+ form of [flot/flot#1793](https://github.com/flot/flot/pull/1793)
54
+ (@netbymatt).
55
+ - `jquery.flot.pie.js`: `drawDonutHole` and `triggerClickHoverEvent`
56
+ now read `options` via `plot.getOptions()` instead of relying on
57
+ the closure-scoped value, which is `null` until the
58
+ `processDatapoints` hook runs. Ports
59
+ [flot/flot#1559](https://github.com/flot/flot/pull/1559)
60
+ (@mnofresno; duplicate of
61
+ [flot/flot#1547](https://github.com/flot/flot/pull/1547)).
62
+ - `jquery.flot.legend.js`: accept a jQuery-wrapped legend container,
63
+ not just a DOM element. Matches the intent of
64
+ [flot/flot#1750](https://github.com/flot/flot/pull/1750)
65
+ (@netbymatt, fixing
66
+ [flot/flot#1698](https://github.com/flot/flot/issues/1698)) but
67
+ inlines the unwrap since this fork is jQuery-optional.
68
+ - `jquery.flot.legend.js`: render a fallback "box" icon for plugin-
69
+ drawn series (e.g. pie, errorbars) that don't turn on
70
+ `lines.show`, `bars.show`, or `points.show`. Previously these
71
+ legend entries showed the label with no icon. Ports the
72
+ substantive half of
73
+ [flot/flot#1641](https://github.com/flot/flot/pull/1641)
74
+ (@faizalluthfi, fixing
75
+ [flot/flot#1640](https://github.com/flot/flot/issues/1640)); the
76
+ upstream PR also switched the icon-selection chain to `else if`,
77
+ which would regress series that intentionally overlay (e.g. lines
78
+ with points) — that part is deliberately not ported.
79
+ - `jquery.canvaswrapper.js`: guard against `positions == null` in
80
+ the text-cache iteration in `removeText`. Ports
81
+ [flot/flot#1444](https://github.com/flot/flot/pull/1444)
82
+ (@andig).
83
+
84
+ ### Changed
85
+
86
+ - Dev dependency: jQuery 3.7.1 -> 4.0.0.
87
+ - Dev dependency: Biome 1.9.4 -> 2.4.12 (includes config migration
88
+ to v2 format).
89
+ - Dev dependency: Vitest 2.1.9 -> 4.1.4.
90
+ - Dev dependency: happy-dom 15.11.7 -> 20.9.0.
91
+ - Dev dependency: size-limit 12.0.1 -> 12.1.0,
92
+ @size-limit/file 12.0.1 -> 12.1.0.
93
+ - CI: actions/checkout v4 -> v6, actions/setup-node v4 -> v6.
94
+
95
+ ### Thanks
96
+
97
+ Thanks to everyone upstream who investigated, reported, and patched
98
+ these bugs — the fixes in this release are direct ports of their
99
+ work: @LYarnall, @ErikSievers, @jzabate, @mjmlopes, @ecsv,
100
+ @netbymatt, @mnofresno, @faizalluthfi, @andig.
101
+
102
+ ## [5.1.0] - 2026-04-14
103
+
104
+ ### Added
105
+
106
+ - **TypeScript type definitions.** Hand-written `.d.ts` files now ship
107
+ with the package. `import { plot, type PlotOptions } from '@kevinburke/flot'`
108
+ gives full autocomplete and type-checking. The jQuery adapter types
109
+ augment `JQueryStatic` so `$.plot()` is also typed.
110
+ - Package validation via `publint` in CI.
111
+ - Source code type-checking via TypeScript `checkJs` mode with a
112
+ ratchet (`.tsc-baseline`) that enforces the error count doesn't
113
+ grow.
114
+
115
+ ### Fixed
116
+
117
+ - `jquery.canvaswrapper.js`: replace bare `hasOwnProperty.call(...)`
118
+ with `Object.prototype.hasOwnProperty.call(...)`. The bare form
119
+ would `ReferenceError` in strict mode — a latent bug in the SVG
120
+ text rendering path.
121
+ - `jquery.flot.composeImages.js`: drop the ignored `"utf-8"` argument
122
+ from `new TextEncoder()`.
123
+ - `jquery.flot.browser.js`: cache `window.top` and null-check it
124
+ before accessing browser-detection properties.
125
+ - `jquery.flot.js`: add null guard after the `options.grid.markings`
126
+ callback in case the user returns `null`/`undefined`.
127
+ - Remove dead arguments from a few internal function calls.
128
+
129
+ ### Internal
130
+
131
+ - Added GitHub Actions Dependabot configuration.
132
+ - Added `RELEASING.md` documenting the release process.
133
+ - Removed `TEST-PORTING.md` (test migration plan completed with v5.0.0).
134
+ - Suppressed benign Rollup missing-global warnings on standalone
135
+ plugin builds.
136
+
8
137
  ## [5.0.0] - 2026-04-14
9
138
 
10
139
  First stable release of the @kevinburke/flot fork. The plotting API is
package/README.md CHANGED
@@ -42,7 +42,7 @@ plot(document.getElementById('placeholder'), data, options);
42
42
  Or via `<script>` tag from a CDN:
43
43
 
44
44
  ```html
45
- <script src="https://unpkg.com/@kevinburke/flot@5.0.0/dist/flot.min.js"></script>
45
+ <script src="https://unpkg.com/@kevinburke/flot@5.1.0/dist/flot.min.js"></script>
46
46
  <script>
47
47
  Flot.plot(document.getElementById('placeholder'), data, options);
48
48
  </script>
@@ -52,7 +52,7 @@ Or via `<script>` tag from a CDN:
52
52
 
53
53
  ```html
54
54
  <script src="https://unpkg.com/jquery@3/dist/jquery.min.js"></script>
55
- <script src="https://unpkg.com/@kevinburke/flot@5.0.0/dist/jquery.flot.min.js"></script>
55
+ <script src="https://unpkg.com/@kevinburke/flot@5.1.0/dist/jquery.flot.min.js"></script>
56
56
  <script>
57
57
  $.plot("#placeholder", data, options);
58
58
  </script>
package/dist/flot.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @kevinburke/flot v5.0.0 | MIT License | https://github.com/kevinburke/flot */
1
+ /*! @kevinburke/flot v5.1.1 | MIT License | https://github.com/kevinburke/flot */
2
2
  var Flot = (function (exports) {
3
3
  'use strict';
4
4
 
@@ -22,7 +22,9 @@ var Flot = (function (exports) {
22
22
  },
23
23
 
24
24
  isSafari: function() {
25
- return /constructor/i.test(window.top.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window.top['safari'] || (typeof window.top.safari !== 'undefined' && window.top.safari.pushNotification));
25
+ var top = window.top;
26
+ if (!top) return false;
27
+ return /constructor/i.test(top.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!top['safari'] || (typeof top.safari !== 'undefined' && top.safari.pushNotification));
26
28
  },
27
29
 
28
30
  isMobileSafari: function() {
@@ -30,7 +32,7 @@ var Flot = (function (exports) {
30
32
  },
31
33
 
32
34
  isOpera: function() {
33
- return (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
35
+ return (!!window.opr && !!window.opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
34
36
  },
35
37
 
36
38
  isFirefox: function() {
@@ -348,7 +350,7 @@ var Flot = (function (exports) {
348
350
  // already been rendered, and remove those that are no longer active.
349
351
 
350
352
  for (var layerKey in cache) {
351
- if (hasOwnProperty.call(cache, layerKey)) {
353
+ if (Object.prototype.hasOwnProperty.call(cache, layerKey)) {
352
354
  var layer = this.getSVGLayer(layerKey),
353
355
  layerCache = cache[layerKey];
354
356
 
@@ -356,10 +358,10 @@ var Flot = (function (exports) {
356
358
  layer.style.display = 'none';
357
359
 
358
360
  for (var styleKey in layerCache) {
359
- if (hasOwnProperty.call(layerCache, styleKey)) {
361
+ if (Object.prototype.hasOwnProperty.call(layerCache, styleKey)) {
360
362
  var styleCache = layerCache[styleKey];
361
363
  for (var key in styleCache) {
362
- if (hasOwnProperty.call(styleCache, key)) {
364
+ if (Object.prototype.hasOwnProperty.call(styleCache, key)) {
363
365
  var val = styleCache[key],
364
366
  positions = val.positions;
365
367
 
@@ -713,14 +715,20 @@ var Flot = (function (exports) {
713
715
  var layerCache = this._textCache[layer];
714
716
  if (layerCache != null) {
715
717
  for (var styleKey in layerCache) {
716
- if (hasOwnProperty.call(layerCache, styleKey)) {
718
+ if (Object.prototype.hasOwnProperty.call(layerCache, styleKey)) {
717
719
  var styleCache = layerCache[styleKey];
718
720
  for (var key in styleCache) {
719
- if (hasOwnProperty.call(styleCache, key)) {
721
+ if (Object.prototype.hasOwnProperty.call(styleCache, key)) {
722
+ // styleCache entries can exist without a
723
+ // positions array (e.g. when a Flot plugin
724
+ // populates the cache outside the normal
725
+ // addText path). Upstream flot/flot#1444.
720
726
  var positions = styleCache[key].positions;
721
- positions.forEach(function(position) {
722
- position.active = false;
723
- });
727
+ if (positions != null) {
728
+ positions.forEach(function(position) {
729
+ position.active = false;
730
+ });
731
+ }
724
732
  }
725
733
  }
726
734
  }
@@ -749,7 +757,7 @@ var Flot = (function (exports) {
749
757
  Canvas.prototype.clearCache = function() {
750
758
  var cache = this._textCache;
751
759
  for (var layerKey in cache) {
752
- if (hasOwnProperty.call(cache, layerKey)) {
760
+ if (Object.prototype.hasOwnProperty.call(cache, layerKey)) {
753
761
  var layer = this.getSVGLayer(layerKey);
754
762
  while (layer.firstChild) {
755
763
  layer.removeChild(layer.firstChild);
@@ -3359,8 +3367,11 @@ var Flot = (function (exports) {
3359
3367
  };
3360
3368
 
3361
3369
  // we might need an extra decimal since forced
3362
- // ticks don't necessarily fit naturally
3363
- if (!axis.mode && opts.tickDecimals == null) {
3370
+ // ticks don't necessarily fit naturally.
3371
+ // Guard against axis.delta <= 0 (min == max): Math.log(0)
3372
+ // is -Infinity, so extraDec would be +Infinity and
3373
+ // toFixed(Infinity) throws. Upstream #1869 / PR #1870.
3374
+ if (!axis.mode && opts.tickDecimals == null && axis.delta > 0) {
3364
3375
  var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
3365
3376
  ts = axis.tickGenerator(axis, plot);
3366
3377
 
@@ -3578,6 +3589,8 @@ var Flot = (function (exports) {
3578
3589
  markings = markings(axes);
3579
3590
  }
3580
3591
 
3592
+ if (!markings) return;
3593
+
3581
3594
  var i;
3582
3595
  for (i = 0; i < markings.length; ++i) {
3583
3596
  var m = markings[i],
@@ -4265,7 +4278,13 @@ var Flot = (function (exports) {
4265
4278
  maxy = maxDistance / series.yaxis.scale,
4266
4279
  points = series.datapoints.points,
4267
4280
  ps = series.datapoints.pointsize,
4268
- smallestDistance = Number.POSITIVE_INFINITY;
4281
+ // Seed with maxDistance (or its square, matching the
4282
+ // default squared-distance metric) so points outside
4283
+ // the hover radius are never selected. Without this,
4284
+ // the maxx/maxy coordinate-space pre-filter is the
4285
+ // only radius check, and it's disabled for axes with
4286
+ // inverseTransform — see upstream flot/flot#1871.
4287
+ smallestDistance = computeDistance ? maxDistance : maxDistance * maxDistance;
4269
4288
 
4270
4289
  // with inverse transforms, we can't use the maxx/maxy
4271
4290
  // optimization, sadly
@@ -4465,7 +4484,16 @@ var Flot = (function (exports) {
4465
4484
  } else {
4466
4485
  // assume this is a gradient spec; IE currently only
4467
4486
  // supports a simple vertical gradient properly, so that's
4468
- // what we support too
4487
+ // what we support too.
4488
+ // createLinearGradient throws if any coordinate is NaN or
4489
+ // ±Infinity (e.g. when the plot container has zero size
4490
+ // or the user supplies bogus bounds) — fall back to the
4491
+ // default solid color instead. Global isFinite coerces
4492
+ // null → 0 (finite), matching the drawSeriesPoints path
4493
+ // that passes (null, null). Upstream flot/flot#1867.
4494
+ if (!isFinite(top) || !isFinite(bottom)) {
4495
+ return defaultColor;
4496
+ }
4469
4497
  var gradient = ctx.createLinearGradient(0, top, 0, bottom);
4470
4498
 
4471
4499
  for (var i = 0, l = spec.colors.length; i < l; ++i) {
@@ -4493,7 +4521,7 @@ var Flot = (function (exports) {
4493
4521
  // Plugin registry. Plugins push to this array to register themselves.
4494
4522
  var plugins = [];
4495
4523
 
4496
- var version = "5.0.0";
4524
+ var version = "5.1.1";
4497
4525
 
4498
4526
  // The main plot function.
4499
4527
  function plot(placeholder, data, options) {
@@ -5754,6 +5782,17 @@ var Flot = (function (exports) {
5754
5782
  var minD = axis.p2c(opts.panRange[0]) - axis.p2c(axis.min);
5755
5783
  // calc max delta (revealing right edge of plot)
5756
5784
  var maxD = axis.p2c(opts.panRange[1]) - axis.p2c(axis.max);
5785
+ // For the y-axis, screen coordinates are inverted
5786
+ // (p2c(smaller v) > p2c(larger v)), so minD/maxD end up
5787
+ // with the opposite signs from the x-axis case. Swap
5788
+ // them so the clamp comparisons below keep their
5789
+ // x-axis semantics. Upstream flot/flot#1789, ports the
5790
+ // minimal form of PR #1793.
5791
+ if (axis.direction === 'y') {
5792
+ var swap = minD;
5793
+ minD = maxD;
5794
+ maxD = swap;
5795
+ }
5757
5796
  // limit delta to min or max if enabled
5758
5797
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5759
5798
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -5918,6 +5957,13 @@ var Flot = (function (exports) {
5918
5957
  var minD = p + axis.p2c(opts.panRange[0]) - axis.p2c(axisMin);
5919
5958
  // calc max delta (revealing right edge of plot)
5920
5959
  var maxD = p + axis.p2c(opts.panRange[1]) - axis.p2c(axisMax);
5960
+ // Same y-axis swap as plot.pan — see comment there.
5961
+ // Upstream flot/flot#1789 / PR #1793.
5962
+ if (axis.direction === 'y') {
5963
+ var swap = minD;
5964
+ minD = maxD;
5965
+ maxD = swap;
5966
+ }
5921
5967
  // limit delta to min or max if enabled
5922
5968
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5923
5969
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -9215,7 +9261,7 @@ var Flot = (function (exports) {
9215
9261
 
9216
9262
  // Encode the string as UTF-8 and convert it to a binary string. The UTF-8 encoding is required to
9217
9263
  // capture unicode characters correctly.
9218
- utf8BinaryString = buildBinaryString(new (TextEncoder || TextEncoderLite)('utf-8').encode(source));
9264
+ utf8BinaryString = buildBinaryString(new (TextEncoder || TextEncoderLite)().encode(source));
9219
9265
 
9220
9266
  data = "data:image/svg+xml;base64," + btoa(utf8BinaryString);
9221
9267
  img.src = data;
@@ -9481,6 +9527,17 @@ var Flot = (function (exports) {
9481
9527
  shape.strokeWidth = entry.options.points.lineWidth;
9482
9528
  iconHtml += getEntryIconHtml(shape);
9483
9529
  }
9530
+ // fallback for plugin-drawn series (pie, errorbars, etc.)
9531
+ // that don't turn on any of lines/bars/points — without
9532
+ // this the legend entry has a label but no icon. Upstream
9533
+ // flot/flot#1641, minus the switch to `else if` so series
9534
+ // that deliberately overlay (e.g. lines + points) keep
9535
+ // rendering both icons.
9536
+ if (iconHtml === '') {
9537
+ shape.name = 'box';
9538
+ shape.fillColor = entry.color;
9539
+ iconHtml += getEntryIconHtml(shape);
9540
+ }
9484
9541
 
9485
9542
  labelHtml = '<text x="' + shape.xPos + '" y="' + shape.yPos + '" text-anchor="start"><tspan dx="2em" dy="1.2em">' + shape.label + '</tspan></text>';
9486
9543
  html[j++] = '<g>' + iconHtml + labelHtml + '</g>';
@@ -9520,9 +9577,17 @@ var Flot = (function (exports) {
9520
9577
  legendEl.style.pointerEvents = 'none';
9521
9578
  placeholder.appendChild(legendEl);
9522
9579
  } else {
9523
- options.legend.container.innerHTML = html.join('');
9524
- options.legend.container.style.width = width + 'px';
9525
- options.legend.container.style.height = height + 'em';
9580
+ // Accept either a DOM Element or a jQuery-wrapped container.
9581
+ // Upstream flot/flot#1750 switched to `$(container).get(0)` to
9582
+ // always land on the underlying element; since this fork is
9583
+ // jQuery-optional, do the unwrap inline.
9584
+ var container = options.legend.container;
9585
+ if (container && typeof container.get === 'function' && container[0]) {
9586
+ container = container[0];
9587
+ }
9588
+ container.innerHTML = html.join('');
9589
+ container.style.width = width + 'px';
9590
+ container.style.height = height + 'em';
9526
9591
  }
9527
9592
  }
9528
9593
 
@@ -9616,6 +9681,14 @@ var Flot = (function (exports) {
9616
9681
  'width="1.5em" height="1.5em"' +
9617
9682
  '/>';
9618
9683
  break;
9684
+ case 'box':
9685
+ html = '<use xlink:href="#box" class="legendIcon" ' +
9686
+ 'x="' + x + '" ' +
9687
+ 'y="' + y + '" ' +
9688
+ 'fill="' + fill + '" ' +
9689
+ 'width="1.5em" height="1.5em"' +
9690
+ '/>';
9691
+ break;
9619
9692
  default:
9620
9693
  // default is circle
9621
9694
  html = '<use xlink:href="#circle" class="legendIcon" ' +
@@ -9638,6 +9711,12 @@ var Flot = (function (exports) {
9638
9711
  '<polyline points="0,15 5,5 10,10 15,0"/>' +
9639
9712
  '</symbol>' +
9640
9713
 
9714
+ // Fallback icon for plugin-drawn series that don't turn on
9715
+ // any of lines / bars / points. Upstream flot/flot#1641.
9716
+ '<symbol id="box" stroke-width="1" viewBox="-5 -5 25 25">' +
9717
+ '<rect x="0" y="0" width="15" height="15"/>' +
9718
+ '</symbol>' +
9719
+
9641
9720
  '<symbol id="area" stroke-width="1" viewBox="-5 -5 25 25">' +
9642
9721
  '<polyline points="0,15 5,5 10,10 15,0, 15,15, 0,15"/>' +
9643
9722
  '</symbol>' +