Skip to content

Commit

Permalink
Box Selection on Map (geosolutions-it#6078)
Browse files Browse the repository at this point in the history
  • Loading branch information
AGMETEOR committed Nov 2, 2020
1 parent aebbf6e commit c99fa44
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 4 deletions.
24 changes: 24 additions & 0 deletions web/client/actions/box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2020, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

export const BOX_END = "BOX_END";
export const CHANGE_BOX_SELECTION_STATUS = "CHANGE_BOX_SELECTION_STATUS";

export function boxEnd(boxEndInfo) {
return {
type: BOX_END,
boxEndInfo
};
}

export function changeBoxSelectionStatus(status) {
return {
type: CHANGE_BOX_SELECTION_STATUS,
status
};
}
46 changes: 46 additions & 0 deletions web/client/components/map/openlayers/BoxSelectionSupport.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2020, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import {useEffect} from 'react';
import Select from 'ol/interaction/Select';
import DragBox from 'ol/interaction/DragBox';

let select;
let dragBox;

const BoxSelectionSupport = (props) => {
const { map, onBoxEnd, status } = props;

useEffect(() => {
if (status === "start") {
select = new Select();
dragBox = new DragBox({});
map.addInteraction(select);
map.addInteraction(dragBox);
} else if (status === "end") {
map.removeInteraction(select);
map.removeInteraction(dragBox);
}
}, [status]);

useEffect(() => {
if (dragBox) {

// TODO: Pass some more information from event to the onBoxEnd function
dragBox.on('boxend', () => {
onBoxEnd({
boxExtent: dragBox.getGeometry().getExtent()
});
});
}
}, [status]);

return null;
};

export default BoxSelectionSupport;
3 changes: 2 additions & 1 deletion web/client/components/map/plugins/openlayers.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = () => {
Overview: require('../openlayers/Overview').default,
ScaleBar: require('../openlayers/ScaleBar').default,
DrawSupport: require('../openlayers/DrawSupport').default,
PopupSupport: require('../openlayers/PopupSupport').default
PopupSupport: require('../openlayers/PopupSupport').default,
BoxSelectionSupport: require('../openlayers/BoxSelectionSupport').default
};
};

39 changes: 39 additions & 0 deletions web/client/epics/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const { FEATURE_INFO_CLICK, HIDE_MAPINFO_MARKER} = require('../actions/mapInfo')
const {query, QUERY, QUERY_CREATE, QUERY_RESULT, LAYER_SELECTED_FOR_SEARCH, FEATURE_TYPE_LOADED, UPDATE_QUERY, featureTypeSelected, createQuery, updateQuery, TOGGLE_SYNC_WMS, QUERY_ERROR, FEATURE_LOADING} = require('../actions/wfsquery');
const {reset, QUERY_FORM_SEARCH, loadFilter} = require('../actions/queryform');
const {zoomToExtent, CLICK_ON_MAP} = require('../actions/map');
const {BOX_END, changeBoxSelectionStatus} = require('../actions/box');
const {projectionSelector} = require('../selectors/map');


Expand Down Expand Up @@ -305,6 +306,34 @@ module.exports = {
type: "geometry"
}));
}),
handleBoxSelectionDrawEnd: (action$, store) =>
action$.ofType(UPDATE_FILTER)
.filter(({update = {}}) => update.type === 'geometry' && update.enabled)
.switchMap(() => {
return action$.ofType(BOX_END).switchMap(({boxEndInfo}) => {
const { boxExtent } = boxEndInfo;
const geom = CoordinatesUtils.getPolygonFromExtent(boxExtent);
const projection = projectionSelector(store.getState());
const currentFilter = find(getAttributeFilters(store.getState()), f => f.type === 'geometry') || {};

return currentFilter.deactivated ? Rx.Observable.empty() : Rx.Observable.of(updateFilter({
...currentFilter,
value: {
geometry: {
...geom.geometry,
projection
},
attribute: currentFilter.attribute || get(spatialFieldSelector(store.getState()), 'attribute'),
method: "Rectangle",
operation: "INTERSECTS"
}
}));
})
.takeUntil(Rx.Observable.merge(
action$.ofType(UPDATE_FILTER).filter(({update = {}}) => update.type === 'geometry' && !update.enabled),
action$.ofType(CLOSE_FEATURE_GRID, LOCATION_CHANGE)
));
}),
handleClickOnMap: (action$, store) =>
action$.ofType(UPDATE_FILTER)
.filter(({update = {}}) => update.type === 'geometry' && update.enabled)
Expand Down Expand Up @@ -561,6 +590,16 @@ module.exports = {
}
return Rx.Observable.from(actions);
}),
activateBoxSelectionTool: (action$) =>
action$.ofType(OPEN_FEATURE_GRID)
.switchMap( () => {
return Rx.Observable.of(changeBoxSelectionStatus("start"));
}),
deactivateBoxSelectionTool: (action$) =>
action$.ofType(CLOSE_FEATURE_GRID)
.switchMap( () => {
return Rx.Observable.of(changeBoxSelectionStatus("end"));
}),
/**
* intercept geometry changed events in draw support to update current
* modified geometry in featuregrid
Expand Down
4 changes: 3 additions & 1 deletion web/client/plugins/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import selector from './map/selector';
import mapReducer from "../reducers/map";
import layersReducer from "../reducers/layers";
import drawReducer from "../reducers/draw";
import boxReducer from '../reducers/box';
import highlightReducer from "../reducers/highlight";
import mapTypeReducer from "../reducers/maptype";
import additionalLayersReducer from "../reducers/additionallayers";
Expand Down Expand Up @@ -219,7 +220,7 @@ class MapPlugin extends React.Component {
zoomControl: false,
mapLoadingMessage: "map.loading",
loadingSpinner: true,
tools: ["measurement", "locate", "scalebar", "draw", "highlight", "popup"],
tools: ["measurement", "locate", "scalebar", "draw", "highlight", "popup", "box"],
options: {},
mapOptions: {},
fonts: ['FontAwesome'],
Expand Down Expand Up @@ -440,6 +441,7 @@ export default createPlugin('Map', {
map: mapReducer,
layers: layersReducer,
draw: drawReducer,
box: boxReducer,
highlight: highlightReducer,
maptype: mapTypeReducer,
additionallayers: additionalLayersReducer
Expand Down
15 changes: 14 additions & 1 deletion web/client/plugins/map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React from 'react';

import { createSelector } from 'reselect';
import { changeMapView, clickOnMap, mouseMove, mouseOut } from '../../actions/map';
import { boxEnd } from '../../actions/box';
import { removePopup } from '../../actions/mapPopups';
import { layerLoading, layerLoad, layerError } from '../../actions/layers';

Expand All @@ -25,6 +26,7 @@ import {
import { measurementSelector } from '../../selectors/measurement';
import { changeSelectionState } from '../../actions/selection';
import { changeLocateState, onLocateError } from '../../actions/locate';
import { boxSelectionStatus } from '../../selectors/box';

import {
changeDrawingStatus,
Expand Down Expand Up @@ -108,6 +110,16 @@ const pluginsCreator = (mapType, actions) => {
setCurrentStyle: setCurrentStyle
})( components.DrawSupport || Empty);

const BoxSelectionSupport = connect(
createSelector(
(state) => boxSelectionStatus(state),
(status) => ({
status
})), {
onBoxEnd: boxEnd
}
)(components.BoxSelectionSupport || Empty);

const HighlightSupport = connect((state) =>
state.highlight || {}, {updateHighlighted})( components.HighlightFeatureSupport || Empty);

Expand Down Expand Up @@ -141,7 +153,8 @@ const pluginsCreator = (mapType, actions) => {
draw: DrawSupport,
highlight: HighlightSupport,
selection: SelectionSupport,
popup: PopupSupport
popup: PopupSupport,
box: BoxSelectionSupport
}
};
});
Expand Down
3 changes: 2 additions & 1 deletion web/client/plugins/map/openlayers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ module.exports = {
DrawSupport: require('../../../components/map/openlayers/DrawSupport').default,
HighlightFeatureSupport: require('../../../components/map/openlayers/HighlightFeatureSupport').default,
SelectionSupport: require('../../../components/map/openlayers/SelectionSupport').default,
PopupSupport: require('../../../components/map/openlayers/PopupSupport').default
PopupSupport: require('../../../components/map/openlayers/PopupSupport').default,
BoxSelectionSupport: require('../../../components/map/openlayers/BoxSelectionSupport').default
};
25 changes: 25 additions & 0 deletions web/client/reducers/box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2020, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
import assign from 'object-assign';

import { CHANGE_BOX_SELECTION_STATUS } from '../actions/box';

const initialState = {
status: null
};

function box(state = initialState, action) {
switch (action.type) {
case CHANGE_BOX_SELECTION_STATUS:
return assign({}, state, {status: action.status});
default:
return state;
}
}

export default box;
9 changes: 9 additions & 0 deletions web/client/selectors/box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright 2020, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

export const boxSelectionStatus = state => state && state.box && state.box.status;

0 comments on commit c99fa44

Please sign in to comment.