Map.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /**
  2. * (c) 2010-2019 Torstein Honsi
  3. *
  4. * License: www.highcharts.com/license
  5. */
  6. 'use strict';
  7. import H from '../parts/Globals.js';
  8. import '../parts/Utilities.js';
  9. import '../parts/Options.js';
  10. import '../parts/Chart.js';
  11. import '../parts/SvgRenderer.js';
  12. var Chart = H.Chart,
  13. defaultOptions = H.defaultOptions,
  14. extend = H.extend,
  15. merge = H.merge,
  16. pick = H.pick,
  17. Renderer = H.Renderer,
  18. SVGRenderer = H.SVGRenderer,
  19. VMLRenderer = H.VMLRenderer;
  20. // Add language
  21. extend(defaultOptions.lang, {
  22. zoomIn: 'Zoom in',
  23. zoomOut: 'Zoom out'
  24. });
  25. // Set the default map navigation options
  26. /**
  27. * @product highmaps
  28. * @optionparent mapNavigation
  29. */
  30. defaultOptions.mapNavigation = {
  31. /**
  32. * General options for the map navigation buttons. Individual options
  33. * can be given from the [mapNavigation.buttons](#mapNavigation.buttons)
  34. * option set.
  35. *
  36. * @sample {highmaps} maps/mapnavigation/button-theme/
  37. * Theming the navigation buttons
  38. */
  39. buttonOptions: {
  40. /**
  41. * What box to align the buttons to. Possible values are `plotBox`
  42. * and `spacingBox`.
  43. *
  44. * @validvalue ["plotBox", "spacingBox"]
  45. */
  46. alignTo: 'plotBox',
  47. /**
  48. * The alignment of the navigation buttons.
  49. *
  50. * @type {Highcharts.AlignType}
  51. */
  52. align: 'left',
  53. /**
  54. * The vertical alignment of the buttons. Individual alignment can
  55. * be adjusted by each button's `y` offset.
  56. *
  57. * @type {Highcharts.VerticalAlignType}
  58. */
  59. verticalAlign: 'top',
  60. /**
  61. * The X offset of the buttons relative to its `align` setting.
  62. */
  63. x: 0,
  64. /**
  65. * The width of the map navigation buttons.
  66. */
  67. width: 18,
  68. /**
  69. * The pixel height of the map navigation buttons.
  70. */
  71. height: 18,
  72. /**
  73. * Padding for the navigation buttons.
  74. *
  75. * @since 5.0.0
  76. */
  77. padding: 5,
  78. /**
  79. * Text styles for the map navigation buttons.
  80. *
  81. * @type {Highcharts.CSSObject}
  82. * @default {"fontSize": "15px", "fontWeight": "bold"}
  83. */
  84. style: {
  85. /** @ignore */
  86. fontSize: '15px',
  87. /** @ignore */
  88. fontWeight: 'bold'
  89. },
  90. /**
  91. * A configuration object for the button theme. The object accepts
  92. * SVG properties like `stroke-width`, `stroke` and `fill`. Tri-state
  93. * button styles are supported by the `states.hover` and `states.select`
  94. * objects.
  95. *
  96. * @sample {highmaps} maps/mapnavigation/button-theme/
  97. * Themed navigation buttons
  98. *
  99. * @type {Highcharts.SVGAttributes}
  100. * @default {"stroke-width": 1, "text-align": "center"}
  101. */
  102. theme: {
  103. /** @ignore */
  104. 'stroke-width': 1,
  105. /** @ignore */
  106. 'text-align': 'center'
  107. }
  108. },
  109. /**
  110. * The individual buttons for the map navigation. This usually includes
  111. * the zoom in and zoom out buttons. Properties for each button is
  112. * inherited from
  113. * [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
  114. * individual options can be overridden. But default, the `onclick`, `text`
  115. * and `y` options are individual.
  116. */
  117. buttons: {
  118. /**
  119. * Options for the zoom in button. Properties for the zoom in and zoom
  120. * out buttons are inherited from
  121. * [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
  122. * individual options can be overridden. By default, the `onclick`,
  123. * `text` and `y` options are individual.
  124. *
  125. * @extends mapNavigation.buttonOptions
  126. */
  127. zoomIn: {
  128. /**
  129. * Click handler for the button.
  130. *
  131. * @type {Function}
  132. * @default function () { this.mapZoom(0.5); }
  133. */
  134. onclick: function () {
  135. this.mapZoom(0.5);
  136. },
  137. /**
  138. * The text for the button. The tooltip (title) is a language option
  139. * given by [lang.zoomIn](#lang.zoomIn).
  140. */
  141. text: '+',
  142. /**
  143. * The position of the zoomIn button relative to the vertical
  144. * alignment.
  145. */
  146. y: 0
  147. },
  148. /**
  149. * Options for the zoom out button. Properties for the zoom in and
  150. * zoom out buttons are inherited from
  151. * [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
  152. * individual options can be overridden. By default, the `onclick`,
  153. * `text` and `y` options are individual.
  154. *
  155. * @extends mapNavigation.buttonOptions
  156. */
  157. zoomOut: {
  158. /**
  159. * Click handler for the button.
  160. *
  161. * @type {Function}
  162. * @default function () { this.mapZoom(2); }
  163. */
  164. onclick: function () {
  165. this.mapZoom(2);
  166. },
  167. /**
  168. * The text for the button. The tooltip (title) is a language option
  169. * given by [lang.zoomOut](#lang.zoomIn).
  170. */
  171. text: '-',
  172. /**
  173. * The position of the zoomOut button relative to the vertical
  174. * alignment.
  175. */
  176. y: 28
  177. }
  178. },
  179. /**
  180. * Whether to enable navigation buttons. By default it inherits the
  181. * [enabled](#mapNavigation.enabled) setting.
  182. *
  183. * @type {boolean}
  184. * @apioption mapNavigation.enableButtons
  185. */
  186. /**
  187. * Whether to enable map navigation. The default is not to enable
  188. * navigation, as many choropleth maps are simple and don't need it.
  189. * Additionally, when touch zoom and mousewheel zoom is enabled, it breaks
  190. * the default behaviour of these interactions in the website, and the
  191. * implementer should be aware of this.
  192. *
  193. * Individual interactions can be enabled separately, namely buttons,
  194. * multitouch zoom, double click zoom, double click zoom to element and
  195. * mousewheel zoom.
  196. *
  197. * @type {boolean}
  198. * @default false
  199. * @apioption mapNavigation.enabled
  200. */
  201. /**
  202. * Enables zooming in on an area on double clicking in the map. By default
  203. * it inherits the [enabled](#mapNavigation.enabled) setting.
  204. *
  205. * @type {boolean}
  206. * @apioption mapNavigation.enableDoubleClickZoom
  207. */
  208. /**
  209. * Whether to zoom in on an area when that area is double clicked.
  210. *
  211. * @sample {highmaps} maps/mapnavigation/doubleclickzoomto/
  212. * Enable double click zoom to
  213. *
  214. * @type {boolean}
  215. * @default false
  216. * @apioption mapNavigation.enableDoubleClickZoomTo
  217. */
  218. /**
  219. * Enables zooming by mouse wheel. By default it inherits the [enabled](
  220. * #mapNavigation.enabled) setting.
  221. *
  222. * @type {boolean}
  223. * @apioption mapNavigation.enableMouseWheelZoom
  224. */
  225. /**
  226. * Whether to enable multitouch zooming. Note that if the chart covers the
  227. * viewport, this prevents the user from using multitouch and touchdrag on
  228. * the web page, so you should make sure the user is not trapped inside the
  229. * chart. By default it inherits the [enabled](#mapNavigation.enabled)
  230. * setting.
  231. *
  232. * @type {boolean}
  233. * @apioption mapNavigation.enableTouchZoom
  234. */
  235. /**
  236. * Sensitivity of mouse wheel or trackpad scrolling. 1 is no sensitivity,
  237. * while with 2, one mousewheel delta will zoom in 50%.
  238. *
  239. * @since 4.2.4
  240. */
  241. mouseWheelSensitivity: 1.1
  242. // enabled: false,
  243. // enableButtons: null, // inherit from enabled
  244. // enableTouchZoom: null, // inherit from enabled
  245. // enableDoubleClickZoom: null, // inherit from enabled
  246. // enableDoubleClickZoomTo: false
  247. // enableMouseWheelZoom: null, // inherit from enabled
  248. };
  249. /**
  250. * Utility for reading SVG paths directly.
  251. *
  252. * @requires module:modules/map
  253. *
  254. * @function Highcharts.splitPath
  255. *
  256. * @param {string} path
  257. *
  258. * @return {Highcharts.SVGPathArray}
  259. */
  260. H.splitPath = function (path) {
  261. var i;
  262. // Move letters apart
  263. path = path.replace(/([A-Za-z])/g, ' $1 ');
  264. // Trim
  265. path = path.replace(/^\s*/, '').replace(/\s*$/, '');
  266. // Split on spaces and commas
  267. path = path.split(/[ ,]+/); // Extra comma to escape gulp.scripts task
  268. // Parse numbers
  269. for (i = 0; i < path.length; i++) {
  270. if (!/[a-zA-Z]/.test(path[i])) {
  271. path[i] = parseFloat(path[i]);
  272. }
  273. }
  274. return path;
  275. };
  276. /**
  277. * Contains all loaded map data for Highmaps.
  278. *
  279. * @requires module:modules/map
  280. *
  281. * @name Highcharts.maps
  282. * @type {Highcharts.Dictionary<Highcharts.MapDataObject>}
  283. */
  284. H.maps = {};
  285. // Create symbols for the zoom buttons
  286. function selectiveRoundedRect(
  287. x,
  288. y,
  289. w,
  290. h,
  291. rTopLeft,
  292. rTopRight,
  293. rBottomRight,
  294. rBottomLeft
  295. ) {
  296. return [
  297. 'M', x + rTopLeft, y,
  298. // top side
  299. 'L', x + w - rTopRight, y,
  300. // top right corner
  301. 'C', x + w - rTopRight / 2,
  302. y, x + w,
  303. y + rTopRight / 2, x + w, y + rTopRight,
  304. // right side
  305. 'L', x + w, y + h - rBottomRight,
  306. // bottom right corner
  307. 'C', x + w, y + h - rBottomRight / 2,
  308. x + w - rBottomRight / 2, y + h,
  309. x + w - rBottomRight, y + h,
  310. // bottom side
  311. 'L', x + rBottomLeft, y + h,
  312. // bottom left corner
  313. 'C', x + rBottomLeft / 2, y + h,
  314. x, y + h - rBottomLeft / 2,
  315. x, y + h - rBottomLeft,
  316. // left side
  317. 'L', x, y + rTopLeft,
  318. // top left corner
  319. 'C', x, y + rTopLeft / 2,
  320. x + rTopLeft / 2, y,
  321. x + rTopLeft, y,
  322. 'Z'
  323. ];
  324. }
  325. SVGRenderer.prototype.symbols.topbutton = function (x, y, w, h, attr) {
  326. return selectiveRoundedRect(x - 1, y - 1, w, h, attr.r, attr.r, 0, 0);
  327. };
  328. SVGRenderer.prototype.symbols.bottombutton = function (x, y, w, h, attr) {
  329. return selectiveRoundedRect(x - 1, y - 1, w, h, 0, 0, attr.r, attr.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 module: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,
  372. options = arguments[hasRenderToArg ? 1 : 0],
  373. userOptions = options,
  374. hiddenAxis = {
  375. endOnTick: false,
  376. visible: false,
  377. minPadding: 0,
  378. maxPadding: 0,
  379. startOnTick: false
  380. },
  381. seriesOptions,
  382. defaultCreditsOptions = H.getOptions().credits;
  383. /* For visual testing
  384. hiddenAxis.gridLineWidth = 1;
  385. hiddenAxis.gridZIndex = 10;
  386. hiddenAxis.tickPositions = undefined;
  387. // */
  388. // Don't merge the data
  389. seriesOptions = options.series;
  390. options.series = null;
  391. options = merge(
  392. {
  393. chart: {
  394. panning: 'xy',
  395. type: 'map'
  396. },
  397. credits: {
  398. mapText: pick(
  399. defaultCreditsOptions.mapText,
  400. ' \u00a9 <a href="{geojson.copyrightUrl}">' +
  401. '{geojson.copyrightShort}</a>'
  402. ),
  403. mapTextFull: pick(
  404. defaultCreditsOptions.mapTextFull,
  405. '{geojson.copyright}'
  406. )
  407. },
  408. tooltip: {
  409. followTouchMove: false
  410. },
  411. xAxis: hiddenAxis,
  412. yAxis: merge(hiddenAxis, { reversed: true })
  413. },
  414. options, // user's options
  415. { // forced options
  416. chart: {
  417. inverted: false,
  418. alignTicks: false
  419. }
  420. }
  421. );
  422. options.series = userOptions.series = seriesOptions;
  423. return hasRenderToArg ?
  424. new Chart(a, options, c) :
  425. new Chart(options, b);
  426. };