highcharts
Version:
JavaScript charting framework
1,566 lines (1,534 loc) • 89.1 kB
JavaScript
// SPDX-License-Identifier: LicenseRef-Highcharts
/**
* @license Highcharts JS v12.6.0 (2026-04-13)
* @module highcharts/modules/tiledwebmap
* @requires highcharts
*
* (c) 2009-2026
*
* A commercial license may be required depending on use.
* See www.highcharts.com/license
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(root["_Highcharts"], root["_Highcharts"]["SeriesRegistry"]);
else if(typeof define === 'function' && define.amd)
define("highcharts/modules/tiledwebmap", ["highcharts/highcharts"], function (amd1) {return factory(amd1,amd1["SeriesRegistry"]);});
else if(typeof exports === 'object')
exports["highcharts/modules/tiledwebmap"] = factory(root["_Highcharts"], root["_Highcharts"]["SeriesRegistry"]);
else
root["Highcharts"] = factory(root["Highcharts"], root["Highcharts"]["SeriesRegistry"]);
})(typeof window === 'undefined' ? this : window, (__WEBPACK_EXTERNAL_MODULE__944__, __WEBPACK_EXTERNAL_MODULE__512__) => {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 512:
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_MODULE__512__;
/***/ }),
/***/ 944:
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_MODULE__944__;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
"default": () => (/* binding */ tiledwebmap_src)
});
// EXTERNAL MODULE: external {"amd":["highcharts/highcharts"],"commonjs":["highcharts"],"commonjs2":["highcharts"],"root":["Highcharts"]}
var highcharts_commonjs_highcharts_commonjs2_highcharts_root_Highcharts_ = __webpack_require__(944);
var highcharts_commonjs_highcharts_commonjs2_highcharts_root_Highcharts_default = /*#__PURE__*/__webpack_require__.n(highcharts_commonjs_highcharts_commonjs2_highcharts_root_Highcharts_);
;// ./code/es-modules/Maps/TilesProviders/OpenStreetMap.js
/* *
* OpenStreetMap provider, used for tile map services
* */
/* *
*
* Class
*
* */
/** @internal */
class OpenStreetMap {
constructor() {
/* *
*
* Properties
*
* */
this.defaultCredits = ('Map data ©2023' +
' <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>');
this.initialProjectionName = 'WebMercator';
this.subdomains = ['a', 'b', 'c'];
this.themes = {
Standard: {
url: 'https://tile.openstreetmap.org/{zoom}/{x}/{y}.png',
minZoom: 0,
maxZoom: 19
},
Hot: {
url: 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
minZoom: 0,
maxZoom: 19
},
OpenTopoMap: {
url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
minZoom: 0,
maxZoom: 17,
credits: `Map data: © <a href="https://www.openstreetmap.org/copyright">
OpenStreetMap</a> contributors, <a href="https://viewfinderpanoramas.org">SRTM</a>
| Map style: © <a href="https://opentopomap.org">OpenTopoMap</a>
(<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)`
}
};
}
}
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const TilesProviders_OpenStreetMap = (OpenStreetMap);
;// ./code/es-modules/Maps/TilesProviders/Stamen.js
/* *
* Stamen provider, used for tile map services
* */
/* *
*
* Class
*
* */
/** @internal */
class Stamen {
constructor() {
/* *
*
* Properties
*
* */
this.defaultCredits = ('© Map tiles by <a href="https://stamen.com">Stamen Design</a>,' +
' under <a href="https://creativecommons.org/licenses/by/3.0">CC BY' +
' 3.0</a>. Data by <a href="https://openstreetmap.org">OpenStreetMap' +
'</a>, under <a href="https://www.openstreetmap.org/copyright">ODbL</a>');
this.initialProjectionName = 'WebMercator';
this.subdomains = ['a', 'b', 'c', 'd'];
this.themes = {
Toner: {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.png',
minZoom: 0,
maxZoom: 20
},
TonerBackground: {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-background/{z}/{x}/{y}.png',
minZoom: 0,
maxZoom: 20
},
TonerLite: {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png',
minZoom: 0,
maxZoom: 20
},
Terrain: {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png',
minZoom: 0,
maxZoom: 18
},
TerrainBackground: {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.png',
minZoom: 0,
maxZoom: 18
},
Watercolor: {
url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png',
minZoom: 1,
maxZoom: 16,
credits: ('© Map tiles by <a href="https://stamen.com">Stamen' +
' Design</a>, under <a href="https://creativecommons.org/' +
'licenses/by/3.0">CC BY 3.0</a>. Data by <a href="https://' +
'openstreetmap.org">OpenStreetMap</a>, under <a href=' +
'"https://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>')
}
};
}
}
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const TilesProviders_Stamen = (Stamen);
;// ./code/es-modules/Maps/TilesProviders/LimaLabs.js
/* *
* LimaLabs provider, used for tile map services
* */
/* *
*
* Class
*
* */
/** @internal */
class LimaLabs {
constructor() {
/* *
*
* Properties
*
* */
this.defaultCredits = ('Map data ©2023' +
' <a href="https://maps.lima-labs.com/">LimaLabs</a>');
this.initialProjectionName = 'WebMercator';
this.requiresApiKey = true;
this.themes = {
Standard: {
url: 'https://cdn.lima-labs.com/{zoom}/{x}/{y}.png?api={apikey}',
minZoom: 0,
maxZoom: 20
}
};
}
}
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const TilesProviders_LimaLabs = (LimaLabs);
;// ./code/es-modules/Maps/TilesProviders/Thunderforest.js
/* *
* Thunderforest provider, used for tile map services
* */
/* *
*
* Class
*
* */
/** @internal */
class Thunderforest {
constructor() {
/* *
*
* Properties
*
* */
this.defaultCredits = ('Maps © <a href="https://www.thunderforest.com">Thunderforest</a>' +
', Data © <a href="https://www.openstreetmap.org/copyright">' +
'OpenStreetMap contributors</a>');
this.initialProjectionName = 'WebMercator';
this.requiresApiKey = true;
this.subdomains = ['a', 'b', 'c'];
this.themes = {
OpenCycleMap: {
url: 'https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
Transport: {
url: 'https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
TransportDark: {
url: 'https://{s}.tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
SpinalMap: {
url: 'https://{s}.tile.thunderforest.com/spinal-map/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
Landscape: {
url: 'https://{s}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
Outdoors: {
url: 'https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
Pioneer: {
url: 'https://{s}.tile.thunderforest.com/pioneer/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
MobileAtlas: {
url: 'https://{s}.tile.thunderforest.com/mobile-atlas/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
},
Neighbourhood: {
url: 'https://{s}.tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png?apikey={apikey}',
minZoom: 0,
maxZoom: 22
}
};
}
}
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const TilesProviders_Thunderforest = (Thunderforest);
;// ./code/es-modules/Maps/TilesProviders/Esri.js
/* *
* Esri provider, used for tile map services
* */
/* *
*
* Class
*
* */
/** @internal */
class Esri {
constructor() {
/* *
*
* Properties
*
* */
this.defaultCredits = ('Tiles © Esri — Source: Esri, DeLorme, NAVTEQ, USGS, ' +
' Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong),' +
' Esri (Thailand), TomTom, 2012');
this.initialProjectionName = 'WebMercator';
this.themes = {
WorldStreetMap: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 20
},
DeLorme: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Specialty/DeLorme_World_Base_Map/MapServer/tile/{z}/{y}/{x}',
minZoom: 1,
maxZoom: 11,
credits: 'Tiles © Esri — Copyright: ©2012 DeLorme'
},
WorldTopoMap: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 20,
credits: ('Tiles © Esri — Esri, DeLorme, NAVTEQ, TomTom,' +
' Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL,' +
' Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong),' +
' and the GIS User Community')
},
WorldImagery: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 20,
credits: ('Tiles © Esri — Source: Esri, i-cubed, USDA, USGS,' +
' AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP,' +
' and the GIS User Community')
},
WorldTerrain: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 13,
credits: ('Tiles © Esri — Source: USGS, Esri, TANA, DeLorme,' +
' and NPS')
},
WorldShadedRelief: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 13,
credits: 'Tiles © Esri — Source: Esri'
},
WorldPhysical: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 8,
credits: 'Tiles © Esri — Source: US National Park Service'
},
NatGeoWorldMap: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 16,
credits: ('Tiles © Esri — National Geographic, Esri,' +
' DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN,' +
' GEBCO, NOAA, iPC')
},
WorldGrayCanvas: {
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 16,
credits: 'Tiles © Esri — Esri, DeLorme, NAVTEQ'
}
};
}
}
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const TilesProviders_Esri = (Esri);
;// ./code/es-modules/Maps/TilesProviders/USGS.js
/* *
* USGS provider, used for tile map services
* */
/* *
*
* Class
*
* */
/** @internal */
class USGS {
constructor() {
/* *
*
* Properties
*
* */
this.defaultCredits = ('Tiles courtesy of the <a href="https://usgs.gov/">U.S. Geological' +
'Survey</a>');
this.initialProjectionName = 'WebMercator';
this.themes = {
USTopo: {
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 20
},
USImagery: {
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 20
},
USImageryTopo: {
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile/{z}/{y}/{x}',
minZoom: 0,
maxZoom: 20
}
};
}
}
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const TilesProviders_USGS = (USGS);
;// ./code/es-modules/Maps/TilesProviders/TilesProviderRegistry.js
/* *
*
*
* */
/* *
*
* Imports
*
* */
/* *
*
* Constants
*
* */
/** @internal */
const tilesProviderRegistry = {
Esri: TilesProviders_Esri,
LimaLabs: TilesProviders_LimaLabs,
OpenStreetMap: TilesProviders_OpenStreetMap,
Stamen: TilesProviders_Stamen,
Thunderforest: TilesProviders_Thunderforest,
USGS: TilesProviders_USGS
};
/* *
*
* Default Export
*
* */
/** @internal */
/* harmony default export */ const TilesProviderRegistry = (tilesProviderRegistry);
// EXTERNAL MODULE: external {"amd":["highcharts/highcharts","SeriesRegistry"],"commonjs":["highcharts","SeriesRegistry"],"commonjs2":["highcharts","SeriesRegistry"],"root":["Highcharts","SeriesRegistry"]}
var highcharts_SeriesRegistry_commonjs_highcharts_SeriesRegistry_commonjs2_highcharts_SeriesRegistry_root_Highcharts_SeriesRegistry_ = __webpack_require__(512);
var highcharts_SeriesRegistry_commonjs_highcharts_SeriesRegistry_commonjs2_highcharts_SeriesRegistry_root_Highcharts_SeriesRegistry_default = /*#__PURE__*/__webpack_require__.n(highcharts_SeriesRegistry_commonjs_highcharts_SeriesRegistry_commonjs2_highcharts_SeriesRegistry_root_Highcharts_SeriesRegistry_);
;// ./code/es-modules/Series/TiledWebMap/TiledWebMapSeriesDefaults.js
/* *
*
* (c) 2010-2026 Highsoft AS
* Author: Hubert Kozik, Kamil Musiałowski
*
* A commercial license may be required depending on use.
* See www.highcharts.com/license
*
*
* */
/* *
*
* API Options
*
* */
/**
* A tiledwebmap series allows user to display dynamically joined individual
* images (tiles) and join them together to create a map.
*
* @sample maps/series-tiledwebmap/simple-demo-norway
* Simple demo of data for Norway on TiledWebMap
* @sample maps/series-tiledwebmap/only-twm
* OpenStreetMap demo
*
* @extends plotOptions.map
* @excluding affectsMapView, allAreas, allowPointSelect, animation,
* animationLimit, boostBlending, boostThreshold, borderColor, borderWidth,
* clip, color, colorAxis, colorByPoint, colorIndex, colorKey, colors,
* cursor, dashStyle, dataLabels, dataParser, dataURL, dragDrop,
* enableMouseTracking, findNearestPointBy, joinBy, keys, marker,
* negativeColor, nullColor, nullInteraction, onPoint, point,
* pointDescriptionFormatter, selected, shadow, showCheckbox,
* sonification, stickyTracking, tooltip, type
* @product highmaps
* @optionparent plotOptions.tiledwebmap
*/
const TiledWebMapSeriesDefaults = {
states: {
inactive: {
enabled: false
}
}
};
/* *
*
* API options
*
* */
/**
* A `tiledwebmap` series. The [type](#series.tiledwebmap.type) option is
* not specified, it is inherited from [chart.type](#chart.type).
*
* @sample maps/series-tiledwebmap/simple-demo-norway
* Simple demo of data for Norway on TiledWebMap
* @sample maps/series-tiledwebmap/only-twm
* OpenStreetMap demo
*
* @extends series,plotOptions.tiledwebmap
* @excluding affectsMapView, allAreas, allowPointSelect, animation,
* animationLimit, boostBlending, boostThreshold, borderColor, borderWidth,
* clip, color, colorAxis, colorByPoint, colorIndex, colorKey, colors, cursor,
* dashStyle, dataLabels, dataParser, dataURL, dragDrop, enableMouseTracking,
* findNearestPointBy, joinBy, keys, marker, negativeColor, nullColor,
* nullInteraction, onPoint, point, pointDescriptionFormatter, selected, shadow,
* showCheckbox, stickyTracking, tooltip, type
* @product highmaps
* @apioption series.tiledwebmap
*/
/**
* Provider options for the series.
*
* @sample maps/series-tiledwebmap/human-anatomy
* Human Anatomy Explorer - Custom TiledWebMap Provider
*
* @since 11.1.0
* @product highmaps
* @apioption plotOptions.tiledwebmap.provider
*/
/**
* Provider type to pull data (tiles) from.
*
* @sample maps/series-tiledwebmap/basic-configuration
* Basic configuration for TiledWebMap
*
* @type {string}
* @since 11.1.0
* @product highmaps
* @apioption plotOptions.tiledwebmap.provider.type
*/
/**
* Set a tiles theme. Check the [providers documentation](https://www.highcharts.com/docs/maps/tiledwebmap)
* for official list of available themes.
*
* @sample maps/series-tiledwebmap/europe-timezones
* Imagery basemap for Europe
* @sample maps/series-tiledwebmap/hiking-trail
* Topo basemap and MapLine
*
* @type {string}
* @since 11.1.0
* @product highmaps
* @apioption plotOptions.tiledwebmap.provider.theme
*/
/**
* Subdomain required by each provider. Check the [providers documentation](https://www.highcharts.com/docs/maps/tiledwebmap)
* for available subdomains.
*
* @sample maps/series-tiledwebmap/basic-configuration
* Basic configuration for TiledWebMap
*
* @type {string}
* @since 11.1.0
* @product highmaps
* @apioption plotOptions.tiledwebmap.provider.subdomain
*/
/**
* API key for providers that require using one.
*
* @type {string}
* @since 11.1.0
* @product highmaps
* @apioption plotOptions.tiledwebmap.provider.apiKey
*/
/**
* Custom URL for providers not specified in [providers type](#series.
* tiledwebmap.provider.type). Available variables to use in URL are: `{x}`,
* `{y}`, `{z}` or `{zoom}`. Remember to always specify a projection, when
* using a custom URL.
*
* @sample maps/series-tiledwebmap/custom-url
* Custom URL with projection in TiledWebMap configuration
*
* @type {string}
* @since 11.1.0
* @product highmaps
* @apioption plotOptions.tiledwebmap.provider.url
*/
''; // Keeps doclets above detached
/* *
*
* Default Export
*
* */
/* harmony default export */ const TiledWebMap_TiledWebMapSeriesDefaults = (TiledWebMapSeriesDefaults);
;// ./code/es-modules/Shared/Utilities.js
/* *
*
* (c) 2009-2026 Highsoft AS
*
* A commercial license may be required depending on use.
* See www.highcharts.com/license
*
*
* */
const { doc, win } = (highcharts_commonjs_highcharts_commonjs2_highcharts_root_Highcharts_default());
/**
* Add an event listener.
*
* @function Highcharts.addEvent<T>
*
* @param {Highcharts.Class<T>|T} el
* The element or object to add a listener to. It can be a
* {@link HTMLDOMElement}, an {@link SVGElement} or any other object.
*
* @param {string} type
* The event type.
*
* @param {Highcharts.EventCallbackFunction<T>|Function} fn
* The function callback to execute when the event is fired.
*
* @param {Highcharts.EventOptionsObject} [options]
* Options for adding the event.
*
* @sample highcharts/members/addevent
* Use a general `render` event to draw shapes on a chart
*
* @return {Function}
* A callback function to remove the added event.
*/
function addEvent(el, type, fn, options = {}) {
// Add hcEvents to either the prototype (in case we're running addEvent on a
// class) or the instance. If hasOwnProperty('hcEvents') is false, it is
// inherited down the prototype chain, in which case we need to set the
// property on this instance (which may itself be a prototype).
const owner = typeof el === 'function' && el.prototype || el;
if (!Object.hasOwnProperty.call(owner, 'hcEvents')) {
owner.hcEvents = {};
}
const events = owner.hcEvents;
// Allow click events added to points, otherwise they will be prevented by
// the TouchPointer.pinch function after a pinch zoom operation (#7091).
if ((highcharts_commonjs_highcharts_commonjs2_highcharts_root_Highcharts_default()).Point && // Without H a dependency loop occurs
el instanceof (highcharts_commonjs_highcharts_commonjs2_highcharts_root_Highcharts_default()).Point &&
el.series &&
el.series.chart) {
el.series.chart.runTrackerClick = true;
}
// Handle DOM events
// If the browser supports passive events, add it to improve performance
// on touch events (#11353).
const addEventListener = el.addEventListener;
if (addEventListener) {
addEventListener.call(el, type, fn, (highcharts_commonjs_highcharts_commonjs2_highcharts_root_Highcharts_default()).supportsPassiveEvents ? {
passive: options.passive === void 0 ?
type.indexOf('touch') !== -1 : options.passive,
capture: false
} : false);
}
if (!events[type]) {
events[type] = [];
}
const eventObject = {
fn,
order: typeof options.order === 'number' ? options.order : Infinity
};
events[type].push(eventObject);
// Order the calls
events[type].sort((a, b) => a.order - b.order);
// Return a function that can be called to remove this event.
return function () {
removeEvent(el, type, fn);
};
}
/**
* Non-recursive method to find the lowest member of an array. `Math.min` raises
* a maximum call stack size exceeded error in Chrome when trying to apply more
* than 150.000 points. This method is slightly slower, but safe.
*
* @function Highcharts.arrayMin
*
* @param {Array<*>} data
* An array of numbers.
*
* @return {number}
* The lowest number.
*/
function arrayMin(data) {
let i = data.length, min = data[0];
while (i--) {
if (data[i] < min) {
min = data[i];
}
}
return min;
}
/**
* Non-recursive method to find the lowest member of an array. `Math.max` raises
* a maximum call stack size exceeded error in Chrome when trying to apply more
* than 150.000 points. This method is slightly slower, but safe.
*
* @function Highcharts.arrayMax
*
* @param {Array<*>} data
* An array of numbers.
*
* @return {number}
* The highest number.
*/
function arrayMax(data) {
let i = data.length, max = data[0];
while (i--) {
if (data[i] > max) {
max = data[i];
}
}
return max;
}
/**
* Set or get an attribute or an object of attributes.
*
* To use as a setter, pass a key and a value, or let the second argument be a
* collection of keys and values. When using a collection, passing a value of
* `null` or `undefined` will remove the attribute.
*
* To use as a getter, pass only a string as the second argument.
*
* @function Highcharts.attr
*
* @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} elem
* The DOM element to receive the attribute(s).
*
* @param {string|Highcharts.HTMLAttributes|Highcharts.SVGAttributes} [keyOrAttribs]
* The property or an object of key-value pairs.
*
* @param {number|string} [value]
* The value if a single property is set.
*
* @return {string|null|undefined}
* When used as a getter, return the value.
*/
function attr(elem, keyOrAttribs, value) {
const isGetter = isString(keyOrAttribs) && !defined(value);
let ret;
const attrSingle = (value, key) => {
// Set the value
if (defined(value)) {
elem.setAttribute(key, value);
// Get the value
}
else if (isGetter) {
ret = elem.getAttribute(key);
// IE7 and below cannot get class through getAttribute (#7850)
if (!ret && key === 'class') {
ret = elem.getAttribute(key + 'Name');
}
// Remove the value
}
else {
elem.removeAttribute(key);
}
};
// If keyOrAttribs is a string
if (isString(keyOrAttribs)) {
attrSingle(value, keyOrAttribs);
// Else if keyOrAttribs is defined, it is a hash of key/value pairs
}
else {
objectEach(keyOrAttribs, attrSingle);
}
return ret;
}
/**
* Constrain a value to within a lower and upper threshold.
*
* @internal
* @param {number} value The initial value
* @param {number} min The lower threshold
* @param {number} max The upper threshold
* @return {number} Returns a number value within min and max.
*/
function clamp(value, min, max) {
return value > min ? value < max ? value : max : min;
}
/**
* Fix JS round off float errors.
*
* @function Highcharts.correctFloat
*
* @param {number} num
* A float number to fix.
*
* @param {number} [prec=14]
* The precision.
*
* @return {number}
* The corrected float number.
*/
function correctFloat(num, prec) {
// When the number is higher than 1e14 use the number (#16275)
return num > 1e14 ? num : parseFloat(num.toPrecision(prec || 14));
}
/**
* Utility function to create an HTML element with attributes and styles.
*
* @function Highcharts.createElement
*
* @param {string} tag
* The HTML tag.
*
* @param {Highcharts.HTMLAttributes} [attribs]
* Attributes as an object of key-value pairs.
*
* @param {Highcharts.CSSObject} [styles]
* Styles as an object of key-value pairs.
*
* @param {Highcharts.HTMLDOMElement} [parent]
* The parent HTML object.
*
* @param {boolean} [nopad=false]
* If true, remove all padding, border and margin.
*
* @return {Highcharts.HTMLDOMElement}
* The created DOM element.
*/
function createElement(tag, attribs, styles, parent, nopad) {
const el = doc.createElement(tag);
if (attribs) {
extend(el, attribs);
}
if (nopad) {
css(el, { padding: '0', border: 'none', margin: '0' });
}
if (styles) {
css(el, styles);
}
if (parent) {
parent.appendChild(el);
}
return el;
}
/**
* Utility for crisping a line position to the nearest full pixel depending on
* the line width.
*
* @internal
* @param {number} value The raw pixel position
* @param {number} lineWidth The line width
* @param {boolean} [inverted] Whether the containing group is inverted.
* Crisping round numbers on the y-scale need to go
* to the other side because the coordinate system
* is flipped (scaleY is -1)
* @return {number} The pixel position to use for a crisp display
*/
function crisp(value, lineWidth = 0, inverted) {
const mod = lineWidth % 2 / 2, inverter = inverted ? -1 : 1;
return (Math.round(value * inverter - mod) + mod) * inverter;
}
/**
* Set CSS on a given element.
*
* @function Highcharts.css
*
* @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} el
* An HTML DOM element.
*
* @param {Highcharts.CSSObject} styles
* Style object with camel case property names.
*
* @return {void}
*/
function css(el, styles) {
extend(el.style, styles);
}
/**
* Check if an object is null or undefined.
*
* @function Highcharts.defined
*
* @param {*} obj
* The object to check.
*
* @return {boolean}
* False if the object is null or undefined, otherwise true.
*/
function defined(obj) {
return typeof obj !== 'undefined' && obj !== null;
}
/**
* Utility method that destroys any SVGElement instances that are properties on
* the given object. It loops all properties and invokes destroy if there is a
* destroy method. The property is then delete.
*
* @function Highcharts.destroyObjectProperties
*
* @param {*} obj
* The object to destroy properties on.
*
* @param {*} [except]
* Exception, do not destroy this property, only delete it.
*/
function destroyObjectProperties(obj, except, destructablesOnly) {
objectEach(obj, function (val, n) {
// If the object is non-null and destroy is defined
if (val !== except && val?.destroy) {
// Invoke the destroy
val.destroy();
}
// Delete the property from the object
if (val?.destroy || !destructablesOnly) {
delete obj[n];
}
});
}
/**
* Discard a HTML element
*
* @function Highcharts.discardElement
*
* @param {Highcharts.HTMLDOMElement} element
* The HTML node to discard.
*/
function discardElement(element) {
element?.parentElement?.removeChild(element);
}
// eslint-disable-next-line valid-jsdoc
/**
* Return the deep difference between two objects. It can either return the new
* properties, or optionally return the old values of new properties.
* @internal
*/
function diffObjects(newer, older, keepOlder, collectionsWithUpdate) {
const ret = {};
/**
* Recurse over a set of options and its current values, and store the
* current values in the ret object.
*/
function diff(newer, older, ret, depth) {
const keeper = keepOlder ? older : newer;
objectEach(newer, function (newerVal, key) {
if (!depth &&
collectionsWithUpdate &&
collectionsWithUpdate.indexOf(key) > -1 &&
older[key]) {
newerVal = splat(newerVal);
ret[key] = [];
// Iterate over collections like series, xAxis or yAxis and map
// the items by index.
for (let i = 0; i < Math.max(newerVal.length, older[key].length); i++) {
// Item exists in current data (#6347)
if (older[key][i]) {
// If the item is missing from the new data, we need to
// save the whole config structure. Like when
// responsively updating from a dual axis layout to a
// single axis and back (#13544).
if (newerVal[i] === void 0) {
ret[key][i] = older[key][i];
// Otherwise, proceed
}
else {
ret[key][i] = {};
diff(newerVal[i], older[key][i], ret[key][i], depth + 1);
}
}
}
}
else if (isObject(newerVal, true) &&
!newerVal.nodeType // #10044
) {
ret[key] = isArray(newerVal) ? [] : {};
diff(newerVal, older[key] || {}, ret[key], depth + 1);
// Delete empty nested objects
if (Object.keys(ret[key]).length === 0 &&
// Except colorAxis which is a special case where the empty
// object means it is enabled. Which is unfortunate and we
// should try to find a better way.
!(key === 'colorAxis' && depth === 0)) {
delete ret[key];
}
}
else if (newer[key] !== older[key] ||
// If the newer key is explicitly undefined, keep it (#10525)
(key in newer && !(key in older))) {
if (key !== '__proto__' && key !== 'constructor') {
ret[key] = keeper[key];
}
}
});
}
diff(newer, older, ret, 0);
return ret;
}
/**
* Remove the last occurrence of an item from an array.
*
* @function Highcharts.erase
*
* @param {Array<*>} arr
* The array.
*
* @param {*} item
* The item to remove.
*
* @return {void}
*/
function erase(arr, item) {
let i = arr.length;
while (i--) {
if (arr[i] === item) {
arr.splice(i, 1);
break;
}
}
}
/**
* Utility function to extend an object with the members of another.
*
* @function Highcharts.extend<T>
*
* @param {T|undefined} a
* The object to be extended.
*
* @param {Partial<T>} b
* The object to add to the first one.
*
* @return {T}
* Object a, the original object.
*/
function extend(a, b) {
let n;
if (!a) {
a = {};
}
for (n in b) { // eslint-disable-line guard-for-in
a[n] = b[n];
}
return a;
}
// eslint-disable-next-line valid-jsdoc
/**
* Extend a prototyped class by new members.
*
* @deprecated
* @function Highcharts.extendClass<T>
*
* @param {Highcharts.Class<T>} parent
* The parent prototype to inherit.
*
* @param {Highcharts.Dictionary<*>} members
* A collection of prototype members to add or override compared to the
* parent prototype.
*
* @return {Highcharts.Class<T>}
* A new prototype.
*/
function extendClass(parent, members) {
const obj = (function () { });
obj.prototype = new parent(); // eslint-disable-line new-cap
extend(obj.prototype, members);
return obj;
}
/**
* Fire an event that was registered with {@link Highcharts#addEvent}.
*
* @function Highcharts.fireEvent<T>
*
* @param {T} el
* The object to fire the event on. It can be a {@link HTMLDOMElement},
* an {@link SVGElement} or any other object.
*
* @param {string} type
* The type of event.
*
* @param {Highcharts.Dictionary<*>|Event} [eventArguments]
* Custom event arguments that are passed on as an argument to the event
* handler.
*
* @param {Highcharts.EventCallbackFunction<T>|Function} [defaultFunction]
* The default function to execute if the other listeners haven't
* returned false.
*
* @return {void}
*/
function fireEvent(el, type, eventArguments, defaultFunction) {
eventArguments = eventArguments || {};
if (doc?.createEvent &&
(el.dispatchEvent ||
(el.fireEvent &&
// Enable firing events on Highcharts instance.
el !== H))) {
const e = doc.createEvent('Events');
e.initEvent(type, true, true);
eventArguments = extend(e, eventArguments);
if (el.dispatchEvent) {
el.dispatchEvent(eventArguments);
}
else {
el.fireEvent(type, eventArguments);
}
}
else if (el.hcEvents) {
if (!eventArguments.target) {
// We're running a custom event
extend(eventArguments, {
// Attach a simple preventDefault function to skip
// default handler if called. The built-in
// defaultPrevented property is not overwritable (#5112)
preventDefault: function () {
eventArguments.defaultPrevented = true;
},
// Setting target to native events fails with clicking
// the zoom-out button in Chrome.
target: el,
// If the type is not set, we're running a custom event
// (#2297). If it is set, we're running a browser event.
type: type
});
}
const events = [];
let object = el;
let multilevel = false;
// Recurse up the inheritance chain and collect hcEvents set as own
// objects on the prototypes.
while (object.hcEvents) {
if (Object.hasOwnProperty.call(object, 'hcEvents') &&
object.hcEvents[type]) {
if (events.length) {
multilevel = true;
}
events.unshift.apply(events, object.hcEvents[type]);
}
object = Object.getPrototypeOf(object);
}
// For performance reasons, only sort the event handlers in case we are
// dealing with multiple levels in the prototype chain. Otherwise, the
// events are already sorted in the addEvent function.
if (multilevel) {
// Order the calls
events.sort((a, b) => a.order - b.order);
}
// Call the collected event handlers
events.forEach((obj) => {
// If the event handler returns false, prevent the default handler
// from executing
if (obj.fn.call(el, eventArguments, el) === false) {
eventArguments.preventDefault();
}
});
}
// Run the default if not prevented
if (defaultFunction && !eventArguments.defaultPrevented) {
defaultFunction.call(el, eventArguments);
}
}
/**
* Convenience function to get the align factor, used several places for
* computing positions
* @internal
*/
const getAlignFactor = (align = '') => ({
center: 0.5,
right: 1,
middle: 0.5,
bottom: 1
}[align] || 0);
/**
* Find the closest distance between two values of a two-dimensional array
* @internal
* @function Highcharts.getClosestDistance
*
* @param {Array<Array<number>>} arrays
* An array of arrays of numbers
*
* @return {number | undefined}
* The closest distance between values
*/
function getClosestDistance(arrays, onError) {
const allowNegative = !onError;
let closest, loopLength, distance, i;
arrays.forEach((xData) => {
if (xData.length > 1) {
loopLength = xData.length - 1;
for (i = loopLength; i > 0; i--) {
distance = xData[i] - xData[i - 1];
if (distance < 0 && !allowNegative) {
onError?.();
// Only one call
onError = void 0;
}
else if (distance && (typeof closest === 'undefined' || distance < closest)) {
closest = distance;
}
}
}
});
return closest;
}
/**
* Get the magnitude of a number.
*
* @function Highcharts.getMagnitude
*
* @param {number} num
* The number.
*
* @return {number}
* The magnitude, where 1-9 are magnitude 1, 10-99 magnitude 2 etc.
*/
function getMagnitude(num) {
return Math.pow(10, Math.floor(Math.log(num) / Math.LN10));
}
/**
* Returns the value of a property path on a given object.
*
* @internal
* @function getNestedProperty
*
* @param {string} path
* Path to the property, for example `custom.myValue`.
*
* @param {unknown} parent
* Instance containing the property on the specific path.
*
* @return {unknown}
* The unknown property value.
*/
function getNestedProperty(path, parent) {
const pathElements = path.split('.');
while (pathElements.length && defined(parent)) {
const pathElement = pathElements.shift();
// Filter on the key
if (typeof pathElement === 'undefined' ||
pathElement === '__proto__') {
return; // Undefined
}
if (pathElement === 'this') {
let thisProp;
if (isObject(parent)) {
thisProp = parent['@this'];
}
return thisProp ?? parent;
}
const child = parent[pathElement.replace(/[\\'"]/g, '')];
// Filter on the child
if (!defined(child) ||
typeof child === 'function' ||
typeof child.nodeType === 'number' ||
child === win) {
return; // Undefined
}
// Else, proceed
parent = child;
}
return parent;
}
/**
* Get the computed CSS value for given element and property, only for numerical
* properties. For width and height, the dimension of the inner box (excluding
* padding) is returned. Used for fitting the chart within the container.
*
* @function Highcharts.getStyle
*
* @param {Highcharts.HTMLDOMElement} el
* An HTML element.
*
* @param {string} prop
* The property name.
*
* @param {boolean} [toInt=true]
* Parse to integer.
*
* @return {number|string|undefined}
* The style value.
*/
function getStyle(el, prop, toInt) {
let style;
// For width and height, return the actual inner pixel size (#4913)
if (prop === 'width') {
let offsetWidth = Math.min(el.offsetWidth, el.scrollWidth);
// In flex boxes, we need to use getBoundingClientRect and floor it,
// because scrollWidth doesn't support subpixel precision (#6427) ...
const boundingClientRectWidth = el.getBoundingClientRect?.().width;
// ...unless if the containing div or its parents are transform-scaled
// down, in which case the boundingClientRect can't be used as it is
// also scaled down (#9871, #10498).
if (boundingClientRectWidth < offsetWidth &&
boundingClientRectWidth >= offsetWidth - 1) {
offsetWidth = Math.floor(boundingClientRectWidth);
}
return Math.max(0, // #8377
(offsetWidth -
(getStyle(el, 'padding-left', true) || 0) -
(getStyle(el, 'padding-right', true) || 0)));
}
if (prop === 'height') {
return Math.max(0, // #8377
(Math.min(el.offsetHeight, el.scrollHeight) -
(getStyle(el, 'padding-top', true) || 0) -
(getStyle(el, 'padding-bottom', true) || 0)));
}
// Otherwise, get the computed style
const css = win.getComputedStyle(el, void 0); // eslint-disable-line no-undefined
if (css) {
style = css.getPropertyValue(prop);
if (pick(toInt, prop !== 'opacity')) {
style = pInt(style);
}
}
return style;
}
/**
* Return the value of the first element in the array that satisfies the
* provided testing function.
*
* @function Highcharts.find<T>
*
* @param {Array<T>} arr
* The array to test.
*
* @param {Function} callback
* The callback function. The function receives the item as the first
* argument. Return `true` if this item satisfies the condition.
*
* @return {T|undefined}
* The value of the element.
*/
const find = Array.prototype.find ?
function (arr, callback) {
return arr.find(callback);
} :
// Legacy implementation. PhantomJS, IE <= 11 etc. #7223.
function (arr, callback) {
let i;
const length = arr.length;
for (i = 0; i < length; i++) {
if (callback(arr[i], i)) { // eslint-disable-line node/callback-return
return arr[i];
}
}
};
/**
* Internal clear timeout. The function checks that the `id` was not removed
* (e.g. by `chart.destroy()`). For the details see
* [issue #7901](https://github.com/highcharts/highcharts/issues/7901).
*
* @internal
*
* @function Highcharts.clearTimeout
*
* @param {number|undefined} id
* Id of a timeout.
*/
function internalClearTimeout(id) {
if (defined(id)) {
clearTimeout(id);
}
}
/**
* Utility function to check if an Object is a HTML Element.
*
* @function Highcharts.isDOMElement
*
* @param {*} obj
* The item to check.
*
* @return {boolean}
* True if the argument is a HTML Element.
*/
function isDOMElement(obj) {
return isObject(obj) && typeof obj.nodeType === 'number';
}
/**
* Utility function to check if an Object is a class.
*
* @function Highcharts.isClass
*
* @param {object|undefined} obj
* The item to check.
*
* @return {boolean}
* True if the argument is a class.
*/
function isClass(obj) {
const c = obj?.constructor;
return !!(isObject(obj, true) &&
!isDOMElement(obj) &&
(c?.name && c.name !== 'Object'));
}
/**
* Utility function to check if an item is a number and it is finite (not NaN,
* Infinity or -Infinity).
*
* @function Highcharts.isNumber
*
* @param {*} n
* The item to check.
*
* @return {boolean}
* True if the item is a finite number
*/
function isNumber(n) {
return typeof n === 'number' && !isNaN(n) && n < Infinity && n > -Infinity;
}
/**
* Utility function to check for string type.
*
* @function Highcharts.isString
*
* @param {*} s
* The item to check.
*
* @return {boolean}
* True if the argument is a string.
*/
function isString(s) {
return typeof s === 'string';
}
/**
* Utility function to check if an item is an array.
*
* @function Highcharts.isArray
*
* @param {*} obj
* The item to check.
*
* @return {boolean}
* True if the argument is an array.
*/
function isArray(obj) {
const str = Object.prototype.toString.call(obj);
return str === '[object Array]' || str === '[object Array Iterator]';
}
/**
* Utility function to check if object is a function.
*
* @function Highcharts.isFunction
*
* @param {*} obj
* The item to check.
*
* @return {boolean}
* True if the argument is a function.
*/
function isFunction(obj) {
return typeof obj === 'function';
}
/**
* Utility function to check if an item is of type object.
*
* @function Highcharts.isObject
*
* @param {*} obj
* The item to check.
*
* @param {boolean} [strict=false]
* Also checks that the object is not an array.
*
* @return {boolean}
* True if the argument is an object.
*/
function isObject(obj, strict) {
return (!!obj &&
typeof obj === 'object' &&
(!strict || !isArray(obj))); // eslint-disable-line @typescript-eslint/no-explicit-any
}
/**
* Utility function to deep merge two or more objects and return a third object.
* If the first argument is true, the contents of the second object is copied
* into the first object. The merge function can also be used with a single
* object argument to create a deep copy of an object.
*
* @function Highcharts.merge<T>
*
* @param {true | T} extendOrSource
* Whether to extend the left-side object,
* or the first object to merge as a deep copy.
*
* @p