@kevinburke/flot 5.1.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,100 @@ 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
+
8
102
  ## [5.1.0] - 2026-04-14
9
103
 
10
104
  ### Added
package/dist/flot.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @kevinburke/flot v5.1.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
 
@@ -719,10 +719,16 @@ var Flot = (function (exports) {
719
719
  var styleCache = layerCache[styleKey];
720
720
  for (var key in styleCache) {
721
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.
722
726
  var positions = styleCache[key].positions;
723
- positions.forEach(function(position) {
724
- position.active = false;
725
- });
727
+ if (positions != null) {
728
+ positions.forEach(function(position) {
729
+ position.active = false;
730
+ });
731
+ }
726
732
  }
727
733
  }
728
734
  }
@@ -3361,8 +3367,11 @@ var Flot = (function (exports) {
3361
3367
  };
3362
3368
 
3363
3369
  // we might need an extra decimal since forced
3364
- // ticks don't necessarily fit naturally
3365
- 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) {
3366
3375
  var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
3367
3376
  ts = axis.tickGenerator(axis, plot);
3368
3377
 
@@ -4269,7 +4278,13 @@ var Flot = (function (exports) {
4269
4278
  maxy = maxDistance / series.yaxis.scale,
4270
4279
  points = series.datapoints.points,
4271
4280
  ps = series.datapoints.pointsize,
4272
- 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;
4273
4288
 
4274
4289
  // with inverse transforms, we can't use the maxx/maxy
4275
4290
  // optimization, sadly
@@ -4469,7 +4484,16 @@ var Flot = (function (exports) {
4469
4484
  } else {
4470
4485
  // assume this is a gradient spec; IE currently only
4471
4486
  // supports a simple vertical gradient properly, so that's
4472
- // 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
+ }
4473
4497
  var gradient = ctx.createLinearGradient(0, top, 0, bottom);
4474
4498
 
4475
4499
  for (var i = 0, l = spec.colors.length; i < l; ++i) {
@@ -4497,7 +4521,7 @@ var Flot = (function (exports) {
4497
4521
  // Plugin registry. Plugins push to this array to register themselves.
4498
4522
  var plugins = [];
4499
4523
 
4500
- var version = "5.1.0";
4524
+ var version = "5.1.1";
4501
4525
 
4502
4526
  // The main plot function.
4503
4527
  function plot(placeholder, data, options) {
@@ -5758,6 +5782,17 @@ var Flot = (function (exports) {
5758
5782
  var minD = axis.p2c(opts.panRange[0]) - axis.p2c(axis.min);
5759
5783
  // calc max delta (revealing right edge of plot)
5760
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
+ }
5761
5796
  // limit delta to min or max if enabled
5762
5797
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5763
5798
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -5922,6 +5957,13 @@ var Flot = (function (exports) {
5922
5957
  var minD = p + axis.p2c(opts.panRange[0]) - axis.p2c(axisMin);
5923
5958
  // calc max delta (revealing right edge of plot)
5924
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
+ }
5925
5967
  // limit delta to min or max if enabled
5926
5968
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5927
5969
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -9485,6 +9527,17 @@ var Flot = (function (exports) {
9485
9527
  shape.strokeWidth = entry.options.points.lineWidth;
9486
9528
  iconHtml += getEntryIconHtml(shape);
9487
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
+ }
9488
9541
 
9489
9542
  labelHtml = '<text x="' + shape.xPos + '" y="' + shape.yPos + '" text-anchor="start"><tspan dx="2em" dy="1.2em">' + shape.label + '</tspan></text>';
9490
9543
  html[j++] = '<g>' + iconHtml + labelHtml + '</g>';
@@ -9524,9 +9577,17 @@ var Flot = (function (exports) {
9524
9577
  legendEl.style.pointerEvents = 'none';
9525
9578
  placeholder.appendChild(legendEl);
9526
9579
  } else {
9527
- options.legend.container.innerHTML = html.join('');
9528
- options.legend.container.style.width = width + 'px';
9529
- 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';
9530
9591
  }
9531
9592
  }
9532
9593
 
@@ -9620,6 +9681,14 @@ var Flot = (function (exports) {
9620
9681
  'width="1.5em" height="1.5em"' +
9621
9682
  '/>';
9622
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;
9623
9692
  default:
9624
9693
  // default is circle
9625
9694
  html = '<use xlink:href="#circle" class="legendIcon" ' +
@@ -9642,6 +9711,12 @@ var Flot = (function (exports) {
9642
9711
  '<polyline points="0,15 5,5 10,10 15,0"/>' +
9643
9712
  '</symbol>' +
9644
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
+
9645
9720
  '<symbol id="area" stroke-width="1" viewBox="-5 -5 25 25">' +
9646
9721
  '<polyline points="0,15 5,5 10,10 15,0, 15,15, 0,15"/>' +
9647
9722
  '</symbol>' +