123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /* *
- *
- * (c) 2010-2021 Torstein Honsi
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- 'use strict';
- import Chart from '../Core/Chart/Chart.js';
- import H from '../Core/Globals.js';
- var doc = H.doc;
- import U from '../Core/Utilities.js';
- var addEvent = U.addEvent, extend = U.extend, merge = U.merge, objectEach = U.objectEach, pick = U.pick;
- import './MapNavigationOptionsDefault.js';
- /* eslint-disable no-invalid-this, valid-jsdoc */
- /**
- * @private
- */
- function stopEvent(e) {
- if (e) {
- if (e.preventDefault) {
- e.preventDefault();
- }
- if (e.stopPropagation) {
- e.stopPropagation();
- }
- e.cancelBubble = true;
- }
- }
- /**
- * The MapNavigation handles buttons for navigation in addition to mousewheel
- * and doubleclick handlers for chart zooming.
- *
- * @private
- * @class
- * @name MapNavigation
- *
- * @param {Highcharts.Chart} chart
- * The Chart instance.
- */
- function MapNavigation(chart) {
- this.init(chart);
- }
- /**
- * Initialize function.
- *
- * @function MapNavigation#init
- *
- * @param {Highcharts.Chart} chart
- * The Chart instance.
- *
- * @return {void}
- */
- MapNavigation.prototype.init = function (chart) {
- this.chart = chart;
- chart.mapNavButtons = [];
- };
- /**
- * Update the map navigation with new options. Calling this is the same as
- * calling `chart.update({ mapNavigation: {} })`.
- *
- * @function MapNavigation#update
- *
- * @param {Highcharts.MapNavigationOptions} [options]
- * New options for the map navigation.
- *
- * @return {void}
- */
- MapNavigation.prototype.update = function (options) {
- var chart = this.chart, o = chart.options.mapNavigation, attr, states, hoverStates, selectStates, outerHandler = function (e) {
- this.handler.call(chart, e);
- stopEvent(e); // Stop default click event (#4444)
- }, mapNavButtons = chart.mapNavButtons;
- // Merge in new options in case of update, and register back to chart
- // options.
- if (options) {
- o = chart.options.mapNavigation =
- merge(chart.options.mapNavigation, options);
- }
- // Destroy buttons in case of dynamic update
- while (mapNavButtons.length) {
- mapNavButtons.pop().destroy();
- }
- if (pick(o.enableButtons, o.enabled) && !chart.renderer.forExport) {
- objectEach(o.buttons, function (buttonOptions, n) {
- buttonOptions = merge(o.buttonOptions, buttonOptions);
- // Presentational
- if (!chart.styledMode && buttonOptions.theme) {
- attr = buttonOptions.theme;
- attr.style = merge(buttonOptions.theme.style, buttonOptions.style // #3203
- );
- states = attr.states;
- hoverStates = states && states.hover;
- selectStates = states && states.select;
- delete attr.states;
- }
- var button = chart.renderer
- .button(buttonOptions.text || '', 0, 0, outerHandler, attr, hoverStates, selectStates, void 0, n === 'zoomIn' ? 'topbutton' : 'bottombutton')
- .addClass('highcharts-map-navigation highcharts-' + {
- zoomIn: 'zoom-in',
- zoomOut: 'zoom-out'
- }[n])
- .attr({
- width: buttonOptions.width,
- height: buttonOptions.height,
- title: chart.options.lang[n],
- padding: buttonOptions.padding,
- zIndex: 5
- })
- .add();
- button.handler = buttonOptions.onclick;
- // Stop double click event (#4444)
- addEvent(button.element, 'dblclick', stopEvent);
- mapNavButtons.push(button);
- extend(buttonOptions, {
- width: button.width,
- height: 2 * button.height
- });
- if (!chart.hasLoaded) {
- // Align it after the plotBox is known (#12776)
- var unbind_1 = addEvent(chart, 'load', function () {
- // #15406: Make sure button hasnt been destroyed
- if (button.element) {
- button.align(buttonOptions, false, buttonOptions.alignTo);
- }
- unbind_1();
- });
- }
- else {
- button.align(buttonOptions, false, buttonOptions.alignTo);
- }
- });
- }
- this.updateEvents(o);
- };
- /**
- * Update events, called internally from the update function. Add new event
- * handlers, or unbinds events if disabled.
- *
- * @function MapNavigation#updateEvents
- *
- * @param {Highcharts.MapNavigationOptions} options
- * Options for map navigation.
- *
- * @return {void}
- */
- MapNavigation.prototype.updateEvents = function (options) {
- var chart = this.chart;
- // Add the double click event
- if (pick(options.enableDoubleClickZoom, options.enabled) ||
- options.enableDoubleClickZoomTo) {
- this.unbindDblClick = this.unbindDblClick || addEvent(chart.container, 'dblclick', function (e) {
- chart.pointer.onContainerDblClick(e);
- });
- }
- else if (this.unbindDblClick) {
- // Unbind and set unbinder to undefined
- this.unbindDblClick = this.unbindDblClick();
- }
- // Add the mousewheel event
- if (pick(options.enableMouseWheelZoom, options.enabled)) {
- this.unbindMouseWheel = this.unbindMouseWheel || addEvent(chart.container, doc.onwheel !== void 0 ? 'wheel' : // Newer Firefox
- doc.onmousewheel !== void 0 ? 'mousewheel' :
- 'DOMMouseScroll', function (e) {
- // Prevent scrolling when the pointer is over the element
- // with that class, for example anotation popup #12100.
- if (!chart.pointer.inClass(e.target, 'highcharts-no-mousewheel')) {
- chart.pointer.onContainerMouseWheel(e);
- // Issue #5011, returning false from non-jQuery event does
- // not prevent default
- stopEvent(e);
- }
- return false;
- });
- }
- else if (this.unbindMouseWheel) {
- // Unbind and set unbinder to undefined
- this.unbindMouseWheel = this.unbindMouseWheel();
- }
- };
- // Add events to the Chart object itself
- extend(Chart.prototype, /** @lends Chart.prototype */ {
- /**
- * Fit an inner box to an outer. If the inner box overflows left or right,
- * align it to the sides of the outer. If it overflows both sides, fit it
- * within the outer. This is a pattern that occurs more places in
- * Highcharts, perhaps it should be elevated to a common utility function.
- *
- * @ignore
- * @function Highcharts.Chart#fitToBox
- *
- * @param {Highcharts.BBoxObject} inner
- *
- * @param {Highcharts.BBoxObject} outer
- *
- * @return {Highcharts.BBoxObject}
- * The inner box
- */
- fitToBox: function (inner, outer) {
- [['x', 'width'], ['y', 'height']].forEach(function (dim) {
- var pos = dim[0], size = dim[1];
- if (inner[pos] + inner[size] >
- outer[pos] + outer[size]) { // right
- // the general size is greater, fit fully to outer
- if (inner[size] > outer[size]) {
- inner[size] = outer[size];
- inner[pos] = outer[pos];
- }
- else { // align right
- inner[pos] = outer[pos] +
- outer[size] - inner[size];
- }
- }
- if (inner[size] > outer[size]) {
- inner[size] = outer[size];
- }
- if (inner[pos] < outer[pos]) {
- inner[pos] = outer[pos];
- }
- });
- return inner;
- },
- /**
- * Highmaps only. Zoom in or out of the map. See also {@link Point#zoomTo}.
- * See {@link Chart#fromLatLonToPoint} for how to get the `centerX` and
- * `centerY` parameters for a geographic location.
- *
- * @function Highcharts.Chart#mapZoom
- *
- * @param {number} [howMuch]
- * How much to zoom the map. Values less than 1 zooms in. 0.5 zooms
- * in to half the current view. 2 zooms to twice the current view. If
- * omitted, the zoom is reset.
- *
- * @param {number} [centerX]
- * The X axis position to center around if available space.
- *
- * @param {number} [centerY]
- * The Y axis position to center around if available space.
- *
- * @param {number} [mouseX]
- * Fix the zoom to this position if possible. This is used for
- * example in mousewheel events, where the area under the mouse
- * should be fixed as we zoom in.
- *
- * @param {number} [mouseY]
- * Fix the zoom to this position if possible.
- *
- * @return {void}
- */
- mapZoom: function (howMuch, centerXArg, centerYArg, mouseX, mouseY, animation) {
- var chart = this, xAxis = chart.xAxis[0], xRange = xAxis.max - xAxis.min, centerX = pick(centerXArg, xAxis.min + xRange / 2), newXRange = xRange * howMuch, yAxis = chart.yAxis[0], yRange = yAxis.max - yAxis.min, centerY = pick(centerYArg, yAxis.min + yRange / 2), newYRange = yRange * howMuch, fixToX = mouseX ? ((mouseX - xAxis.pos) / xAxis.len) : 0.5, fixToY = mouseY ? ((mouseY - yAxis.pos) / yAxis.len) : 0.5, newXMin = centerX - newXRange * fixToX, newYMin = centerY - newYRange * fixToY, newExt = chart.fitToBox({
- x: newXMin,
- y: newYMin,
- width: newXRange,
- height: newYRange
- }, {
- x: xAxis.dataMin,
- y: yAxis.dataMin,
- width: xAxis.dataMax - xAxis.dataMin,
- height: yAxis.dataMax - yAxis.dataMin
- }), zoomOut = (newExt.x <= xAxis.dataMin &&
- newExt.width >=
- xAxis.dataMax - xAxis.dataMin &&
- newExt.y <= yAxis.dataMin &&
- newExt.height >= yAxis.dataMax - yAxis.dataMin);
- // When mousewheel zooming, fix the point under the mouse
- if (mouseX && xAxis.mapAxis) {
- xAxis.mapAxis.fixTo = [mouseX - xAxis.pos, centerXArg];
- }
- if (mouseY && yAxis.mapAxis) {
- yAxis.mapAxis.fixTo = [mouseY - yAxis.pos, centerYArg];
- }
- // Zoom
- if (typeof howMuch !== 'undefined' && !zoomOut) {
- xAxis.setExtremes(newExt.x, newExt.x + newExt.width, false);
- yAxis.setExtremes(newExt.y, newExt.y + newExt.height, false);
- // Reset zoom
- }
- else {
- xAxis.setExtremes(void 0, void 0, false);
- yAxis.setExtremes(void 0, void 0, false);
- }
- // Prevent zooming until this one is finished animating
- /*
- chart.holdMapZoom = true;
- setTimeout(function () {
- chart.holdMapZoom = false;
- }, 200);
- */
- /*
- delay = animation ? animation.duration || 500 : 0;
- if (delay) {
- chart.isMapZooming = true;
- setTimeout(function () {
- chart.isMapZooming = false;
- if (chart.mapZoomQueue) {
- chart.mapZoom.apply(chart, chart.mapZoomQueue);
- }
- chart.mapZoomQueue = null;
- }, delay);
- }
- */
- chart.redraw(animation);
- }
- });
- // Extend the Chart.render method to add zooming and panning
- addEvent(Chart, 'beforeRender', function () {
- // Render the plus and minus buttons. Doing this before the shapes makes
- // getBBox much quicker, at least in Chrome.
- this.mapNavigation = new MapNavigation(this);
- this.mapNavigation.update();
- });
- H.MapNavigation = MapNavigation;
|