@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/dist/flot.mjs 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 browser = {
3
3
  getPageXY: function (e) {
4
4
  var doc = document.documentElement,
@@ -21,7 +21,7 @@ var browser = {
21
21
  isSafari: function() {
22
22
  var top = window.top;
23
23
  if (!top) return false;
24
- return /constructor/i.test(top.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!top['safari'] || (typeof top.safari !== 'undefined' && top.safari.pushNotification));
24
+ 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));
25
25
  },
26
26
 
27
27
  isMobileSafari: function() {
@@ -102,6 +102,9 @@ function extend(deep, target) {
102
102
  var keys = Object.keys(src);
103
103
  for (var k = 0; k < keys.length; k++) {
104
104
  var key = keys[k];
105
+ if (key === '__proto__' || key === 'constructor') {
106
+ continue;
107
+ }
105
108
  var val = src[key];
106
109
  if (val === undefined) {
107
110
  continue;
@@ -168,10 +171,11 @@ function removeData(el, key) {
168
171
  }
169
172
  }
170
173
 
171
- // Trigger a custom event on an element. Extra args are passed as the
172
- // event's `detail` property (an array). For jQuery adapter compatibility,
173
- // the adapter re-dispatches these as jQuery events so $(el).on() works.
174
- function trigger(el, type, args) {
174
+ // Default trigger: dispatches a native CustomEvent with extra args stashed
175
+ // on `event.detail` (an array). The jQuery adapter overrides this via
176
+ // setTrigger so handlers bound with $(el).on(type, fn) receive the extra
177
+ // args as positional parameters, matching upstream flot/flot behavior.
178
+ var triggerImpl = function(el, type, args) {
175
179
  var event = new CustomEvent(type, {
176
180
  detail: args || [],
177
181
  bubbles: true,
@@ -179,6 +183,10 @@ function trigger(el, type, args) {
179
183
  });
180
184
  el.dispatchEvent(event);
181
185
  return event;
186
+ };
187
+
188
+ function trigger(el, type, args) {
189
+ return triggerImpl(el, type, args);
182
190
  }
183
191
 
184
192
  // Bind an event listener, tracking it so unbindAll can remove it later.
@@ -441,7 +449,9 @@ var Canvas = function(cls, container) {
441
449
  layer.style.left = '0px';
442
450
  layer.style.bottom = '0px';
443
451
  layer.style.right = '0px';
444
- svgElement.appendChild(layer);
452
+ if (svgElement) {
453
+ svgElement.appendChild(layer);
454
+ }
445
455
  this.SVG[classes] = layer;
446
456
  }
447
457
 
@@ -535,8 +545,8 @@ var Canvas = function(cls, container) {
535
545
 
536
546
  element.style.position = 'absolute';
537
547
  element.style.maxWidth = width;
538
- element.setAttributeNS(null, 'x', -9999);
539
- element.setAttributeNS(null, 'y', -9999);
548
+ element.setAttributeNS(null, 'x', String(-9999));
549
+ element.setAttributeNS(null, 'y', String(-9999));
540
550
 
541
551
  if (typeof font === 'object') {
542
552
  element.style.font = textStyle;
@@ -560,7 +570,9 @@ var Canvas = function(cls, container) {
560
570
  while (element.firstChild) {
561
571
  element.removeChild(element.firstChild);
562
572
  }
563
- element.parentNode.removeChild(element);
573
+ if (element.parentNode) {
574
+ element.parentNode.removeChild(element);
575
+ }
564
576
  }
565
577
 
566
578
  info.measured = true;
@@ -716,10 +728,16 @@ var Canvas = function(cls, container) {
716
728
  var styleCache = layerCache[styleKey];
717
729
  for (var key in styleCache) {
718
730
  if (Object.prototype.hasOwnProperty.call(styleCache, key)) {
731
+ // styleCache entries can exist without a
732
+ // positions array (e.g. when a Flot plugin
733
+ // populates the cache outside the normal
734
+ // addText path). Upstream flot/flot#1444.
719
735
  var positions = styleCache[key].positions;
720
- positions.forEach(function(position) {
721
- position.active = false;
722
- });
736
+ if (positions != null) {
737
+ positions.forEach(function(position) {
738
+ position.active = false;
739
+ });
740
+ }
723
741
  }
724
742
  }
725
743
  }
@@ -3358,8 +3376,11 @@ Licensed under the MIT license.
3358
3376
  };
3359
3377
 
3360
3378
  // we might need an extra decimal since forced
3361
- // ticks don't necessarily fit naturally
3362
- if (!axis.mode && opts.tickDecimals == null) {
3379
+ // ticks don't necessarily fit naturally.
3380
+ // Guard against axis.delta <= 0 (min == max): Math.log(0)
3381
+ // is -Infinity, so extraDec would be +Infinity and
3382
+ // toFixed(Infinity) throws. Upstream #1869 / PR #1870.
3383
+ if (!axis.mode && opts.tickDecimals == null && axis.delta > 0) {
3363
3384
  var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
3364
3385
  ts = axis.tickGenerator(axis, plot);
3365
3386
 
@@ -4266,7 +4287,13 @@ Licensed under the MIT license.
4266
4287
  maxy = maxDistance / series.yaxis.scale,
4267
4288
  points = series.datapoints.points,
4268
4289
  ps = series.datapoints.pointsize,
4269
- smallestDistance = Number.POSITIVE_INFINITY;
4290
+ // Seed with maxDistance (or its square, matching the
4291
+ // default squared-distance metric) so points outside
4292
+ // the hover radius are never selected. Without this,
4293
+ // the maxx/maxy coordinate-space pre-filter is the
4294
+ // only radius check, and it's disabled for axes with
4295
+ // inverseTransform — see upstream flot/flot#1871.
4296
+ smallestDistance = computeDistance ? maxDistance : maxDistance * maxDistance;
4270
4297
 
4271
4298
  // with inverse transforms, we can't use the maxx/maxy
4272
4299
  // optimization, sadly
@@ -4466,7 +4493,16 @@ Licensed under the MIT license.
4466
4493
  } else {
4467
4494
  // assume this is a gradient spec; IE currently only
4468
4495
  // supports a simple vertical gradient properly, so that's
4469
- // what we support too
4496
+ // what we support too.
4497
+ // createLinearGradient throws if any coordinate is NaN or
4498
+ // ±Infinity (e.g. when the plot container has zero size
4499
+ // or the user supplies bogus bounds) — fall back to the
4500
+ // default solid color instead. Global isFinite coerces
4501
+ // null → 0 (finite), matching the drawSeriesPoints path
4502
+ // that passes (null, null). Upstream flot/flot#1867.
4503
+ if (!isFinite(top) || !isFinite(bottom)) {
4504
+ return defaultColor;
4505
+ }
4470
4506
  var gradient = ctx.createLinearGradient(0, top, 0, bottom);
4471
4507
 
4472
4508
  for (var i = 0, l = spec.colors.length; i < l; ++i) {
@@ -4494,7 +4530,7 @@ Licensed under the MIT license.
4494
4530
  // Plugin registry. Plugins push to this array to register themselves.
4495
4531
  var plugins = [];
4496
4532
 
4497
- var version = "5.1.0";
4533
+ var version = "5.1.2";
4498
4534
 
4499
4535
  // The main plot function.
4500
4536
  function plot(placeholder, data, options) {
@@ -5755,6 +5791,17 @@ Licensed under the MIT license.
5755
5791
  var minD = axis.p2c(opts.panRange[0]) - axis.p2c(axis.min);
5756
5792
  // calc max delta (revealing right edge of plot)
5757
5793
  var maxD = axis.p2c(opts.panRange[1]) - axis.p2c(axis.max);
5794
+ // For the y-axis, screen coordinates are inverted
5795
+ // (p2c(smaller v) > p2c(larger v)), so minD/maxD end up
5796
+ // with the opposite signs from the x-axis case. Swap
5797
+ // them so the clamp comparisons below keep their
5798
+ // x-axis semantics. Upstream flot/flot#1789, ports the
5799
+ // minimal form of PR #1793.
5800
+ if (axis.direction === 'y') {
5801
+ var swap = minD;
5802
+ minD = maxD;
5803
+ maxD = swap;
5804
+ }
5758
5805
  // limit delta to min or max if enabled
5759
5806
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5760
5807
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -5919,6 +5966,13 @@ Licensed under the MIT license.
5919
5966
  var minD = p + axis.p2c(opts.panRange[0]) - axis.p2c(axisMin);
5920
5967
  // calc max delta (revealing right edge of plot)
5921
5968
  var maxD = p + axis.p2c(opts.panRange[1]) - axis.p2c(axisMax);
5969
+ // Same y-axis swap as plot.pan — see comment there.
5970
+ // Upstream flot/flot#1789 / PR #1793.
5971
+ if (axis.direction === 'y') {
5972
+ var swap = minD;
5973
+ minD = maxD;
5974
+ maxD = swap;
5975
+ }
5922
5976
  // limit delta to min or max if enabled
5923
5977
  if (opts.panRange[0] !== undefined && d >= maxD) d = maxD;
5924
5978
  if (opts.panRange[1] !== undefined && d <= minD) d = minD;
@@ -5972,7 +6026,7 @@ Licensed under the MIT license.
5972
6026
  ctx.lineJoin = "round";
5973
6027
  var startx = Math.round(panHint.start.x),
5974
6028
  starty = Math.round(panHint.start.y),
5975
- endx, endy;
6029
+ endx = 0, endy = 0;
5976
6030
 
5977
6031
  if (panAxes) {
5978
6032
  if (panAxes[0].direction === 'x') {
@@ -6737,13 +6791,14 @@ var options$4 = {
6737
6791
  }
6738
6792
 
6739
6793
  function initTouchNavigation$1(plot, options) {
6794
+ /** @type {{ zoomEnable: boolean, prevDistance: number | null, prevTapTime: number, prevPanPosition: {x: number, y: number}, prevTapPosition: {x: number, y: number} }} */
6740
6795
  var gestureState = {
6741
6796
  zoomEnable: false,
6742
6797
  prevDistance: null,
6743
- prevTapTime: 0,
6744
6798
  prevPanPosition: { x: 0, y: 0 },
6745
6799
  prevTapPosition: { x: 0, y: 0 }
6746
6800
  },
6801
+ /** @type {{ prevTouchedAxis: string, currentTouchedAxis: string, touchedAxis: any, navigationConstraint: string, initialState: any }} */
6747
6802
  navigationState = {
6748
6803
  prevTouchedAxis: 'none',
6749
6804
  currentTouchedAxis: 'none',
@@ -6800,7 +6855,7 @@ var options$4 = {
6800
6855
  drag: function(e) {
6801
6856
  presetNavigationState(e, 'pan');
6802
6857
 
6803
- if (useSmartPan) {
6858
+ if (useSmartPan && navigationState.initialState) {
6804
6859
  var point = getPoint(e, 'pan');
6805
6860
  plot.smartPan({
6806
6861
  x: navigationState.initialState.startPageX - point.x,
@@ -6824,7 +6879,7 @@ var options$4 = {
6824
6879
  }
6825
6880
 
6826
6881
  if (wasPinchEvent(e, gestureState)) {
6827
- updateprevPanPosition(e, 'pan', gestureState, navigationState);
6882
+ updatePrevPanPosition(e, 'pan', gestureState, navigationState);
6828
6883
  }
6829
6884
  }
6830
6885
  };
@@ -6856,7 +6911,7 @@ var options$4 = {
6856
6911
 
6857
6912
  var dist = pinchDistance(e);
6858
6913
 
6859
- if (gestureState.zoomEnable || Math.abs(dist - gestureState.prevDistance) > ZOOM_DISTANCE_MARGIN) {
6914
+ if (gestureState.zoomEnable || (gestureState.prevDistance != null && Math.abs(dist - gestureState.prevDistance) > ZOOM_DISTANCE_MARGIN)) {
6860
6915
  zoomPlot(plot, e, gestureState, navigationState);
6861
6916
 
6862
6917
  //activate zoom mode
@@ -7116,10 +7171,10 @@ var options$4 = {
7116
7171
  newEvent = new CustomEvent('mouseevent');
7117
7172
 
7118
7173
  //transform from touch event to mouse event format
7119
- newEvent.pageX = e.detail.changedTouches[0].pageX;
7120
- newEvent.pageY = e.detail.changedTouches[0].pageY;
7121
- newEvent.clientX = e.detail.changedTouches[0].clientX;
7122
- newEvent.clientY = e.detail.changedTouches[0].clientY;
7174
+ /** @type {any} */ (newEvent).pageX = e.detail.changedTouches[0].pageX;
7175
+ /** @type {any} */ (newEvent).pageY = e.detail.changedTouches[0].pageY;
7176
+ /** @type {any} */ (newEvent).clientX = e.detail.changedTouches[0].clientX;
7177
+ /** @type {any} */ (newEvent).clientY = e.detail.changedTouches[0].clientY;
7123
7178
 
7124
7179
  if (o.grid.hoverable) {
7125
7180
  doTriggerClickHoverEvent(newEvent, eventType.hover, 30);
@@ -7398,6 +7453,7 @@ var options$2 = {
7398
7453
  }
7399
7454
 
7400
7455
  function initTouchNavigation(plot, options) {
7456
+ /** @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 }} */
7401
7457
  var gestureState = {
7402
7458
  twoTouches: false,
7403
7459
  currentTapStart: { x: 0, y: 0 },
@@ -7551,6 +7607,7 @@ var options$2 = {
7551
7607
  },
7552
7608
 
7553
7609
  isLongTap: function(e) {
7610
+ if (gestureState.tapStartTime == null) return false;
7554
7611
  var currentTime = new Date().getTime(),
7555
7612
  tapDuration = currentTime - gestureState.tapStartTime;
7556
7613
  if (tapDuration >= minLongTapDuration && !gestureState.interceptedLongTap) {
@@ -7591,6 +7648,7 @@ var options$2 = {
7591
7648
  },
7592
7649
 
7593
7650
  isTap: function(e) {
7651
+ if (gestureState.tapStartTime == null) return false;
7594
7652
  var currentTime = new Date().getTime(),
7595
7653
  tapDuration = currentTime - gestureState.tapStartTime;
7596
7654
  if (tapDuration <= pressedTapDuration) {
@@ -7639,7 +7697,9 @@ var options$2 = {
7639
7697
  }
7640
7698
  function isDoubleTap(e) {
7641
7699
  var currentTime = new Date().getTime(),
7642
- intervalBetweenTaps = currentTime - gestureState.prevTapTime;
7700
+ intervalBetweenTaps = gestureState.prevTapTime != null
7701
+ ? currentTime - gestureState.prevTapTime
7702
+ : Infinity;
7643
7703
 
7644
7704
  if (intervalBetweenTaps >= 0 && intervalBetweenTaps < maxIntervalBetweenTaps) {
7645
7705
  if (distance(gestureState.prevTap.x, gestureState.prevTap.y, gestureState.currentTap.x, gestureState.currentTap.y) < maxDistanceBetweenTaps) {
@@ -8026,9 +8086,9 @@ API.txt for details.
8026
8086
  }
8027
8087
 
8028
8088
  for (var i = 0; i < spec.length - 1; ++i) {
8029
- if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] +
8030
- spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 &&
8031
- spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {
8089
+ if (axis.delta < (Number(spec[i][0]) * timeUnitSize[spec[i][1]] +
8090
+ Number(spec[i + 1][0]) * timeUnitSize[spec[i + 1][1]]) / 2 &&
8091
+ Number(spec[i][0]) * timeUnitSize[spec[i][1]] >= minSize) {
8032
8092
  break;
8033
8093
  }
8034
8094
  }
@@ -8691,6 +8751,7 @@ The plugin allso adds the following methods to the plot object:
8691
8751
  }
8692
8752
 
8693
8753
  function triggerSelectedEvent() {
8754
+ /** @type {any} */
8694
8755
  var r = getSelection();
8695
8756
 
8696
8757
  trigger(plot.getPlaceholder(), "plotselected", [ r ]);
@@ -8773,7 +8834,7 @@ The plugin allso adds the following methods to the plot object:
8773
8834
 
8774
8835
  // function taken from markings support in Flot
8775
8836
  function extractRange(ranges, coord) {
8776
- var axis, from, to, key, axes = plot.getAxes();
8837
+ var axis, from, to, /** @type {string|undefined} */ key, axes = plot.getAxes();
8777
8838
 
8778
8839
  for (var k in axes) {
8779
8840
  axis = axes[k];
@@ -8793,7 +8854,7 @@ The plugin allso adds the following methods to the plot object:
8793
8854
  }
8794
8855
 
8795
8856
  // backwards-compat stuff - to be removed in future
8796
- if (!ranges[key]) {
8857
+ if (key && !ranges[key]) {
8797
8858
  axis = coord === "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
8798
8859
  from = ranges[coord + "1"];
8799
8860
  to = ranges[coord + "2"];
@@ -9202,7 +9263,7 @@ temporary images load their data.
9202
9263
  const utf8Array = new Uint8Array(arrayBuffer);
9203
9264
  const blockSize = 16384;
9204
9265
  for (var i = 0; i < utf8Array.length; i = i + blockSize) {
9205
- const binarySubString = String.fromCharCode.apply(null, utf8Array.subarray(i, i + blockSize));
9266
+ const binarySubString = String.fromCharCode.apply(null, /** @type {any} */ (utf8Array.subarray(i, i + blockSize)));
9206
9267
  binaryString = binaryString + binarySubString;
9207
9268
  }
9208
9269
  return binaryString;
@@ -9417,7 +9478,7 @@ temporary images load their data.
9417
9478
 
9418
9479
  var left = 0;
9419
9480
  var columnWidths = [];
9420
- var style = window.getComputedStyle(document.querySelector('body'));
9481
+ var style = window.getComputedStyle(document.body);
9421
9482
  for (i = 0; i < entries.length; ++i) {
9422
9483
  let columnIndex = i % options.legend.noColumns;
9423
9484
  entry = entries[i];
@@ -9482,6 +9543,17 @@ temporary images load their data.
9482
9543
  shape.strokeWidth = entry.options.points.lineWidth;
9483
9544
  iconHtml += getEntryIconHtml(shape);
9484
9545
  }
9546
+ // fallback for plugin-drawn series (pie, errorbars, etc.)
9547
+ // that don't turn on any of lines/bars/points — without
9548
+ // this the legend entry has a label but no icon. Upstream
9549
+ // flot/flot#1641, minus the switch to `else if` so series
9550
+ // that deliberately overlay (e.g. lines + points) keep
9551
+ // rendering both icons.
9552
+ if (iconHtml === '') {
9553
+ shape.name = 'box';
9554
+ shape.fillColor = entry.color;
9555
+ iconHtml += getEntryIconHtml(shape);
9556
+ }
9485
9557
 
9486
9558
  labelHtml = '<text x="' + shape.xPos + '" y="' + shape.yPos + '" text-anchor="start"><tspan dx="2em" dy="1.2em">' + shape.label + '</tspan></text>';
9487
9559
  html[j++] = '<g>' + iconHtml + labelHtml + '</g>';
@@ -9521,9 +9593,17 @@ temporary images load their data.
9521
9593
  legendEl.style.pointerEvents = 'none';
9522
9594
  placeholder.appendChild(legendEl);
9523
9595
  } else {
9524
- options.legend.container.innerHTML = html.join('');
9525
- options.legend.container.style.width = width + 'px';
9526
- options.legend.container.style.height = height + 'em';
9596
+ // Accept either a DOM Element or a jQuery-wrapped container.
9597
+ // Upstream flot/flot#1750 switched to `$(container).get(0)` to
9598
+ // always land on the underlying element; since this fork is
9599
+ // jQuery-optional, do the unwrap inline.
9600
+ var container = options.legend.container;
9601
+ if (container && typeof container.get === 'function' && container[0]) {
9602
+ container = container[0];
9603
+ }
9604
+ container.innerHTML = html.join('');
9605
+ container.style.width = width + 'px';
9606
+ container.style.height = height + 'em';
9527
9607
  }
9528
9608
  }
9529
9609
 
@@ -9617,6 +9697,14 @@ temporary images load their data.
9617
9697
  'width="1.5em" height="1.5em"' +
9618
9698
  '/>';
9619
9699
  break;
9700
+ case 'box':
9701
+ html = '<use xlink:href="#box" class="legendIcon" ' +
9702
+ 'x="' + x + '" ' +
9703
+ 'y="' + y + '" ' +
9704
+ 'fill="' + fill + '" ' +
9705
+ 'width="1.5em" height="1.5em"' +
9706
+ '/>';
9707
+ break;
9620
9708
  default:
9621
9709
  // default is circle
9622
9710
  html = '<use xlink:href="#circle" class="legendIcon" ' +
@@ -9639,6 +9727,12 @@ temporary images load their data.
9639
9727
  '<polyline points="0,15 5,5 10,10 15,0"/>' +
9640
9728
  '</symbol>' +
9641
9729
 
9730
+ // Fallback icon for plugin-drawn series that don't turn on
9731
+ // any of lines / bars / points. Upstream flot/flot#1641.
9732
+ '<symbol id="box" stroke-width="1" viewBox="-5 -5 25 25">' +
9733
+ '<rect x="0" y="0" width="15" height="15"/>' +
9734
+ '</symbol>' +
9735
+
9642
9736
  '<symbol id="area" stroke-width="1" viewBox="-5 -5 25 25">' +
9643
9737
  '<polyline points="0,15 5,5 10,10 15,0, 15,15, 0,15"/>' +
9644
9738
  '</symbol>' +