Skip to content

Commit

Permalink
Fix #2668 Increase precision of Query Panel Circle/BBox Details (#2720)
Browse files Browse the repository at this point in the history
  • Loading branch information
kappu72 authored and offtherailz committed Mar 9, 2018
1 parent ebb2dd1 commit 55bdb6e
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 43 deletions.
67 changes: 38 additions & 29 deletions web/client/components/data/query/GeometryDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ const assign = require('object-assign');

const CoordinatesUtils = require("../../../utils/CoordinatesUtils");


class GeometryDetails extends React.Component {
static propTypes = {
useMapProjection: PropTypes.bool,
geometry: PropTypes.object,
type: PropTypes.string,
onShowPanel: PropTypes.func,
onChangeDrawingStatus: PropTypes.func,
onEndDrawing: PropTypes.func
onEndDrawing: PropTypes.func,
zoom: PropTypes.number
};

static defaultProps = {
Expand Down Expand Up @@ -101,7 +103,6 @@ class GeometryDetails extends React.Component {

onModifyGeometry = () => {
let geometry;

// Update the geometry
if (this.props.type === "BBOX") {
this.extent = this.tempExtent;
Expand Down Expand Up @@ -168,28 +169,27 @@ class GeometryDetails extends React.Component {
};

onClosePanel = () => {
if (this.props.type === "BBOX") {
this.resetBBOX();
} else if (this.props.type === "Circle") {
this.resetCircle();
}

this.resetGeom();
this.props.onShowPanel(false);
};

getStep = (zoom = 1) => Math.min(1 / Math.pow(10, Math.ceil(Math.min(zoom, 21) / 3) - 2), 1);
getStepCircle = (zoom, name) => {
const step = this.getStep(zoom);
return name === 'radius' && step * 10000 || step;
};
getBBOXDimensions = (geometry) => {
const extent = geometry.projection !== 'EPSG:4326' && !this.props.useMapProjection ?
CoordinatesUtils.reprojectBbox(geometry.extent, geometry.projection, 'EPSG:4326') : geometry.extent;

return {
// minx
west: Math.round(extent[0] * 100) / 100,
west: extent[0],
// miny
sud: Math.round(extent[1] * 100) / 100,
sud: extent[1],
// maxx
est: Math.round(extent[2] * 100) / 100,
est: extent[2],
// maxy
north: Math.round(extent[3] * 100) / 100
north: extent[3]
};
};
getCircleDimensions = (geometry) => {
Expand All @@ -201,9 +201,9 @@ class GeometryDetails extends React.Component {
center = (center.x === undefined) ? {x: center[0], y: center[1]} : center;

return {
x: Math.round(center.x * 100) / 100,
y: Math.round(center.y * 100) / 100,
radius: Math.round(geometry.radius * 100) / 100
x: center.x,
y: center.y,
radius: geometry.radius
};
};
renderCoordinateField = (value, name) => {
Expand All @@ -214,18 +214,19 @@ class GeometryDetails extends React.Component {
style={{minWidth: '105px', margin: 'auto'}}
type="number"
id={"queryform_bbox_" + name}
defaultValue={value}
step={!this.isWGS84() ? 1 : this.getStep(this.props.zoom)}
defaultValue={this.roundValue(value, !this.isWGS84() ? 100 : 1000000)}
onChange={(evt) => this.onUpdateBBOX(evt.target.value, name)}/>
</div>
);
};

renderCircleField = (value, name) => {
return (
<FormControl
type="number"
id={"queryform_circle_" + name}
defaultValue={value}
defaultValue={this.roundValue(value, !this.isWGS84() || name === 'radius' ? 100 : 1000000)}
step={!this.isWGS84() ? 1 : this.getStepCircle(this.props.zoom, name)}
onChange={(evt) => this.onUpdateCircle(evt.target.value, name)}/>
);
};
Expand Down Expand Up @@ -352,7 +353,7 @@ class GeometryDetails extends React.Component {
key: 'reset',
tooltipId: 'queryform.reset',
glyph: 'clear-filter',
onClick: () => this.resetBBOX()
onClick: () => this.resetGeom()
}, {
key: 'close',
glyph: '1-close',
Expand All @@ -362,29 +363,37 @@ class GeometryDetails extends React.Component {
</SwitchPanel>
);
}

isWGS84 = () => (this.props.geometry || {}).projection === 'EPSG:4326' || !this.props.useMapProjection;
roundValue = (val, prec = 1000000) => Math.round(val * prec) / prec;
resetGeom = () => {
if (this.props.type === "BBOX") {
this.resetBBOX();
} else if (this.props.type === "Circle") {
this.resetCircle();
}
};
resetBBOX = () => {
for (let prop in this.extent) {
if (prop) {
let coordinateInput = document.getElementById("queryform_bbox_" + prop);
coordinateInput.value = this.extent[prop];
this.onUpdateBBOX(coordinateInput.value, prop);
coordinateInput.value = this.roundValue(this.extent[prop], !this.isWGS84() ? 100 : 1000000);
this.onUpdateBBOX(this.extent[prop], prop);
}
}
};

resetCircle = () => {
let radiusInput = document.getElementById("queryform_circle_radius");
radiusInput.value = this.circle.radius;
this.onUpdateCircle(radiusInput.value, "radius");
radiusInput.value = this.roundValue(this.circle.radius, 100);
this.onUpdateCircle(this.circle.radius, "radius");

let coordinateXInput = document.getElementById("queryform_circle_x");
coordinateXInput.value = this.circle.x;
this.onUpdateCircle(coordinateXInput.value, "x");
coordinateXInput.value = this.roundValue(this.circle.x, !this.isWGS84() ? 100 : 1000000);
this.onUpdateCircle(this.circle.x, "x");

let coordinateYInput = document.getElementById("queryform_circle_y");
coordinateYInput.value = this.circle.y;
this.onUpdateCircle(coordinateYInput.value, "y");
coordinateYInput.value = this.roundValue(this.circle.y, !this.isWGS84() ? 100 : 1000000);
this.onUpdateCircle(this.circle.y, "y");
};
}

Expand Down
6 changes: 4 additions & 2 deletions web/client/components/data/query/QueryBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ class QueryBuilder extends React.Component {
allowEmptyFilter: PropTypes.bool,
autocompleteEnabled: PropTypes.bool,
emptyFilterWarning: PropTypes.bool,
header: PropTypes.node
header: PropTypes.node,
zoom: PropTypes.number
};

static defaultProps = {
Expand Down Expand Up @@ -180,7 +181,8 @@ class QueryBuilder extends React.Component {
spatialMethodOptions={this.props.spatialMethodOptions}
spatialPanelExpanded={this.props.spatialPanelExpanded}
showDetailsPanel={this.props.showDetailsPanel}
actions={this.props.spatialFilterActions}/>
actions={this.props.spatialFilterActions}
zoom={this.props.zoom}/>
<CrossLayerFilter
spatialOperations={this.props.spatialOperations}
crossLayerExpanded={this.props.crossLayerExpanded}
Expand Down
9 changes: 6 additions & 3 deletions web/client/components/data/query/SpatialFilter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
const React = require('react');
const {find} = require('lodash');
const PropTypes = require('prop-types');

const {Row, Col, Panel, Glyphicon, FormControl} = require('react-bootstrap');

const ComboField = require('./ComboField');
const GeometryDetails = require('./GeometryDetails');

const {AutocompleteWFSCombobox} = require('../../misc/AutocompleteWFSCombobox');
const ComboFieldListItem = require('./ComboFieldListItem');
const {createWFSFetchStream} = require('../../../observables/autocomplete');
Expand All @@ -31,7 +32,8 @@ class SpatialFilter extends React.Component {
spatialPanelExpanded: PropTypes.bool,
showDetailsPanel: PropTypes.bool,
withContainer: PropTypes.bool,
actions: PropTypes.object
actions: PropTypes.object,
zoom: PropTypes.number
};

static contextTypes = {
Expand Down Expand Up @@ -275,7 +277,8 @@ class SpatialFilter extends React.Component {
type={this.props.spatialField.method}
onShowPanel={this.props.actions.onShowSpatialSelectionDetails}
onChangeDrawingStatus={this.changeDrawingStatus}
onEndDrawing={this.props.actions.onEndDrawing}/>)
onEndDrawing={this.props.actions.onEndDrawing}
zoom={this.props.zoom}/>)
:
<span/>
;
Expand Down
46 changes: 46 additions & 0 deletions web/client/components/misc/enhancers/__tests__/debounce-test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2018, 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, compose} = require('recompose');
const expect = require('expect');
const debounce = require('../debounce');

describe('debounce 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('debounce call only last action', (done) => {
const action = (status, method, owner, features) => {
expect(status).toExist();
expect(status).toBe("replace");
expect(method).toNotExist();
expect(owner).toExist();
expect(owner).toBe("queryform");
expect(features).toExist();
expect(features).toBe("geom2");
done();
};
const Sink = compose(debounce("onChangeDrawingStatus", 800))(createSink( props => {
expect(props).toExist();
expect(props.onChangeDrawingStatus).toExist();
props.onChangeDrawingStatus("geom");
props.onChangeDrawingStatus("geom1");
props.onChangeDrawingStatus("replace", undefined, "queryform", "geom2");
}));
ReactDOM.render((<Sink onChangeDrawingStatus={action}
/>), document.getElementById("container"));
});
});
27 changes: 27 additions & 0 deletions web/client/components/misc/enhancers/debounce.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright 2018, 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 {withHandlers} = require('recompose');
const {debounce} = require("lodash");
const emptyFunc = () => {};
/**
* This enhancer de-bounce a method passed as prop of the given time.
* The action should be present in the props passed to the component
* @memberof components.misc.enhancers
* @function
* @name debounce
* @example
* // example: every props change increment the *count* prop
* compose(debounce("onChangeDrawingStatus", 800));
* the onChangeDrawingStatus action is debounced by 800 ms
*/
module.exports = (action = "", debounceTime = 1000) => withHandlers((initProp = {}) => {
const debounced = debounce(initProp[action] || emptyFunc, debounceTime);
return {
[action]: () => debounced
};
});
5 changes: 3 additions & 2 deletions web/client/plugins/QueryPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const {zoomToExtent} = require('../actions/map');
const {toggleControl} = require('../actions/controls');

const {groupsSelector} = require('../selectors/layers');
const {mapSelector} = require('../selectors/map');
const {
crossLayerFilterSelector,
availableCrossLayerFilterLayersSelector
Expand Down Expand Up @@ -111,11 +112,11 @@ const SmartQueryForm = connect((state) => {
showGeneratedFilter: false,
allowEmptyFilter: true,
emptyFilterWarning: true,
maxHeight: state.map && state.map.present && state.map.present.size && state.map.present.size.height
maxHeight: state.map && state.map.present && state.map.present.size && state.map.present.size.height,
zoom: (mapSelector(state) || {}).zoom
};
}, dispatch => {
return {

attributeFilterActions: bindActionCreators({
onAddGroupField: addGroupField,
onAddFilterField: addFilterField,
Expand Down
2 changes: 1 addition & 1 deletion web/client/translations/data.de-DE
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@
"reset_bbox": "Zurücksetzen",
"save_bbox": "BBOX Änderungen speichern",
"save_radius": "Radius/Kreiszentrum Änderungen speichern",
"radius": "Radius"
"radius": "Radius(m)"
},
"methods": {
"zone": "Zone",
Expand Down
2 changes: 1 addition & 1 deletion web/client/translations/data.en-US
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@
"reset_bbox": "Reset",
"save_bbox": "Save BBOX modifications",
"save_radius": "Save the radius/center modifications",
"radius": "Radius"
"radius": "Radius(m)"
},
"methods": {
"zone": "Zone",
Expand Down
2 changes: 1 addition & 1 deletion web/client/translations/data.es-ES
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@
"reset_bbox": "Reset",
"save_bbox": "Guardar los cambios",
"save_radius": "Guardar los cambios",
"radius": "Radio"
"radius": "Radio(m)"
},
"methods": {
"zone": "Zona",
Expand Down
2 changes: 1 addition & 1 deletion web/client/translations/data.fr-FR
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@
"reset_bbox": "Recommencer",
"save_bbox": "Sauver les modifications",
"save_radius": "Sauver les modifications",
"radius": "Rayon"
"radius": "Rayon(m)"
},
"methods": {
"zone": "Zone",
Expand Down
2 changes: 1 addition & 1 deletion web/client/translations/data.it-IT
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@
"reset_bbox": "Reset",
"save_bbox": "Salva le modifiche al BBOX",
"save_radius": "Salva le modifiche al raggio e/o al centro",
"radius": "Raggio"
"radius": "Raggio(m)"
},
"methods": {
"zone": "Zona",
Expand Down
2 changes: 1 addition & 1 deletion web/client/translations/data.nl-NL
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@
"reset_bbox": "Herbegin",
"save_bbox": "Wijzigingen opslaan",
"save_radius": "Wijzigingen opslaan",
"radius": "Straal"
"radius": "Straal(m)"
},
"methods": {
"zone": "Zone",
Expand Down
2 changes: 1 addition & 1 deletion web/client/translations/data.zh-ZH
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@
"reset_bbox": "Reset",
"save_bbox": "Save BBOX modifications",
"save_radius": "Save the radius/center modifications",
"radius": "Radius"
"radius": "Radius(m)"
},
"methods": {
"zone": "Zone",
Expand Down

0 comments on commit 55bdb6e

Please sign in to comment.