Map.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /* *
  2. *
  3. * (c) 2010-2020 Torstein Honsi
  4. *
  5. * License: www.highcharts.com/license
  6. *
  7. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  8. *
  9. * */
  10. 'use strict';
  11. import Chart from '../Core/Chart/Chart.js';
  12. import H from '../Core/Globals.js';
  13. import O from '../Core/Options.js';
  14. var defaultOptions = O.defaultOptions;
  15. import SVGRenderer from '../Core/Renderer/SVG/SVGRenderer.js';
  16. import U from '../Core/Utilities.js';
  17. var extend = U.extend, getOptions = U.getOptions, merge = U.merge, pick = U.pick;
  18. import '../Core/Options.js';
  19. import '../Core/Chart/Chart.js';
  20. var Renderer = H.Renderer, VMLRenderer = H.VMLRenderer;
  21. // Add language
  22. extend(defaultOptions.lang, {
  23. zoomIn: 'Zoom in',
  24. zoomOut: 'Zoom out'
  25. });
  26. // Set the default map navigation options
  27. /**
  28. * @product highmaps
  29. * @optionparent mapNavigation
  30. */
  31. defaultOptions.mapNavigation = {
  32. /**
  33. * General options for the map navigation buttons. Individual options
  34. * can be given from the [mapNavigation.buttons](#mapNavigation.buttons)
  35. * option set.
  36. *
  37. * @sample {highmaps} maps/mapnavigation/button-theme/
  38. * Theming the navigation buttons
  39. */
  40. buttonOptions: {
  41. /**
  42. * What box to align the buttons to. Possible values are `plotBox`
  43. * and `spacingBox`.
  44. *
  45. * @type {Highcharts.ButtonRelativeToValue}
  46. */
  47. alignTo: 'plotBox',
  48. /**
  49. * The alignment of the navigation buttons.
  50. *
  51. * @type {Highcharts.AlignValue}
  52. */
  53. align: 'left',
  54. /**
  55. * The vertical alignment of the buttons. Individual alignment can
  56. * be adjusted by each button's `y` offset.
  57. *
  58. * @type {Highcharts.VerticalAlignValue}
  59. */
  60. verticalAlign: 'top',
  61. /**
  62. * The X offset of the buttons relative to its `align` setting.
  63. */
  64. x: 0,
  65. /**
  66. * The width of the map navigation buttons.
  67. */
  68. width: 18,
  69. /**
  70. * The pixel height of the map navigation buttons.
  71. */
  72. height: 18,
  73. /**
  74. * Padding for the navigation buttons.
  75. *
  76. * @since 5.0.0
  77. */
  78. padding: 5,
  79. /**
  80. * Text styles for the map navigation buttons.
  81. *
  82. * @type {Highcharts.CSSObject}
  83. * @default {"fontSize": "15px", "fontWeight": "bold"}
  84. */
  85. style: {
  86. /** @ignore */
  87. fontSize: '15px',
  88. /** @ignore */
  89. fontWeight: 'bold'
  90. },
  91. /**
  92. * A configuration object for the button theme. The object accepts
  93. * SVG properties like `stroke-width`, `stroke` and `fill`. Tri-state
  94. * button styles are supported by the `states.hover` and `states.select`
  95. * objects.
  96. *
  97. * @sample {highmaps} maps/mapnavigation/button-theme/
  98. * Themed navigation buttons
  99. *
  100. * @type {Highcharts.SVGAttributes}
  101. * @default {"stroke-width": 1, "text-align": "center"}
  102. */
  103. theme: {
  104. /** @ignore */
  105. 'stroke-width': 1,
  106. /** @ignore */
  107. 'text-align': 'center'
  108. }
  109. },
  110. /**
  111. * The individual buttons for the map navigation. This usually includes
  112. * the zoom in and zoom out buttons. Properties for each button is
  113. * inherited from
  114. * [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
  115. * individual options can be overridden. But default, the `onclick`, `text`
  116. * and `y` options are individual.
  117. */
  118. buttons: {
  119. /**
  120. * Options for the zoom in button. Properties for the zoom in and zoom
  121. * out buttons are inherited from
  122. * [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
  123. * individual options can be overridden. By default, the `onclick`,
  124. * `text` and `y` options are individual.
  125. *
  126. * @extends mapNavigation.buttonOptions
  127. */
  128. zoomIn: {
  129. // eslint-disable-next-line valid-jsdoc
  130. /**
  131. * Click handler for the button.
  132. *
  133. * @type {Function}
  134. * @default function () { this.mapZoom(0.5); }
  135. */
  136. onclick: function () {
  137. this.mapZoom(0.5);
  138. },
  139. /**
  140. * The text for the button. The tooltip (title) is a language option
  141. * given by [lang.zoomIn](#lang.zoomIn).
  142. */
  143. text: '+',
  144. /**
  145. * The position of the zoomIn button relative to the vertical
  146. * alignment.
  147. */
  148. y: 0
  149. },
  150. /**
  151. * Options for the zoom out button. Properties for the zoom in and
  152. * zoom out buttons are inherited from
  153. * [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
  154. * individual options can be overridden. By default, the `onclick`,
  155. * `text` and `y` options are individual.
  156. *
  157. * @extends mapNavigation.buttonOptions
  158. */
  159. zoomOut: {
  160. // eslint-disable-next-line valid-jsdoc
  161. /**
  162. * Click handler for the button.
  163. *
  164. * @type {Function}
  165. * @default function () { this.mapZoom(2); }
  166. */
  167. onclick: function () {
  168. this.mapZoom(2);
  169. },
  170. /**
  171. * The text for the button. The tooltip (title) is a language option
  172. * given by [lang.zoomOut](#lang.zoomIn).
  173. */
  174. text: '-',
  175. /**
  176. * The position of the zoomOut button relative to the vertical
  177. * alignment.
  178. */
  179. y: 28
  180. }
  181. },
  182. /**
  183. * Whether to enable navigation buttons. By default it inherits the
  184. * [enabled](#mapNavigation.enabled) setting.
  185. *
  186. * @type {boolean}
  187. * @apioption mapNavigation.enableButtons
  188. */
  189. /**
  190. * Whether to enable map navigation. The default is not to enable
  191. * navigation, as many choropleth maps are simple and don't need it.
  192. * Additionally, when touch zoom and mousewheel zoom is enabled, it breaks
  193. * the default behaviour of these interactions in the website, and the
  194. * implementer should be aware of this.
  195. *
  196. * Individual interactions can be enabled separately, namely buttons,
  197. * multitouch zoom, double click zoom, double click zoom to element and
  198. * mousewheel zoom.
  199. *
  200. * @type {boolean}
  201. * @default false
  202. * @apioption mapNavigation.enabled
  203. */
  204. /**
  205. * Enables zooming in on an area on double clicking in the map. By default
  206. * it inherits the [enabled](#mapNavigation.enabled) setting.
  207. *
  208. * @type {boolean}
  209. * @apioption mapNavigation.enableDoubleClickZoom
  210. */
  211. /**
  212. * Whether to zoom in on an area when that area is double clicked.
  213. *
  214. * @sample {highmaps} maps/mapnavigation/doubleclickzoomto/
  215. * Enable double click zoom to
  216. *
  217. * @type {boolean}
  218. * @default false
  219. * @apioption mapNavigation.enableDoubleClickZoomTo
  220. */
  221. /**
  222. * Enables zooming by mouse wheel. By default it inherits the [enabled](
  223. * #mapNavigation.enabled) setting.
  224. *
  225. * @type {boolean}
  226. * @apioption mapNavigation.enableMouseWheelZoom
  227. */
  228. /**
  229. * Whether to enable multitouch zooming. Note that if the chart covers the
  230. * viewport, this prevents the user from using multitouch and touchdrag on
  231. * the web page, so you should make sure the user is not trapped inside the
  232. * chart. By default it inherits the [enabled](#mapNavigation.enabled)
  233. * setting.
  234. *
  235. * @type {boolean}
  236. * @apioption mapNavigation.enableTouchZoom
  237. */
  238. /**
  239. * Sensitivity of mouse wheel or trackpad scrolling. 1 is no sensitivity,
  240. * while with 2, one mousewheel delta will zoom in 50%.
  241. *
  242. * @since 4.2.4
  243. */
  244. mouseWheelSensitivity: 1.1
  245. // enabled: false,
  246. // enableButtons: null, // inherit from enabled
  247. // enableTouchZoom: null, // inherit from enabled
  248. // enableDoubleClickZoom: null, // inherit from enabled
  249. // enableDoubleClickZoomTo: false
  250. // enableMouseWheelZoom: null, // inherit from enabled
  251. };
  252. /* eslint-disable valid-jsdoc */
  253. /**
  254. * Utility for reading SVG paths directly.
  255. *
  256. * @requires modules/map
  257. *
  258. * @function Highcharts.splitPath
  259. *
  260. * @param {string|Array<string|number>} path
  261. *
  262. * @return {Highcharts.SVGPathArray}
  263. */
  264. H.splitPath = function (path) {
  265. var arr;
  266. if (typeof path === 'string') {
  267. path = path
  268. // Move letters apart
  269. .replace(/([A-Za-z])/g, ' $1 ')
  270. // Trim
  271. .replace(/^\s*/, '').replace(/\s*$/, '');
  272. // Split on spaces and commas. The semicolon is bogus, designed to
  273. // circumvent string replacement in the pre-v7 assembler that built
  274. // specific styled mode files.
  275. var split = path.split(/[ ,;]+/);
  276. arr = split.map(function (item) {
  277. if (!/[A-za-z]/.test(item)) {
  278. return parseFloat(item);
  279. }
  280. return item;
  281. });
  282. }
  283. else {
  284. arr = path;
  285. }
  286. return SVGRenderer.prototype.pathToSegments(arr);
  287. };
  288. /**
  289. * Contains all loaded map data for Highmaps.
  290. *
  291. * @requires modules/map
  292. *
  293. * @name Highcharts.maps
  294. * @type {Highcharts.Dictionary<*>}
  295. */
  296. H.maps = {};
  297. /**
  298. * Create symbols for the zoom buttons
  299. * @private
  300. */
  301. function selectiveRoundedRect(x, y, w, h, rTopLeft, rTopRight, rBottomRight, rBottomLeft) {
  302. return [
  303. ['M', x + rTopLeft, y],
  304. // top side
  305. ['L', x + w - rTopRight, y],
  306. // top right corner
  307. ['C', x + w - rTopRight / 2, y, x + w, y + rTopRight / 2, x + w, y + rTopRight],
  308. // right side
  309. ['L', x + w, y + h - rBottomRight],
  310. // bottom right corner
  311. ['C', x + w, y + h - rBottomRight / 2, x + w - rBottomRight / 2, y + h, x + w - rBottomRight, y + h],
  312. // bottom side
  313. ['L', x + rBottomLeft, y + h],
  314. // bottom left corner
  315. ['C', x + rBottomLeft / 2, y + h, x, y + h - rBottomLeft / 2, x, y + h - rBottomLeft],
  316. // left side
  317. ['L', x, y + rTopLeft],
  318. // top left corner
  319. ['C', x, y + rTopLeft / 2, x + rTopLeft / 2, y, x + rTopLeft, y],
  320. ['Z']
  321. ];
  322. }
  323. SVGRenderer.prototype.symbols.topbutton = function (x, y, w, h, options) {
  324. var r = (options && options.r) || 0;
  325. return selectiveRoundedRect(x - 1, y - 1, w, h, r, r, 0, 0);
  326. };
  327. SVGRenderer.prototype.symbols.bottombutton = function (x, y, w, h, options) {
  328. var r = (options && options.r) || 0;
  329. return selectiveRoundedRect(x - 1, y - 1, w, h, 0, 0, r, r);
  330. };
  331. // The symbol callbacks are generated on the SVGRenderer object in all browsers.
  332. // Even VML browsers need this in order to generate shapes in export. Now share
  333. // them with the VMLRenderer.
  334. if (Renderer === VMLRenderer) {
  335. ['topbutton', 'bottombutton'].forEach(function (shape) {
  336. VMLRenderer.prototype.symbols[shape] =
  337. SVGRenderer.prototype.symbols[shape];
  338. });
  339. }
  340. /**
  341. * The factory function for creating new map charts. Creates a new {@link
  342. * Highcharts.Chart|Chart} object with different default options than the basic
  343. * Chart.
  344. *
  345. * @requires modules/map
  346. *
  347. * @function Highcharts.mapChart
  348. *
  349. * @param {string|Highcharts.HTMLDOMElement} [renderTo]
  350. * The DOM element to render to, or its id.
  351. *
  352. * @param {Highcharts.Options} options
  353. * The chart options structure as described in the
  354. * [options reference](https://api.highcharts.com/highstock).
  355. *
  356. * @param {Highcharts.ChartCallbackFunction} [callback]
  357. * A function to execute when the chart object is finished loading and
  358. * rendering. In most cases the chart is built in one thread, but in
  359. * Internet Explorer version 8 or less the chart is sometimes
  360. * initialized before the document is ready, and in these cases the
  361. * chart object will not be finished synchronously. As a consequence,
  362. * code that relies on the newly built Chart object should always run in
  363. * the callback. Defining a
  364. * [chart.events.load](https://api.highcharts.com/highstock/chart.events.load)
  365. * handler is equivalent.
  366. *
  367. * @return {Highcharts.Chart}
  368. * The chart object.
  369. */
  370. H.Map = H.mapChart = function (a, b, c) {
  371. var hasRenderToArg = typeof a === 'string' || a.nodeName, options = arguments[hasRenderToArg ? 1 : 0], userOptions = options, hiddenAxis = {
  372. endOnTick: false,
  373. visible: false,
  374. minPadding: 0,
  375. maxPadding: 0,
  376. startOnTick: false
  377. }, seriesOptions, defaultCreditsOptions = getOptions().credits;
  378. /* For visual testing
  379. hiddenAxis.gridLineWidth = 1;
  380. hiddenAxis.gridZIndex = 10;
  381. hiddenAxis.tickPositions = undefined;
  382. // */
  383. // Don't merge the data
  384. seriesOptions = options.series;
  385. options.series = null;
  386. options = merge({
  387. chart: {
  388. panning: {
  389. enabled: true,
  390. type: 'xy'
  391. },
  392. type: 'map'
  393. },
  394. credits: {
  395. mapText: pick(defaultCreditsOptions.mapText, ' \u00a9 <a href="{geojson.copyrightUrl}">' +
  396. '{geojson.copyrightShort}</a>'),
  397. mapTextFull: pick(defaultCreditsOptions.mapTextFull, '{geojson.copyright}')
  398. },
  399. tooltip: {
  400. followTouchMove: false
  401. },
  402. xAxis: hiddenAxis,
  403. yAxis: merge(hiddenAxis, { reversed: true })
  404. }, options, // user's options
  405. {
  406. chart: {
  407. inverted: false,
  408. alignTicks: false
  409. }
  410. });
  411. options.series = userOptions.series = seriesOptions;
  412. return hasRenderToArg ?
  413. new Chart(a, options, c) :
  414. new Chart(options, b);
  415. };