Skip to content

Commit

Permalink
Fix #3617. Add feature zoomTo and highlight to Identify (#3635)
Browse files Browse the repository at this point in the history
  • Loading branch information
offtherailz authored Mar 22, 2019
1 parent d14aae5 commit 1f45a3f
Show file tree
Hide file tree
Showing 31 changed files with 666 additions and 1,399 deletions.
18 changes: 17 additions & 1 deletion web/client/actions/__tests__/mapInfo-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ var {
toggleMapInfoState,
updateCenterToMarker,
TOGGLE_SHOW_COORD_EDITOR, toggleShowCoordinateEditor,
CHANGE_FORMAT, changeFormat
CHANGE_FORMAT, changeFormat,
CHANGE_PAGE, changePage,
TOGGLE_HIGHLIGHT_FEATURE, toggleHighlightFeature
} = require('../mapInfo');

describe('Test correctness of the map actions', () => {
Expand Down Expand Up @@ -119,4 +121,18 @@ describe('Test correctness of the map actions', () => {
expect(retval.type).toBe(CHANGE_FORMAT);
expect(retval.format).toBe(format);
});
it('toggleHighlightFeature', () => {
const retVal = toggleHighlightFeature(true);
expect(retVal).toExist();
expect(retVal.type).toBe(TOGGLE_HIGHLIGHT_FEATURE);
expect(toggleHighlightFeature().enabled).toBeFalsy();
expect(toggleHighlightFeature(true).enabled).toBe(true);
});
it('changePage', () => {
const retVal = changePage(true);
expect(retVal).toExist();
expect(retVal.type).toBe(CHANGE_PAGE);
expect(changePage().index).toBeFalsy();
expect(changePage(1).index).toBe(1);
});
});
23 changes: 23 additions & 0 deletions web/client/actions/mapInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ const GET_VECTOR_INFO = 'GET_VECTOR_INFO';
const NO_QUERYABLE_LAYERS = 'NO_QUERYABLE_LAYERS';
const CLEAR_WARNING = 'CLEAR_WARNING';
const FEATURE_INFO_CLICK = 'FEATURE_INFO_CLICK';
const TOGGLE_HIGHLIGHT_FEATURE = "IDENTIFY:TOGGLE_HIGHLIGHT_FEATURE";
const TOGGLE_MAPINFO_STATE = 'TOGGLE_MAPINFO_STATE';
const UPDATE_CENTER_TO_MARKER = 'UPDATE_CENTER_TO_MARKER';
const CHANGE_PAGE = 'IDENTIFY:CHANGE_PAGE';
const CLOSE_IDENTIFY = 'IDENTIFY:CLOSE_IDENTIFY';
const CHANGE_FORMAT = 'IDENTIFY:CHANGE_FORMAT';
const TOGGLE_SHOW_COORD_EDITOR = 'IDENTIFY:TOGGLE_SHOW_COORD_EDITOR';
Expand Down Expand Up @@ -193,6 +195,25 @@ function featureInfoClick(point, layer) {
};
}

function toggleHighlightFeature(enabled) {
return {
type: TOGGLE_HIGHLIGHT_FEATURE,
enabled
};
}

/**
* Changes the current page of the feature info.
* The index is relative only to valid responses, excluding invalid.(see validResponsesSelector)
* @param {number} index index of the page
*/
function changePage(index) {
return {
type: CHANGE_PAGE,
index
};
}

const closeIdentify = () => ({
type: CLOSE_IDENTIFY
});
Expand Down Expand Up @@ -231,6 +252,8 @@ module.exports = {
NO_QUERYABLE_LAYERS,
CLEAR_WARNING,
FEATURE_INFO_CLICK,
TOGGLE_HIGHLIGHT_FEATURE, toggleHighlightFeature,
CHANGE_PAGE, changePage,
TOGGLE_MAPINFO_STATE,
UPDATE_CENTER_TO_MARKER,
CLOSE_IDENTIFY,
Expand Down
6 changes: 1 addition & 5 deletions web/client/components/data/identify/IdentifyContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const React = require('react');
const {Row, Col} = require('react-bootstrap');
const Toolbar = require('../../misc/toolbar/Toolbar');
const Message = require('../../I18N/Message');
const MapInfoUtils = require('../../../utils/MapInfoUtils');
const DockablePanel = require('../../misc/panels/DockablePanel');
const GeocodeViewer = require('./GeocodeViewer');
const ResizableModal = require('../../misc/ResizableModal');
Expand Down Expand Up @@ -42,7 +41,7 @@ module.exports = props => {
position,
size,
fluid,
validator = MapInfoUtils.getValidator,
validResponses = [],
viewer = () => null,
getButtons = () => [],
showFullscreen,
Expand Down Expand Up @@ -76,9 +75,6 @@ module.exports = props => {
/* the following formula apply the converion */
lngCorrected = lngCorrected - 360 * Math.floor(lngCorrected / 360 + 0.5);
}

const validatorFormat = validator(format);
const validResponses = validatorFormat.getValidResponses(responses);
const Viewer = viewer;
const buttons = getButtons({...props, lngCorrected, validResponses, latlng});
const missingResponses = requests.length - responses.length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
const React = require('react');
const expect = require('expect');
const ReactDOM = require('react-dom');
const {defaultViewerHandlers, switchControlledDefaultViewer, defaultViewerDefaultProps} = require('../defaultViewer');
const {defaultViewerHandlers, defaultViewerDefaultProps} = require('../defaultViewer');
const TestUtils = require('react-dom/test-utils');

describe("test defaultViewer enhancers", () => {
Expand All @@ -30,32 +30,17 @@ describe("test defaultViewer enhancers", () => {
expect(testComponent.innerHTML).toBe('text/plain');
});

it('test switchControlledDefaultViewer', () => {
const Component = switchControlledDefaultViewer(({index = 0, setIndex = () => {}}) => <div id="test-component" onClick={() => setIndex(2)}>{index}</div>);
ReactDOM.render(<Component header />, document.getElementById("container"));
let testComponent = document.getElementById('test-component');
expect(testComponent.innerHTML).toBe('0');
TestUtils.Simulate.click(testComponent);
expect(testComponent.innerHTML).toBe('2');

ReactDOM.render(<Component />, document.getElementById("container"));
testComponent = document.getElementById('test-component');
expect(testComponent.innerHTML).toBe('0');
TestUtils.Simulate.click(testComponent);
expect(testComponent.innerHTML).toBe('0');
});

it('test defaultViewerHanlders onNext', done => {
const Component = defaultViewerHandlers(({onNext = () => {}, index = 0}) =>
<span>
<div id="test-component-next" onClick={() => onNext()}>{index}</div>
</span>
);

ReactDOM.render(<Component index={0} setIndex={index => {
ReactDOM.render(<Component validResponses={[{dummy: "dummy response"}]} index={0} setIndex={index => {
expect(index).toBe(0);
done();
}} validator={() => ({getValidResponses: (responses) => responses})} format="text/plain" responses={[{}]}/>, document.getElementById("container"));
}} />, document.getElementById("container"));

const testComponentNext = document.getElementById('test-component-next');
TestUtils.Simulate.click(testComponentNext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
const React = require('react');
const expect = require('expect');
const ReactDOM = require('react-dom');
const {identifyLifecycle, switchControlledIdentify} = require('../identify');
const {identifyLifecycle} = require('../identify');
const TestUtils = require('react-dom/test-utils');

describe("test identify enhancers", () => {
Expand All @@ -23,28 +23,7 @@ describe("test identify enhancers", () => {
setTimeout(done);
});

it('test switchControlledIdentify', () => {
const Component = switchControlledIdentify(({index = 0, setIndex = () => {}}) => <div id="test-component" onClick={() => setIndex(2)}>{index}</div>);
ReactDOM.render(<Component />, document.getElementById("container"));
let testComponent = document.getElementById('test-component');
expect(testComponent.innerHTML).toBe('0');
TestUtils.Simulate.click(testComponent);
expect(testComponent.innerHTML).toBe('2');

ReactDOM.render(<Component viewerOptions={{header: true}}/>, document.getElementById("container"));
testComponent = document.getElementById('test-component');
expect(testComponent.innerHTML).toBe('0');
TestUtils.Simulate.click(testComponent);
expect(testComponent.innerHTML).toBe('0');

ReactDOM.render(<Component viewerOptions={{}}/>, document.getElementById("container"));
testComponent = document.getElementById('test-component');
expect(testComponent.innerHTML).toBe('0');
TestUtils.Simulate.click(testComponent);
expect(testComponent.innerHTML).toBe('2');
});

it('test switchControlledIdentify component changes mousepointer on enable / disable', () => {
it('test identifyLifecycle component changes mousepointer on enable / disable', () => {

const Component = identifyLifecycle(() => <div id="test-component"></div>);

Expand All @@ -70,7 +49,7 @@ describe("test identify enhancers", () => {
expect(spyMousePointer.calls.length).toEqual(2);
});

it("test switchControlledIdentify component doesn't need reset current index when requests are the same", () => {
it("test identifyLifecycle component doesn't need reset current index when requests are the same", () => {
const Component = identifyLifecycle(() => <div id="test-component"></div>);
const testHandlers = {
setIndex: () => {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright 2019, 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.
*/
const React = require('react');
const ReactDOM = require('react-dom');
const {createSink} = require('recompose');
const expect = require('expect');
const zoomToFeatureHandler = require('../zoomToFeatureHandler');

const SAMPLE_FEATURES = [
{
"type": "Feature",
"id": "",
"geometry": null,
"properties": {
"GRAY_INDEX": 336
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2.4609375,
55.27911529201561
],
[
3.515625,
45.1510532655634
],
[
12.83203125,
45.089035564831036
],
[
12.568359375,
55.3791104480105
],
[
2.4609375,
55.27911529201561
]
]
]
}
}
];

describe('zoomToFeatureHandler enhancer', () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});
afterEach((done) => {
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
document.body.innerHTML = '';
setTimeout(done);
});
it('zoomToFeatureHandler rendering with defaults', (done) => {
const Sink = zoomToFeatureHandler(createSink( props => {
expect(props.zoomToFeature).toExist();
done();
}));
ReactDOM.render(<Sink />, document.getElementById("container"));
});
it('callback to zoomToExtent', () => {
const actions = {
zoomToExtent: () => {}
};
const spy = expect.spyOn(actions, 'zoomToExtent');

const Sink = zoomToFeatureHandler(createSink( props => {
props.zoomToFeature();
}));
ReactDOM.render(<Sink
zoomToExtent={actions.zoomToExtent}
currentFeatureCrs="EPSG:3857"
currentFeature={SAMPLE_FEATURES}/>, document.getElementById("container"));
expect(spy).toHaveBeenCalled();
expect(spy.calls[0].arguments[0]).toBeAn(Array);
expect(spy.calls[0].arguments[1]).toBe("EPSG:3857");
});
it('not zoom if at least one geometry is not available', () => {
const actions = {
zoomToExtent: () => { }
};
const spy = expect.spyOn(actions, 'zoomToExtent');

const Sink = zoomToFeatureHandler(createSink(props => {
props.zoomToFeature();
}));
ReactDOM.render(<Sink
zoomToExtent={actions.zoomToExtent}
currentFeatureCrs="EPSG:3857"
currentFeature={[SAMPLE_FEATURES[0]]} />, document.getElementById("container"));
expect(spy).toNotHaveBeenCalled();

});
});
19 changes: 3 additions & 16 deletions web/client/components/data/identify/enhancers/defaultViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/

const {withState, withHandlers, branch, defaultProps} = require('recompose');
const {withHandlers, defaultProps} = require('recompose');
const MapInfoUtils = require('../../../../utils/MapInfoUtils');

/**
Expand All @@ -17,27 +17,15 @@ const MapInfoUtils = require('../../../../utils/MapInfoUtils');
* @class
*/
const defaultViewerHandlers = withHandlers({
onNext: ({index = 0, setIndex = () => {}, responses, format, validator}) => () => {
setIndex(Math.min(validator(format).getValidResponses(responses).length - 1, index + 1));
onNext: ({index = 0, setIndex = () => {}, validResponses = []}) => () => {
setIndex(Math.min(validResponses.length - 1, index + 1));
},
onPrevious: ({index, setIndex = () => {}}) => () => {
setIndex(Math.max(0, index - 1));
}
});


/**
* Enhancer to enable set index only if Component has header
* @memberof enhancers.switchControlledDefaultViewer
* @class
*/
const switchControlledDefaultViewer = branch(
({header}) => header,
withState(
'index', 'setIndex', 0
)
);

/**
* Set the default props of DefaultViewer
* @memberof enhancers.defaultViewerDefaultProps
Expand All @@ -50,6 +38,5 @@ const defaultViewerDefaultProps = defaultProps({

module.exports = {
defaultViewerHandlers,
switchControlledDefaultViewer,
defaultViewerDefaultProps
};
17 changes: 2 additions & 15 deletions web/client/components/data/identify/enhancers/identify.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,10 @@
* LICENSE file in the root directory of this source tree.
*/

const {lifecycle, withHandlers, branch, withState, compose} = require('recompose');
const {lifecycle, withHandlers, compose} = require('recompose');
const {set} = require('../../../../utils/ImmutableUtils');
const {isEqual, isNil} = require('lodash');

/**
* Enhancer to enable set index only if Component has not header in viewerOptions props
* @memberof enhancers.switchControlledIdentify
* @class
*/
const switchControlledIdentify = branch(
({viewerOptions}) => !viewerOptions || (viewerOptions && !viewerOptions.header),
withState(
'index', 'setIndex', 0
)
);

/**
* Enhancer to enable set index only if Component has header
* - needsRefresh: check if current selected point if different of next point, if so return true
Expand Down Expand Up @@ -118,6 +106,5 @@ const identifyLifecycle = compose(
);

module.exports = {
identifyLifecycle,
switchControlledIdentify
identifyLifecycle
};
Loading

0 comments on commit 1f45a3f

Please sign in to comment.