diff --git a/components/MapSelection.jsx b/components/MapSelection.jsx index 24fc6a501..5f22869c6 100644 --- a/components/MapSelection.jsx +++ b/components/MapSelection.jsx @@ -103,6 +103,7 @@ class MapSelection extends React.Component { } componentWillUnmount() { this.map.removeLayer(this.selectionLayer); + this.removeDrawInteraction(); } addDrawInteraction = () => { // cleanup old interaction @@ -111,8 +112,7 @@ class MapSelection extends React.Component { } if (this.props.geomType === "DragBox") { this.drawInteraction = new ol.interaction.DragBox({ - className: 'selection-drag-box', - condition: ol.events.condition.shiftKeyOnly + className: 'selection-drag-box' }); this.drawInteraction.on('boxend', () => { diff --git a/plugins/ZoomButtons.jsx b/plugins/ZoomButtons.jsx index 43a41c038..179075935 100644 --- a/plugins/ZoomButtons.jsx +++ b/plugins/ZoomButtons.jsx @@ -9,10 +9,13 @@ import React from 'react'; import {connect} from 'react-redux'; +import classnames from 'classnames'; import PropTypes from 'prop-types'; -import {changeZoomLevel} from '../actions/map'; +import {changeZoomLevel, zoomToExtent, zoomToPoint} from '../actions/map'; +import {setCurrentTask} from '../actions/task'; import Icon from '../components/Icon'; +import MapSelection from '../components/MapSelection'; import LocaleUtils from '../utils/LocaleUtils'; import ThemeUtils from '../utils/ThemeUtils'; @@ -26,18 +29,49 @@ import './style/Buttons.css'; class ZoomButton extends React.Component { static propTypes = { changeZoomLevel: PropTypes.func, + click: PropTypes.object, + currentTask: PropTypes.string, currentZoom: PropTypes.number, direction: PropTypes.number, + /** Enable zoom in or out by box selection. */ + enableZoomByBoxSelection: PropTypes.bool, + mapCrs: PropTypes.string, mapMargins: PropTypes.object, maxZoom: PropTypes.number, /** The position slot index of the map button, from the bottom (0: bottom slot). */ position: PropTypes.number, + setCurrentTask: PropTypes.func, theme: PropTypes.object, /** Omit the button in themes matching one of these flags. */ themeFlagBlacklist: PropTypes.arrayOf(PropTypes.string), /** Only show the button in themes matching one of these flags. */ - themeFlagWhitelist: PropTypes.arrayOf(PropTypes.string) + themeFlagWhitelist: PropTypes.arrayOf(PropTypes.string), + zoomToExtent: PropTypes.func, + zoomToPoint: PropTypes.func }; + constructor(props) { + super(props); + this.task = props.direction > 0 ? "ZoomIn" : "ZoomOut"; + } + state = { + disabled: false + }; + componentDidUpdate(prevProps) { + if (prevProps.currentZoom !== this.props.currentZoom || prevProps.maxZoom !== this.props.maxZoom) { + if (this.props.direction > 0) { + this.setState({disabled: this.props.currentZoom >= this.props.maxZoom}); + } else if (this.props.direction < 0) { + this.setState({disabled: this.props.currentZoom <= 0}); + } + } + if (this.props.currentTask === this.task && this.props.click !== prevProps.click) { + const point = this.props.click?.coordinate; + if (point) { + const zoom = Math.max(0, this.props.currentZoom + this.props.direction); + this.props.zoomToPoint(point, zoom, this.mapCrs); + } + } + } render() { if (!ThemeUtils.themFlagsAllowed(this.props.theme, this.props.themeFlagWhitelist, this.props.themeFlagBlacklist)) { return null; @@ -50,42 +84,79 @@ class ZoomButton extends React.Component { right: 'calc(1.5em + ' + right + 'px)', bottom: 'calc(' + bottom + 'px + ' + (5 + 4 * position) + 'em)' }; - let disabled = false; - if (this.props.direction > 0) { - disabled = this.props.currentZoom >= this.props.maxZoom; - } else if (this.props.direction < 0) { - disabled = this.props.currentZoom <= 0; - } const tooltip = this.props.direction > 0 ? LocaleUtils.tr("tooltip.zoomin") : LocaleUtils.tr("tooltip.zoomout"); - return ( - - ); + ), ( + this.props.currentTask === this.task ? ( + 0 ? "zoom-in" : "zoom-out"} + geomType="DragBox" + geometryChanged={(geom) => this.updateZoom(geom)} + key="MapSelection" + /> + ) : null + )]; } + buttonClicked = () => { + if (this.props.enableZoomByBoxSelection) { + this.props.setCurrentTask(this.props.currentTask === this.task ? null : this.task); + } else if (!this.state.disabled) { + this.props.changeZoomLevel(this.props.currentZoom + this.props.direction); + } + }; + updateZoom = (geom) => { + const zoomBox = geom.coordinates[0]; + if (this.props.direction > 0) { + this.props.zoomToExtent(zoomBox, this.props.mapCrs); + } else { + const center = [0.5 * (zoomBox[0] + zoomBox[2]), 0.5 * (zoomBox[1] + zoomBox[3])]; + const zoom = Math.max(0, this.props.currentZoom + this.props.direction); + this.props.zoomToPoint(center, zoom, this.props.mapCrs); + } + }; } export const ZoomInPlugin = connect((state) => ({ + click: state.map.click, + currentTask: state.task.id, currentZoom: state.map.zoom, maxZoom: state.map.resolutions.length - 1, direction: +1, + mapCrs: state.map.projection, mapMargins: state.windows.mapMargins, theme: state.theme.current }), { - changeZoomLevel: changeZoomLevel + changeZoomLevel: changeZoomLevel, + setCurrentTask: setCurrentTask, + zoomToExtent: zoomToExtent, + zoomToPoint: zoomToPoint })(ZoomButton); export const ZoomOutPlugin = connect((state) => ({ + click: state.map.click || {}, + currentTask: state.task.id, currentZoom: state.map.zoom, maxZoom: state.map.resolutions.length - 1, direction: -1, + mapCrs: state.map.projection, mapMargins: state.windows.mapMargins, theme: state.theme.current }), { - changeZoomLevel: changeZoomLevel + changeZoomLevel: changeZoomLevel, + setCurrentTask: setCurrentTask, + zoomToExtent: zoomToExtent, + zoomToPoint: zoomToPoint })(ZoomButton);