@kevinburke/flot 5.1.0 → 5.1.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/CHANGELOG.md CHANGED
@@ -5,6 +5,124 @@ 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.2] - 2026-04-22
9
+
10
+ ### Fixed
11
+
12
+ - `jquery-adapter.js`: restore upstream flot/flot event-dispatch
13
+ semantics for consumers using `@kevinburke/flot/jquery` (or the
14
+ `jquery.flot.min.js` bundle). In 5.0.0, the fork's core switched to
15
+ native `CustomEvent` with extra args stashed on `event.detail`. That
16
+ is correct for the jQuery-free core, but broke every handler bound
17
+ through jQuery — `$(el).on("plothover", function(event, pos, item))`
18
+ silently received `undefined` for `pos` and `item`, because native
19
+ `dispatchEvent` does not spread args into jQuery handler positional
20
+ parameters. Same for `plotclick`, `plotselected`, `plotunselected`,
21
+ `plotselecting`, `plotzoom`, `plotpan`, `plotactivated`, and the pie
22
+ plugin's events.
23
+ Fixed by adding a `setTrigger()` hook in `helpers.js` and having the
24
+ jQuery adapter install a jQuery-aware trigger: arrays are dispatched
25
+ as `$(el).trigger(type, args)` (spreading into handler params);
26
+ non-array args are wrapped in a `$.Event` with `detail`, matching
27
+ upstream's `re-center` contract. The jQuery-free core path is
28
+ unchanged.
29
+ Added a browser regression test (`plothover handler receives pos
30
+ and item positional args`) that would have caught this.
31
+
32
+ ## [5.1.1] - 2026-04-15
33
+
34
+ ### Fixed
35
+
36
+ All bug fixes in this release are ports or re-implementations of
37
+ existing upstream work. Thanks to the reporters and submitters
38
+ credited below.
39
+
40
+ - `jquery.flot.js`: skip the `extraDec` branch in `setupTickGeneration`
41
+ when `axis.delta` is zero. Previously, a second `setupGrid()` call
42
+ (for example from the resize plugin) on an axis with `min === max`
43
+ and another axis using `alignTicksWithAxis` produced
44
+ `extraDec = +Infinity`, left `axis.tickDecimals` as `Infinity`, and
45
+ could throw `RangeError: toFixed() digits argument must be between
46
+ 0 and 100` during tick formatting. Ports
47
+ [flot/flot#1870](https://github.com/flot/flot/pull/1870)
48
+ (@LYarnall) for
49
+ [flot/flot#1869](https://github.com/flot/flot/issues/1869).
50
+ - `jquery.flot.js`: enforce `mouseActiveRadius` in `findNearbyPoint`
51
+ even when the pre-filter is disabled. Previously, seeding
52
+ `smallestDistance` with `+Infinity` meant the hover radius was only
53
+ enforced via the `maxx`/`maxy` coordinate-space pre-filter, which
54
+ is explicitly skipped for axes with `transform` /
55
+ `inverseTransform`. As a result, hovering anywhere in the plot
56
+ could highlight an arbitrarily distant point. Seed with
57
+ `maxDistance` (or its square, matching the default squared-distance
58
+ metric) so the radius is always an upper bound. Ports
59
+ [flot/flot#1872](https://github.com/flot/flot/pull/1872)
60
+ (@ErikSievers) for
61
+ [flot/flot#1871](https://github.com/flot/flot/issues/1871).
62
+ - `jquery.flot.js`: guard `getColorOrGradient` against non-finite
63
+ coordinates. `ctx.createLinearGradient(0, top, 0, bottom)` throws
64
+ `Uncaught TypeError: Argument 4 is not finite floating-point value`
65
+ when `top` or `bottom` is `NaN` or `±Infinity`, which can happen
66
+ when the plot container has zero size or when bogus axis bounds
67
+ flow in. Fall back to `defaultColor` in that case. Fixes upstream
68
+ [flot/flot#1867](https://github.com/flot/flot/issues/1867)
69
+ (reported by @jzabate).
70
+ - `jquery.flot.navigate.js`: panning on the y-axis with
71
+ `panRange` set no longer clamps the axis origin to
72
+ `panRange[0]`. Screen y coordinates run opposite to data y, so
73
+ the `minD` / `maxD` clamp bounds in `plot.pan` and `plot.smartPan`
74
+ needed to be swapped for y-axes. Fixes upstream
75
+ [flot/flot#1789](https://github.com/flot/flot/issues/1789)
76
+ (reported by @mjmlopes, diagnosed by @ecsv); ports the minimal
77
+ form of [flot/flot#1793](https://github.com/flot/flot/pull/1793)
78
+ (@netbymatt).
79
+ - `jquery.flot.pie.js`: `drawDonutHole` and `triggerClickHoverEvent`
80
+ now read `options` via `plot.getOptions()` instead of relying on
81
+ the closure-scoped value, which is `null` until the
82
+ `processDatapoints` hook runs. Ports
83
+ [flot/flot#1559](https://github.com/flot/flot/pull/1559)
84
+ (@mnofresno; duplicate of
85
+ [flot/flot#1547](https://github.com/flot/flot/pull/1547)).
86
+ - `jquery.flot.legend.js`: accept a jQuery-wrapped legend container,
87
+ not just a DOM element. Matches the intent of
88
+ [flot/flot#1750](https://github.com/flot/flot/pull/1750)
89
+ (@netbymatt, fixing
90
+ [flot/flot#1698](https://github.com/flot/flot/issues/1698)) but
91
+ inlines the unwrap since this fork is jQuery-optional.
92
+ - `jquery.flot.legend.js`: render a fallback "box" icon for plugin-
93
+ drawn series (e.g. pie, errorbars) that don't turn on
94
+ `lines.show`, `bars.show`, or `points.show`. Previously these
95
+ legend entries showed the label with no icon. Ports the
96
+ substantive half of
97
+ [flot/flot#1641](https://github.com/flot/flot/pull/1641)
98
+ (@faizalluthfi, fixing
99
+ [flot/flot#1640](https://github.com/flot/flot/issues/1640)); the
100
+ upstream PR also switched the icon-selection chain to `else if`,
101
+ which would regress series that intentionally overlay (e.g. lines
102
+ with points) — that part is deliberately not ported.
103
+ - `jquery.canvaswrapper.js`: guard against `positions == null` in
104
+ the text-cache iteration in `removeText`. Ports
105
+ [flot/flot#1444](https://github.com/flot/flot/pull/1444)
106
+ (@andig).
107
+
108
+ ### Changed
109
+
110
+ - Dev dependency: jQuery 3.7.1 -> 4.0.0.
111
+ - Dev dependency: Biome 1.9.4 -> 2.4.12 (includes config migration
112
+ to v2 format).
113
+ - Dev dependency: Vitest 2.1.9 -> 4.1.4.
114
+ - Dev dependency: happy-dom 15.11.7 -> 20.9.0.
115
+ - Dev dependency: size-limit 12.0.1 -> 12.1.0,
116
+ @size-limit/file 12.0.1 -> 12.1.0.
117
+ - CI: actions/checkout v4 -> v6, actions/setup-node v4 -> v6.
118
+
119
+ ### Thanks
120
+
121
+ Thanks to everyone upstream who investigated, reported, and patched
122
+ these bugs — the fixes in this release are direct ports of their
123
+ work: @LYarnall, @ErikSievers, @jzabate, @mjmlopes, @ecsv,
124
+ @netbymatt, @mnofresno, @faizalluthfi, @andig.
125
+
8
126
  ## [5.1.0] - 2026-04-14
9
127
 
10
128
  ### 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.2 | MIT License | https://github.com/kevinburke/flot */
2
2
  var Flot = (function (exports) {
3
3
  'use strict';
4
4
 
@@ -24,7 +24,7 @@ var Flot = (function (exports) {
24
24
  isSafari: function() {
25
25
  var top = window.top;
26
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));
27
+ return /constructor/i.test(/** @type {any} */ (top.HTMLElement)) || (function (/** @type {any} */ p) { return p.toString() === "[object SafariRemoteNotification]"; })(!(/** @type {any} */ (top))['safari'] || (typeof (/** @type {any} */ (top)).safari !== 'undefined' && (/** @type {any} */ (top)).safari.pushNotification));
28
28
  },
29
29
 
30
30
  isMobileSafari: function() {
@@ -105,6 +105,9 @@ var Flot = (function (exports) {
105
105
  var keys = Object.keys(src);
106
106
  for (var k = 0; k < keys.length; k++) {
107
107
  var key = keys[k];
108
+ if (key === '__proto__' || key === 'constructor') {
109
+ continue;
110
+ }
108
111
  var val = src[key];
109
112
  if (val === undefined) {
110
113
  continue;
@@ -171,10 +174,11 @@ var Flot = (function (exports) {
171
174
  }
172
175
  }
173
176
 
174
- // Trigger a custom event on an element. Extra args are passed as the
175
- // event's `detail` property (an array). For jQuery adapter compatibility,
176
- // the adapter re-dispatches these as jQuery events so $(el).on() works.
177
- function trigger(el, type, args) {
177
+ // Default trigger: dispatches a native CustomEvent with extra args stashed
178
+ // on `event.detail` (an array). The jQuery adapter overrides this via
179
+ // setTrigger so handlers bound with $(el).on(type, fn) receive the extra
180
+ // args as positional parameters, matching upstream flot/flot behavior.
181
+ var triggerImpl = function(el, type, args) {
178
182
  var event = new CustomEvent(type, {
179
183
  detail: args || [],
180
184
  bubbles: true,
@@ -182,6 +186,10 @@ var Flot = (function (exports) {
182
186
  });
183
187
  el.dispatchEvent(event);
184
188
  return event;
189
+ };
190
+
191
+ function trigger(el, type, args) {
192
+ return triggerImpl(el, type, args);
185
193
  }
186
194
 
187
195
  // Bind an event listener, tracking it so unbindAll can remove it later.
@@ -444,7 +452,9 @@ var Flot = (function (exports) {
444
452
  layer.style.left = '0px';
445
453
  layer.style.bottom = '0px';
446
454
  layer.style.right = '0px';
447
- svgElement.appendChild(layer);
455
+ if (svgElement) {
456
+ svgElement.appendChild(layer);
457
+ }
448
458
  this.SVG[classes] = layer;
449
459
  }
450
460
 
@@ -538,8 +548,8 @@ var Flot = (function (exports) {
538
548
 
539
549
  element.style.position = 'absolute';
540
550
  element.style.maxWidth = width;
541
- element.setAttributeNS(null, 'x', -9999);
542
- element.setAttributeNS(null, 'y', -9999);
551
+ element.setAttributeNS(null, 'x', String(-9999));
552
+ element.setAttributeNS(null, 'y', String(-9999));
543
553
 
544
554
  if (typeof font === 'object') {
545
555
  element.style.font = textStyle;
@@ -563,7 +573,9 @@ var Flot = (function (exports) {
563
573
  while (element.firstChild) {
564
574
  element.removeChild(element.firstChild);
565
575
  }
566
- element.parentNode.removeChild(element);
576
+ if (element.parentNode) {
577
+ element.parentNode.removeChild(element);
578
+ }
567
579
  }
568
580
 
569
581
  info.measured = true;
@@ -719,10 +731,16 @@ var Flot = (function (exports) {
719
731
  var styleCache = layerCache[styleKey];
720
732
  for (var key in styleCache) {
721
733
  if (Object.prototype.hasOwnProperty.call(styleCache, key)) {
734
+ // styleCache entries can exist without a
735
+ // positions array (e.g. when a Flot plugin
736
+ // populates the cache outside the normal
737
+ // addText path). Upstream flot/flot#1444.
722
738
  var positions = styleCache[key].positions;
723
- positions.forEach(function(position) {
724
- position.active = false;
725
- });
739
+ if (positions != null) {
740
+ positions.forEach(function(position) {
741
+ position.active = false;
742
+ });
743
+ }
726
744
  }
727
745
  }
728
746
  }
@@ -3361,8 +3379,11 @@ var Flot = (function (exports) {
3361
3379
  };
3362
3380
 
3363
3381
  // we might need an extra decimal since forced
3364
- // ticks don't necessarily fit naturally
3365
- if (!axis.mode && opts.tickDecimals == null) {
3382
+ // ticks don't necessarily fit naturally.
3383
+ // Guard against axis.delta <= 0 (min == max): Math.log(0)
3384
+ // is -Infinity, so extraDec would be +Infinity and
3385
+ // toFixed(Infinity) throws. Upstream #1869 / PR #1870.
3386
+ if (!axis.mode && opts.tickDecimals == null && axis.delta > 0) {
3366
3387
  var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
3367
3388
  ts = axis.tickGenerator(axis, plot);
3368
3389
 
@@ -4269,7 +4290,13 @@ var Flot = (function (exports) {
4269
4290
  maxy = maxDistance / series.yaxis.scale,
4270
4291
  points = series.datapoints.points,
4271
4292
  ps = series.datapoints.pointsize,
4272
- smallestDistance = Number.POSITIVE_INFINITY;
4293
+ // Seed with maxDistance (or its square, matching the
4294
+ // default squared-distance metric) so points outside
4295
+ // the hover radius are never selected. Without this,
4296
+ // the maxx/maxy coordinate-space pre-filter is the
4297
+ // only radius check, and it's disabled for axes with
4298
+ // inverseTransform — see upstream flot/flot#1871.
4299
+ smallestDistance = computeDistance ? maxDistance : maxDistance * maxDistance;
4273
4300
 
4274
4301
  // with inverse transforms, we can't use the maxx/maxy
4275
4302
  // optimization, sadly
@@ -4469,7 +4496,16 @@ var Flot = (function (exports) {
4469
4496
  } else {
4470
4497
  // assume this is a gradient spec; IE currently only
4471
4498
  // supports a simple vertical gradient properly, so that's
4472
- // what we support too
4499
+ // what we support too.
4500
+ // createLinearGradient throws if any coordinate is NaN or
4501
+ // ±Infinity (e.g. when the plot container has zero size
4502
+ // or the user supplies bogus bounds) — fall back to the
4503
+ // default solid color instead. Global isFinite coerces
4504
+ // null → 0 (finite), matching the drawSeriesPoints path
4505
+ // that passes (null, null). Upstream flot/flot#1867.
4506
+ if (!isFinite(top) || !isFinite(bottom)) {
4507
+ return defaultColor;
4508
+ }
4473
4509
  var gradient = ctx.createLinearGradient(0, top, 0, bottom);
4474
4510
 
4475
4511
  for (var i = 0, l = spec.colors.length; i < l; ++i) {
@@ -4497,7 +4533,7 @@ var Flot = (function (exports) {
4497
4533
  // Plugin registry. Plugins push to this array to register themselves.
4498
4534
  var plugins = [];
4499
4535
 
4500
- var version = "5.1.0";
4536
+ var version = "5.1.2";
4501
4537
 
4502
4538
  // The main plot function.
4503
4539
  function plot(placeholder, data, options) {
@@ -5758,6 +5794,17 @@ var Flot = (function (exports) {
5758
5794
  var minD = axis.p2c(opts.panRange[0]) - axis.p2c(axis.min);
5759
5795
  // calc max delta (revealing right edge of plot)
5760
5796
  var maxD = axis.p2c(opts.panRange[1]) - axis.p2c(axis.max);
5797
+ // For the y-axis, screen coordinates are inverted
5798
+ // (p2c(smaller v) > p2c(larger v)), so minD/maxD end up
5799
+ // with the opposite signs from the x-axis case. Swap
5800
+ // them so the clamp comparisons below keep their
5801
+ // x-axis semantics. Upstream flot/flot#1789, ports the
5802
+ // minimal form of PR #1793.
5803
+ if (axis.direction === 'y') {
5804
+ var swap = minD;
5805
+ minD = maxD;
5806
+ maxD = swap;
5807
+ }
5761
5808
  // limit delta to min or max if enabled
5762
5809
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5763
5810
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -5922,6 +5969,13 @@ var Flot = (function (exports) {
5922
5969
  var minD = p + axis.p2c(opts.panRange[0]) - axis.p2c(axisMin);
5923
5970
  // calc max delta (revealing right edge of plot)
5924
5971
  var maxD = p + axis.p2c(opts.panRange[1]) - axis.p2c(axisMax);
5972
+ // Same y-axis swap as plot.pan — see comment there.
5973
+ // Upstream flot/flot#1789 / PR #1793.
5974
+ if (axis.direction === 'y') {
5975
+ var swap = minD;
5976
+ minD = maxD;
5977
+ maxD = swap;
5978
+ }
5925
5979
  // limit delta to min or max if enabled
5926
5980
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5927
5981
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -5975,7 +6029,7 @@ var Flot = (function (exports) {
5975
6029
  ctx.lineJoin = "round";
5976
6030
  var startx = Math.round(panHint.start.x),
5977
6031
  starty = Math.round(panHint.start.y),
5978
- endx, endy;
6032
+ endx = 0, endy = 0;
5979
6033
 
5980
6034
  if (panAxes) {
5981
6035
  if (panAxes[0].direction === 'x') {
@@ -6740,13 +6794,14 @@ var Flot = (function (exports) {
6740
6794
  }
6741
6795
 
6742
6796
  function initTouchNavigation$1(plot, options) {
6797
+ /** @type {{ zoomEnable: boolean, prevDistance: number | null, prevTapTime: number, prevPanPosition: {x: number, y: number}, prevTapPosition: {x: number, y: number} }} */
6743
6798
  var gestureState = {
6744
6799
  zoomEnable: false,
6745
6800
  prevDistance: null,
6746
- prevTapTime: 0,
6747
6801
  prevPanPosition: { x: 0, y: 0 },
6748
6802
  prevTapPosition: { x: 0, y: 0 }
6749
6803
  },
6804
+ /** @type {{ prevTouchedAxis: string, currentTouchedAxis: string, touchedAxis: any, navigationConstraint: string, initialState: any }} */
6750
6805
  navigationState = {
6751
6806
  prevTouchedAxis: 'none',
6752
6807
  currentTouchedAxis: 'none',
@@ -6803,7 +6858,7 @@ var Flot = (function (exports) {
6803
6858
  drag: function(e) {
6804
6859
  presetNavigationState(e, 'pan');
6805
6860
 
6806
- if (useSmartPan) {
6861
+ if (useSmartPan && navigationState.initialState) {
6807
6862
  var point = getPoint(e, 'pan');
6808
6863
  plot.smartPan({
6809
6864
  x: navigationState.initialState.startPageX - point.x,
@@ -6827,7 +6882,7 @@ var Flot = (function (exports) {
6827
6882
  }
6828
6883
 
6829
6884
  if (wasPinchEvent(e, gestureState)) {
6830
- updateprevPanPosition(e, 'pan', gestureState, navigationState);
6885
+ updatePrevPanPosition(e, 'pan', gestureState, navigationState);
6831
6886
  }
6832
6887
  }
6833
6888
  };
@@ -6859,7 +6914,7 @@ var Flot = (function (exports) {
6859
6914
 
6860
6915
  var dist = pinchDistance(e);
6861
6916
 
6862
- if (gestureState.zoomEnable || Math.abs(dist - gestureState.prevDistance) > ZOOM_DISTANCE_MARGIN) {
6917
+ if (gestureState.zoomEnable || (gestureState.prevDistance != null && Math.abs(dist - gestureState.prevDistance) > ZOOM_DISTANCE_MARGIN)) {
6863
6918
  zoomPlot(plot, e, gestureState, navigationState);
6864
6919
 
6865
6920
  //activate zoom mode
@@ -7119,10 +7174,10 @@ var Flot = (function (exports) {
7119
7174
  newEvent = new CustomEvent('mouseevent');
7120
7175
 
7121
7176
  //transform from touch event to mouse event format
7122
- newEvent.pageX = e.detail.changedTouches[0].pageX;
7123
- newEvent.pageY = e.detail.changedTouches[0].pageY;
7124
- newEvent.clientX = e.detail.changedTouches[0].clientX;
7125
- newEvent.clientY = e.detail.changedTouches[0].clientY;
7177
+ /** @type {any} */ (newEvent).pageX = e.detail.changedTouches[0].pageX;
7178
+ /** @type {any} */ (newEvent).pageY = e.detail.changedTouches[0].pageY;
7179
+ /** @type {any} */ (newEvent).clientX = e.detail.changedTouches[0].clientX;
7180
+ /** @type {any} */ (newEvent).clientY = e.detail.changedTouches[0].clientY;
7126
7181
 
7127
7182
  if (o.grid.hoverable) {
7128
7183
  doTriggerClickHoverEvent(newEvent, eventType.hover, 30);
@@ -7401,6 +7456,7 @@ var Flot = (function (exports) {
7401
7456
  }
7402
7457
 
7403
7458
  function initTouchNavigation(plot, options) {
7459
+ /** @type {{ twoTouches: boolean, currentTapStart: {x: number, y: number}, currentTapEnd: {x: number, y: number}, prevTap: {x: number, y: number}, currentTap: {x: number, y: number}, interceptedLongTap: boolean, isUnsupportedGesture: boolean, prevTapTime: number | null, tapStartTime: number | null, longTapTriggerId: ReturnType<typeof setTimeout> | null }} */
7404
7460
  var gestureState = {
7405
7461
  twoTouches: false,
7406
7462
  currentTapStart: { x: 0, y: 0 },
@@ -7554,6 +7610,7 @@ var Flot = (function (exports) {
7554
7610
  },
7555
7611
 
7556
7612
  isLongTap: function(e) {
7613
+ if (gestureState.tapStartTime == null) return false;
7557
7614
  var currentTime = new Date().getTime(),
7558
7615
  tapDuration = currentTime - gestureState.tapStartTime;
7559
7616
  if (tapDuration >= minLongTapDuration && !gestureState.interceptedLongTap) {
@@ -7594,6 +7651,7 @@ var Flot = (function (exports) {
7594
7651
  },
7595
7652
 
7596
7653
  isTap: function(e) {
7654
+ if (gestureState.tapStartTime == null) return false;
7597
7655
  var currentTime = new Date().getTime(),
7598
7656
  tapDuration = currentTime - gestureState.tapStartTime;
7599
7657
  if (tapDuration <= pressedTapDuration) {
@@ -7642,7 +7700,9 @@ var Flot = (function (exports) {
7642
7700
  }
7643
7701
  function isDoubleTap(e) {
7644
7702
  var currentTime = new Date().getTime(),
7645
- intervalBetweenTaps = currentTime - gestureState.prevTapTime;
7703
+ intervalBetweenTaps = gestureState.prevTapTime != null
7704
+ ? currentTime - gestureState.prevTapTime
7705
+ : Infinity;
7646
7706
 
7647
7707
  if (intervalBetweenTaps >= 0 && intervalBetweenTaps < maxIntervalBetweenTaps) {
7648
7708
  if (distance(gestureState.prevTap.x, gestureState.prevTap.y, gestureState.currentTap.x, gestureState.currentTap.y) < maxDistanceBetweenTaps) {
@@ -8029,9 +8089,9 @@ var Flot = (function (exports) {
8029
8089
  }
8030
8090
 
8031
8091
  for (var i = 0; i < spec.length - 1; ++i) {
8032
- if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] +
8033
- spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 &&
8034
- spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {
8092
+ if (axis.delta < (Number(spec[i][0]) * timeUnitSize[spec[i][1]] +
8093
+ Number(spec[i + 1][0]) * timeUnitSize[spec[i + 1][1]]) / 2 &&
8094
+ Number(spec[i][0]) * timeUnitSize[spec[i][1]] >= minSize) {
8035
8095
  break;
8036
8096
  }
8037
8097
  }
@@ -8694,6 +8754,7 @@ var Flot = (function (exports) {
8694
8754
  }
8695
8755
 
8696
8756
  function triggerSelectedEvent() {
8757
+ /** @type {any} */
8697
8758
  var r = getSelection();
8698
8759
 
8699
8760
  trigger(plot.getPlaceholder(), "plotselected", [ r ]);
@@ -8776,7 +8837,7 @@ var Flot = (function (exports) {
8776
8837
 
8777
8838
  // function taken from markings support in Flot
8778
8839
  function extractRange(ranges, coord) {
8779
- var axis, from, to, key, axes = plot.getAxes();
8840
+ var axis, from, to, /** @type {string|undefined} */ key, axes = plot.getAxes();
8780
8841
 
8781
8842
  for (var k in axes) {
8782
8843
  axis = axes[k];
@@ -8796,7 +8857,7 @@ var Flot = (function (exports) {
8796
8857
  }
8797
8858
 
8798
8859
  // backwards-compat stuff - to be removed in future
8799
- if (!ranges[key]) {
8860
+ if (key && !ranges[key]) {
8800
8861
  axis = coord === "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
8801
8862
  from = ranges[coord + "1"];
8802
8863
  to = ranges[coord + "2"];
@@ -9205,7 +9266,7 @@ var Flot = (function (exports) {
9205
9266
  const utf8Array = new Uint8Array(arrayBuffer);
9206
9267
  const blockSize = 16384;
9207
9268
  for (var i = 0; i < utf8Array.length; i = i + blockSize) {
9208
- const binarySubString = String.fromCharCode.apply(null, utf8Array.subarray(i, i + blockSize));
9269
+ const binarySubString = String.fromCharCode.apply(null, /** @type {any} */ (utf8Array.subarray(i, i + blockSize)));
9209
9270
  binaryString = binaryString + binarySubString;
9210
9271
  }
9211
9272
  return binaryString;
@@ -9420,7 +9481,7 @@ var Flot = (function (exports) {
9420
9481
 
9421
9482
  var left = 0;
9422
9483
  var columnWidths = [];
9423
- var style = window.getComputedStyle(document.querySelector('body'));
9484
+ var style = window.getComputedStyle(document.body);
9424
9485
  for (i = 0; i < entries.length; ++i) {
9425
9486
  let columnIndex = i % options.legend.noColumns;
9426
9487
  entry = entries[i];
@@ -9485,6 +9546,17 @@ var Flot = (function (exports) {
9485
9546
  shape.strokeWidth = entry.options.points.lineWidth;
9486
9547
  iconHtml += getEntryIconHtml(shape);
9487
9548
  }
9549
+ // fallback for plugin-drawn series (pie, errorbars, etc.)
9550
+ // that don't turn on any of lines/bars/points — without
9551
+ // this the legend entry has a label but no icon. Upstream
9552
+ // flot/flot#1641, minus the switch to `else if` so series
9553
+ // that deliberately overlay (e.g. lines + points) keep
9554
+ // rendering both icons.
9555
+ if (iconHtml === '') {
9556
+ shape.name = 'box';
9557
+ shape.fillColor = entry.color;
9558
+ iconHtml += getEntryIconHtml(shape);
9559
+ }
9488
9560
 
9489
9561
  labelHtml = '<text x="' + shape.xPos + '" y="' + shape.yPos + '" text-anchor="start"><tspan dx="2em" dy="1.2em">' + shape.label + '</tspan></text>';
9490
9562
  html[j++] = '<g>' + iconHtml + labelHtml + '</g>';
@@ -9524,9 +9596,17 @@ var Flot = (function (exports) {
9524
9596
  legendEl.style.pointerEvents = 'none';
9525
9597
  placeholder.appendChild(legendEl);
9526
9598
  } else {
9527
- options.legend.container.innerHTML = html.join('');
9528
- options.legend.container.style.width = width + 'px';
9529
- options.legend.container.style.height = height + 'em';
9599
+ // Accept either a DOM Element or a jQuery-wrapped container.
9600
+ // Upstream flot/flot#1750 switched to `$(container).get(0)` to
9601
+ // always land on the underlying element; since this fork is
9602
+ // jQuery-optional, do the unwrap inline.
9603
+ var container = options.legend.container;
9604
+ if (container && typeof container.get === 'function' && container[0]) {
9605
+ container = container[0];
9606
+ }
9607
+ container.innerHTML = html.join('');
9608
+ container.style.width = width + 'px';
9609
+ container.style.height = height + 'em';
9530
9610
  }
9531
9611
  }
9532
9612
 
@@ -9620,6 +9700,14 @@ var Flot = (function (exports) {
9620
9700
  'width="1.5em" height="1.5em"' +
9621
9701
  '/>';
9622
9702
  break;
9703
+ case 'box':
9704
+ html = '<use xlink:href="#box" class="legendIcon" ' +
9705
+ 'x="' + x + '" ' +
9706
+ 'y="' + y + '" ' +
9707
+ 'fill="' + fill + '" ' +
9708
+ 'width="1.5em" height="1.5em"' +
9709
+ '/>';
9710
+ break;
9623
9711
  default:
9624
9712
  // default is circle
9625
9713
  html = '<use xlink:href="#circle" class="legendIcon" ' +
@@ -9642,6 +9730,12 @@ var Flot = (function (exports) {
9642
9730
  '<polyline points="0,15 5,5 10,10 15,0"/>' +
9643
9731
  '</symbol>' +
9644
9732
 
9733
+ // Fallback icon for plugin-drawn series that don't turn on
9734
+ // any of lines / bars / points. Upstream flot/flot#1641.
9735
+ '<symbol id="box" stroke-width="1" viewBox="-5 -5 25 25">' +
9736
+ '<rect x="0" y="0" width="15" height="15"/>' +
9737
+ '</symbol>' +
9738
+
9645
9739
  '<symbol id="area" stroke-width="1" viewBox="-5 -5 25 25">' +
9646
9740
  '<polyline points="0,15 5,5 10,10 15,0, 15,15, 0,15"/>' +
9647
9741
  '</symbol>' +