Skip to content

Commit

Permalink
#9567: implement the new approach in zoom to records in table widgets…
Browse files Browse the repository at this point in the history
… + writing unit tests
  • Loading branch information
mahmoudadel54 committed Oct 25, 2023
1 parent 6b2667d commit 73d51f8
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,27 @@ describe('onMapViewChanges enhancer', () => {
expect(map.mapStateSource).toExist();
expect(map.projection).toExist();
});
it('onMapViewChanges rendering with zoomToExtentHandler', () => {
const Sink = onMapViewChanges(createSink( props => {
expect(props.eventHandlers.onMapViewChanges).toExist();
setTimeout(props.eventHandlers.onMapViewChanges("CENTER", "ZOOM", { bbox: { x: 2 } }, "SIZE", "mapStateSource", "projection", {}, "RESOLUTION", "ORINATE", () => {}));

}));
const actions = {
onMapViewChanges: () => {}
};
const spy = expect.spyOn(actions, 'onMapViewChanges');
ReactDOM.render(<Sink map={{ bbox: { x: 1, y: 1 }, test: "TEST" }} onMapViewChanges={actions.onMapViewChanges} />, document.getElementById("container"));
expect(spy).toHaveBeenCalled();
const map = spy.calls[0].arguments[0];
expect(map).toExist();
expect(map.center).toExist();
expect(map.zoom).toExist();
expect(map.bbox).toExist();
expect(map.size).toExist();
expect(map.mapStateSource).toExist();
expect(map.projection).toExist();
expect(map.zoomToExtentHandler).toExist();
});

});
5 changes: 3 additions & 2 deletions web/client/components/map/enhancers/onMapViewChanges.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { compose, withHandlers, withPropsOnChange } from 'recompose';
*/
export default compose(
withHandlers({
onMapViewChanges: ({ map = {}, onMapViewChanges = () => {}}) => (center, zoom, bbox, size, mapStateSource, projection, viewerOptions, resolution, orientate) => {
onMapViewChanges: ({ map = {}, onMapViewChanges = () => {}}) => (center, zoom, bbox, size, mapStateSource, projection, viewerOptions, resolution, orientate, zoomToExtentHandler) => {
onMapViewChanges({
...map,
center,
Expand All @@ -27,7 +27,8 @@ export default compose(
mapStateSource,
projection,
resolution,
orientate
orientate,
zoomToExtentHandler
});
}
}),
Expand Down
46 changes: 24 additions & 22 deletions web/client/components/map/openlayers/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,9 @@ class OpenlayersMap extends React.Component {
this.props.id,
this.props.projection,
undefined, // viewerOptions,
view.getResolution() // resolution
view.getResolution(), // resolution
undefined,
this.zoomToExtentHandler
);
}
};
Expand Down Expand Up @@ -561,6 +563,26 @@ class OpenlayersMap extends React.Component {
}
};

zoomToExtentHandler = (extent, { padding, crs, maxZoom: zoomLevel, duration, nearest} = {})=> {
let bounds = reprojectBbox(extent, crs, this.props.projection);
// TODO: improve this to manage all degenerated bounding boxes.
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] &&
crs === "EPSG:4326" && isArray(extent) && extent[0] === -180 && extent[1] === -90) {
bounds = this.map.getView().getProjection().getExtent();
}
let maxZoom = zoomLevel;
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] && isNil(maxZoom)) {
maxZoom = 21; // TODO: allow to this maxZoom to be customizable
}
this.map.getView().fit(bounds, {
size: this.map.getSize(),
padding: padding && [padding.top || 0, padding.right || 0, padding.bottom || 0, padding.left || 0],
maxZoom,
duration,
nearest
});
}

registerHooks = () => {
this.props.hookRegister.registerHook(mapUtils.RESOLUTIONS_HOOK, (srs) => {
return this.getResolutions(srs);
Expand Down Expand Up @@ -590,27 +612,7 @@ class OpenlayersMap extends React.Component {
this.props.hookRegister.registerHook(mapUtils.GET_COORDINATES_FROM_PIXEL_HOOK, (pixel) => {
return this.map.getCoordinateFromPixel(pixel);
});
this.props.hookRegister.registerHook(mapUtils.ZOOM_TO_EXTENT_HOOK, (extent, { padding, crs, maxZoom: zoomLevel, duration, nearest} = {}) => {
let bounds = reprojectBbox(extent, crs, this.props.projection);
// if EPSG:4326 with max extent (-180, -90, 180, 90) bounds are 0,0,0,0. In this case zoom to max extent
// TODO: improve this to manage all degenerated bounding boxes.
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] &&
crs === "EPSG:4326" && isArray(extent) && extent[0] === -180 && extent[1] === -90) {
bounds = this.map.getView().getProjection().getExtent();
}
let maxZoom = zoomLevel;
if (bounds && bounds[0] === bounds[2] && bounds[1] === bounds[3] && isNil(maxZoom)) {
maxZoom = 21; // TODO: allow to this maxZoom to be customizable
}

this.map.getView().fit(bounds, {
size: this.map.getSize(),
padding: padding && [padding.top || 0, padding.right || 0, padding.bottom || 0, padding.left || 0],
maxZoom,
duration,
nearest
});
});
this.props.hookRegister.registerHook(mapUtils.ZOOM_TO_EXTENT_HOOK, this.zoomToExtentHandler);
};
}

Expand Down
4 changes: 2 additions & 2 deletions web/client/components/map/openlayers/__tests__/Map-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ describe('OpenlayersMap', () => {
olMap.on('moveend', () => {
// The first call is triggered as soon as the map component is mounted, the second one is as a result of setZoom
expect(spy.calls.length).toEqual(2);
expect(spy.calls[1].arguments.length).toEqual(8);
expect(spy.calls[1].arguments.length).toEqual(10);
expect(normalizeFloat(spy.calls[1].arguments[0].y, 1)).toBe(43.9);
expect(normalizeFloat(spy.calls[1].arguments[0].x, 1)).toBe(10.3);
expect(spy.calls[1].arguments[1]).toBe(12);
Expand Down Expand Up @@ -563,7 +563,7 @@ describe('OpenlayersMap', () => {
olMap.on('moveend', () => {
// The first call is triggered as soon as the map component is mounted, the second one is as a result of setCenter
expect(spy.calls.length).toEqual(2);
expect(spy.calls[1].arguments.length).toEqual(8);
expect(spy.calls[1].arguments.length).toEqual(10);
expect(normalizeFloat(spy.calls[1].arguments[0].y, 1)).toBe(44);
expect(normalizeFloat(spy.calls[1].arguments[0].x, 1)).toBe(10);
expect(spy.calls[1].arguments[1]).toBe(11);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import React from 'react';
import { Col, Form, Row } from 'react-bootstrap';
import {compose, withProps} from 'recompose';
import { isGeometryType } from '../../../../../utils/ogc/WFS/base';

import AttributeTable from '../../../../data/featuregrid/AttributeTable';
import Message from '../../../../I18N/Message';
Expand All @@ -28,6 +29,7 @@ const AttributeSelector = compose(
withProps(
({ attributes = [], options = {}, layer = {}} = {}) => ({ // TODO manage hide condition
attributes: attributes
.filter(a => !isGeometryType(a))
.map( a => {
const propertyNames = options?.propertyName?.map(p => p.name);
const currPropertyName = options?.propertyName?.find(p => p.name === a.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ import MockAdapter from 'axios-mock-adapter';

import dependenciesToZoomTo from '../dependenciesToZoomTo';

import MapUtils from '../../../../utils/MapUtils';


describe('widgets dependenciesToZoomTo enhancer', () => {
let mockAxios;
const widgetsProps = [{
Expand All @@ -30,13 +27,18 @@ describe('widgets dependenciesToZoomTo enhancer', () => {
maxZoom: 21
}
},
dependenciesMap: {
mapSync: "MapID[id]"
},
geomProp: "the_geom",
mapSync: true
},
{
id: "123Map",
id: "MapID",
widgetType: "map",
maps: [{}],
maps: [{
mapStateSource: "MapID"
}],
mapSync: true
}];
beforeEach((done) => {
Expand All @@ -60,19 +62,14 @@ describe('widgets dependenciesToZoomTo enhancer', () => {
});

it('dependenciesToZoomTo triggering zoom to extent', (done) => {
let hookRegisterProps = MapUtils.createRegisterHooks();
const Sink = dependenciesToZoomTo(createSink(({
hookRegister = hookRegisterProps, widgets = widgetsProps
widgets = widgetsProps
}) => {
expect(hookRegister).toExist();
const hook = hookRegister.getHook(MapUtils.ZOOM_TO_EXTENT_HOOK);
expect(hook).toExist();
expect(widgets).toExist();
expect(widgets).toEqual(widgetsProps);
done();
}));
hookRegisterProps.registerHook(MapUtils.ZOOM_TO_EXTENT_HOOK, {hookName: MapUtils.ZOOM_TO_EXTENT_HOOK});
ReactDOM.render(<Sink hookRegister={hookRegisterProps} widgets={widgetsProps} updateProperty={(path) => {
ReactDOM.render(<Sink widgets={widgetsProps} updateProperty={(path) => {
expect(path).toBe("dependencies.extentObj");
done();
}}/>, document.getElementById("container"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,43 @@ describe('widgets tableWidget enhancer', () => {
expect(filter).toBe(someFilter);
}}/></Provider>, document.getElementById("container"));
});

it('tableWidget with gridTools including zoom icon for dashboard viewer', (done) => {
const Sink = tableWidget(createSink( props => {
expect(props).toExist();
expect(props.gridTools.length).toEqual(1);
props.gridTools[0].events.onClick(
{
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "", maxZoom: null }
);
done();
}));
ReactDOM.render( <Provider store={store}><Sink id="123456" mapSync={"true"} widgetType={"table"} isDashboardOpened={"true"} updateProperty={(id, path, value) => {
expect(path).toBe("dependencies.extentObj");
expect(id).toBe("123456");
expect(value).toEqual({
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "EPSG:4326", maxZoom: null });
}}/></Provider>, document.getElementById("container"));
const container = document.getElementById('container');
expect(container).toExist();

});
it('tableWidget with gridTools including zoom icon for mapViewer', (done) => {
const Sink = tableWidget(createSink( props => {
expect(props).toExist();
expect(props.gridTools.length).toEqual(1);
props.gridTools[0].events.onClick(
{
bbox: [-10, 0, 0, -10]
}, {}, "", { crs: "", maxZoom: null }
);
done();
}));
ReactDOM.render( <Provider store={store}><Sink id="123456" widgetType={"table"} /></Provider>, document.getElementById("container"));
const container = document.getElementById('container');
expect(container).toExist();

});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import xml2js from 'xml2js';

import { Observable } from 'rxjs';
import { mapPropsStream, compose, branch, withPropsOnChange, defaultProps } from 'recompose';
import { mapPropsStream, compose, branch, withPropsOnChange } from 'recompose';
import { isEmpty, isEqual } from 'lodash';
import { composeFilterObject } from './utils';
import wpsBounds from '../../../observables/wps/bounds';
Expand All @@ -22,9 +22,7 @@ import { createRegisterHooks, ZOOM_TO_EXTENT_HOOK } from '../../../utils/MapUtil
* @returns {object} the map with center and zoom updated
*/
export default compose(
defaultProps({
hookRegister: createRegisterHooks() // it is for zoomTo HOC
}),

branch(
({mapSync, dependencies} = {}) => {
return mapSync && (!isEmpty(dependencies.quickFilters) || !isEmpty(dependencies.filter));
Expand Down
23 changes: 16 additions & 7 deletions web/client/components/widgets/enhancers/dependenciesToZoomTo.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
/*
* Copyright 2023, 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 React, { useEffect, memo } from 'react';

const dependenciesToZoomTo = (WrappedCompoennet)=>{
const dependenciesToZoomTo = (WrappedComponent)=>{
function DependenciesToZoomTo(props) {
let tblWidgetWithExtentObj = props.widgets.find(i=>i?.dependencies?.extentObj);
const extentObj = tblWidgetWithExtentObj?.dependencies?.extentObj;
let mapWidget = props?.widgets?.find(i=>tblWidgetWithExtentObj?.dependenciesMap?.mapSync.includes(i.id));
useEffect(()=>{
if ( extentObj && extentObj ) {
const hook = props?.hookRegister?.getHook("ZOOM_TO_EXTENT_HOOK");
if (hook) {
if ( extentObj && mapWidget ) {
let connectedMap = mapWidget?.maps.find(i=>i.mapStateSource === mapWidget.id);
let zoomToExtentHandler = connectedMap?.zoomToExtentHandler;
if (zoomToExtentHandler) {
// trigger "internal" zoom to extent
hook(extentObj.extent, {
zoomToExtentHandler(extentObj.extent, {
crs: extentObj.crs, maxZoom: extentObj.maxZoom
});
// removeextentObj from state
// remove extentObj from state
props?.updateProperty(tblWidgetWithExtentObj.id, `dependencies.extentObj`, undefined);
}
}

}, [extentObj?.extent?.join(",")]);
return <WrappedCompoennet { ...props } />;
return <WrappedComponent { ...props } />;
}
return memo(DependenciesToZoomTo);
};
Expand Down
Loading

0 comments on commit 73d51f8

Please sign in to comment.