diff --git a/web/client/actions/__tests__/measurement-test.js b/web/client/actions/__tests__/measurement-test.js
index 89c3d8a61a..18ccf944db 100644
--- a/web/client/actions/__tests__/measurement-test.js
+++ b/web/client/actions/__tests__/measurement-test.js
@@ -16,7 +16,8 @@ const {
init, INIT,
changeGeometry, CHANGED_GEOMETRY,
changeCoordinates, CHANGE_COORDINATES,
- addAnnotation, ADD_MEASURE_AS_ANNOTATION
+ addAnnotation, ADD_MEASURE_AS_ANNOTATION,
+ updateMeasures, UPDATE_MEASURES
} = require('../measurement');
const feature = {type: "Feature", geometry: {
coordinates: [],
@@ -113,4 +114,10 @@ describe('Test correctness of measurement actions', () => {
expect(retval.type).toBe(CHANGE_COORDINATES);
expect(retval.coordinates).toEqual(coordinates);
});
+ it('Test updateMeasures action creator', () => {
+ const retval = updateMeasures({len: 0});
+ expect(retval).toExist();
+ expect(retval.type).toBe(UPDATE_MEASURES);
+ expect(retval.measures).toEqual({len: 0});
+ });
});
diff --git a/web/client/actions/measurement.js b/web/client/actions/measurement.js
index 3fa6f0dbf7..b2e4a823b8 100644
--- a/web/client/actions/measurement.js
+++ b/web/client/actions/measurement.js
@@ -13,6 +13,7 @@ const RESET_GEOMETRY = 'MEASUREMENT:RESET_GEOMETRY';
const CHANGE_FORMAT = 'MEASUREMENT:CHANGE_FORMAT';
const CHANGE_COORDINATES = 'MEASUREMENT:CHANGE_COORDINATES';
const ADD_MEASURE_AS_ANNOTATION = 'MEASUREMENT:ADD_MEASURE_AS_ANNOTATION';
+const UPDATE_MEASURES = 'MEASUREMENT:UPDATE_MEASURES';
const INIT = 'MEASUREMENT:INIT';
/**
@@ -79,6 +80,12 @@ function resetGeometry() {
type: RESET_GEOMETRY
};
}
+function updateMeasures(measures) {
+ return {
+ type: UPDATE_MEASURES,
+ measures
+ };
+}
function changeMeasurementState(measureState) {
return {
type: CHANGE_MEASUREMENT_STATE,
@@ -109,6 +116,7 @@ module.exports = {
changeUom, CHANGE_UOM,
changeGeometry, CHANGED_GEOMETRY,
changeFormatMeasurement, CHANGE_FORMAT,
+ updateMeasures, UPDATE_MEASURES,
changeCoordinates, CHANGE_COORDINATES,
resetGeometry, RESET_GEOMETRY,
addAnnotation, ADD_MEASURE_AS_ANNOTATION,
diff --git a/web/client/components/map/openlayers/DrawSupport.jsx b/web/client/components/map/openlayers/DrawSupport.jsx
index 1dc73328d2..e4292c4158 100644
--- a/web/client/components/map/openlayers/DrawSupport.jsx
+++ b/web/client/components/map/openlayers/DrawSupport.jsx
@@ -379,7 +379,7 @@ class DrawSupport extends React.Component {
this.drawInteraction.on('drawend', function(evt) {
this.sketchFeature = evt.feature;
this.sketchFeature.set('id', uuid.v1());
- let drawnGeom = evt.feature.getGeometry();
+ let drawnGeom = this.sketchFeature.getGeometry();
let drawnFeatures = this.drawLayer.getSource().getFeatures();
let previousGeometries;
let features = this.props.features;
@@ -395,7 +395,7 @@ class DrawSupport extends React.Component {
newFeature = this.getNewFeature(newDrawMethod, coordinates);
// TODO verify center is projected in 4326 and is an array
center = reproject(center, this.getMapCrs(), "EPSG:4326", false);
- const originalId = newProps && newProps.features && newProps.features.length && newProps.features[0].features && newProps.features[0].features.length && newProps.features[0].features.filter(f => f.properties.isDrawing)[0].properties.id || this.sketchFeature.get("id");
+ const originalId = newProps && newProps.features && newProps.features.length && newProps.features[0] && newProps.features[0].features && newProps.features[0].features.length && newProps.features[0].features.filter(f => f.properties.isDrawing)[0].properties.id || this.sketchFeature.get("id");
// this.sketchFeature.set('id', originalId);
newFeature.setProperties({isCircle: true, radius, center: [center.x, center.y], id: originalId});
} else if (drawMethod === "Polygon") {
@@ -435,7 +435,7 @@ class DrawSupport extends React.Component {
const center = drawnGeom.getCenter();
const coordinates = this.polygonCoordsFromCircle(center, radius);
const newMultiGeom = this.toMulti(this.createOLGeometry({type: newDrawMethod, coordinates}));
- if (features.length === 1 && !features[0].geometry) {
+ if (features.length === 1 && features[0] && !features[0].geometry) {
previousGeometries = [];
geomCollection = new ol.geom.GeometryCollection([newMultiGeom]);
} else {
@@ -730,8 +730,8 @@ class DrawSupport extends React.Component {
this.addFeatures(newProps);
}
};
- addSingleClickListener = (singleclickCallback) => {
- let evtKey = this.props.map.on('singleclick', singleclickCallback);
+ addSingleClickListener = (singleclickCallback, props) => {
+ let evtKey = props.map.on('singleclick', singleclickCallback);
return evtKey;
};
@@ -740,7 +740,7 @@ class DrawSupport extends React.Component {
if (this.state && this.state.keySingleClickCallback) {
ol.Observable.unByKey(this.state.keySingleClickCallback);
}
- const singleClickCallback = (e) => {
+ const singleClickCallback = (event) => {
if (this.drawSource && newProps.options) {
let previousFeatures = this.drawSource.getFeatures();
let previousFtIndex = 0;
@@ -761,22 +761,22 @@ class DrawSupport extends React.Component {
if (isCompletePolygon(previousCoords)) {
// insert at penultimate position
actualCoords = slice(previousCoords[0], 0, previousCoords[0].length - 1);
- actualCoords = actualCoords.concat([e.coordinate]);
+ actualCoords = actualCoords.concat([event.coordinate]);
actualCoords = [actualCoords.concat([previousCoords[0][0]])];
} else {
// insert at ultimate position if more than 2 point
- actualCoords = previousCoords[0].length > 1 ? [[...previousCoords[0], e.coordinate, previousCoords[0][0] ]] : [[...previousCoords[0], e.coordinate ]];
+ actualCoords = previousCoords[0].length > 1 ? [[...previousCoords[0], event.coordinate, previousCoords[0][0] ]] : [[...previousCoords[0], event.coordinate ]];
}
} else {
// insert at first position
- actualCoords = [[e.coordinate]];
+ actualCoords = [[event.coordinate]];
}
olFt = this.getNewFeature(newDrawMethod, actualCoords);
olFt.setProperties(omit(previousFt && previousFt.getProperties() || {}, "geometry"));
break;
}
case "LineString": case "MultiPoint": {
- actualCoords = previousCoords.length ? [...previousCoords, e.coordinate] : [e.coordinate];
+ actualCoords = previousCoords.length ? [...previousCoords, event.coordinate] : [event.coordinate];
olFt = this.getNewFeature(newDrawMethod, actualCoords);
olFt.setProperties(omit(previousFt && previousFt.getProperties() || {}, "geometry"));
}
@@ -784,7 +784,7 @@ class DrawSupport extends React.Component {
case "Circle": {
newDrawMethod = "Polygon";
const radius = previousFt && previousFt.getProperties() && previousFt.getProperties().radius || 10000;
- let center = e.coordinate;
+ let center = event.coordinate;
const coords = this.polygonCoordsFromCircle(center, 100);
olFt = this.getNewFeature(newDrawMethod, coords);
// TODO verify center is projected in 4326 and is an array
@@ -795,14 +795,14 @@ class DrawSupport extends React.Component {
}
case "Text": {
newDrawMethod = "Point";
- olFt = this.getNewFeature(newDrawMethod, e.coordinate);
+ olFt = this.getNewFeature(newDrawMethod, event.coordinate);
olFt.setProperties(omit(previousFt && previousFt.getProperties() || {}, "geometry"));
olFt.setProperties({isText: true, valueText: previousFt && previousFt.getProperties() && previousFt.getProperties().valueText || newProps.options.defaultTextAnnotation || "New" });
break;
}
// point
default: {
- actualCoords = e.coordinate;
+ actualCoords = event.coordinate;
olFt = this.getNewFeature(newDrawMethod, actualCoords);
olFt.setProperties(omit(previousFt && previousFt.getProperties() || {}, "geometry"));
}
@@ -835,7 +835,7 @@ class DrawSupport extends React.Component {
};
this.clean();
- let newFeature = reprojectGeoJson(head(newProps.features), newProps.options.featureProjection, this.getMapCrs());
+ let newFeature = reprojectGeoJson(head(newProps.features), newProps.options.featureProjection, this.getMapCrs()) || {};
let props;
if (newFeature && newFeature.features && newFeature.features.length) {
// filtering circles features only when drawing
@@ -864,7 +864,7 @@ class DrawSupport extends React.Component {
this.addTranslateInteraction();
}
if (newProps.options.addClickCallback) {
- this.setState({keySingleClickCallback: this.addSingleClickListener(singleClickCallback)});
+ this.setState({keySingleClickCallback: this.addSingleClickListener(singleClickCallback, newProps)});
}
}
if (newProps.options && newProps.options.selectEnabled) {
@@ -999,7 +999,7 @@ class DrawSupport extends React.Component {
// retrieve geodesic center from properties
// it's different from extent center
let center = geometryProperties && geometryProperties.geodesicCenter || ol.extent.getCenter(extent);
- let coordinates = geometry.getCoordinates();
+ let coordinates;
let projection = this.props.map.getView().getProjection().getCode();
let radius;
let type = geometry.getType();
diff --git a/web/client/components/map/openlayers/Feature.jsx b/web/client/components/map/openlayers/Feature.jsx
index b7f06cc29f..fe0b6945ef 100644
--- a/web/client/components/map/openlayers/Feature.jsx
+++ b/web/client/components/map/openlayers/Feature.jsx
@@ -40,19 +40,13 @@ class Feature extends React.Component {
// TODO check if shallow comparison is enough properties and geometry
return !isEqual(nextProps.properties, this.props.properties) ||
!isEqual(nextProps.geometry, this.props.geometry) ||
- (nextProps.features !== this.props.features) ||
- (nextProps.style !== this.props.style);
+ !isEqual(nextProps.features, this.props.features) ||
+ !isEqual(nextProps.style, this.props.style);
}
componentWillUpdate(nextProps) {
- // TODO check if shallow comparison is enough properties and geometry
- if (!isEqual(nextProps.properties, this.props.properties) ||
- !isEqual(nextProps.geometry, this.props.geometry) ||
- (nextProps.features !== this.props.features) ||
- (nextProps.style !== this.props.style)) {
- this.removeFromContainer();
- this.addFeatures(nextProps);
- }
+ this.removeFromContainer();
+ this.addFeatures(nextProps);
}
componentWillUnmount() {
diff --git a/web/client/components/map/openlayers/LegacyVectorStyle.js b/web/client/components/map/openlayers/LegacyVectorStyle.js
index 21606eda61..ef77f98c4f 100644
--- a/web/client/components/map/openlayers/LegacyVectorStyle.js
+++ b/web/client/components/map/openlayers/LegacyVectorStyle.js
@@ -4,7 +4,7 @@ var ol = require('openlayers');
const {last, head} = require('lodash');
const blue = [0, 153, 255, 1];
const assign = require('object-assign');
-const {trim, isString} = require('lodash');
+const {trim, isString, isArray} = require('lodash');
const {colorToRgbaStr} = require('../../../utils/ColorUtils');
const {set} = require('../../../utils/ImmutableUtils');
const selectedStyleConfiguration = {
@@ -485,7 +485,11 @@ function getStyle(options, isDrawing = false, textValues = []) {
}));
}
let gStyle = getValidStyle(type, options, isDrawing, textValues);
- gStyle.setGeometry(c);
+ if (isArray(gStyle)) {
+ gStyle.forEach(s => s.setGeometry(c));
+ } else {
+ gStyle.setGeometry(c);
+ }
return p.concat([gStyle]);
}, []);
return styles;
diff --git a/web/client/components/map/openlayers/MeasurementSupport.jsx b/web/client/components/map/openlayers/MeasurementSupport.jsx
index 69fb7ad086..41cffd1d0e 100644
--- a/web/client/components/map/openlayers/MeasurementSupport.jsx
+++ b/web/client/components/map/openlayers/MeasurementSupport.jsx
@@ -8,25 +8,30 @@
const React = require('react');
const PropTypes = require('prop-types');
-const {round, isEqual, dropRight, slice} = require('lodash');
+const {round, isEqual, dropRight, pick} = require('lodash');
const assign = require('object-assign');
const ol = require('openlayers');
const wgs84Sphere = new ol.Sphere(6378137);
const {reprojectGeoJson, reproject, calculateAzimuth, calculateDistance, transformLineToArcs} = require('../../../utils/CoordinatesUtils');
-const {convertUom, getFormattedBearingValue, isValidGeometry} = require('../../../utils/MeasureUtils');
+const {convertUom, getFormattedBearingValue} = require('../../../utils/MeasureUtils');
const {set} = require('../../../utils/ImmutableUtils');
const {startEndPolylineStyle} = require('./VectorStyle');
const {getMessageById} = require('../../../utils/LocaleUtils');
+const {createOLGeometry} = require('../../../utils/openlayers/DrawUtils');
+
+const getProjectionCode = (olMap) => {
+ return olMap.getView().getProjection().getCode();
+};
class MeasurementSupport extends React.Component {
static propTypes = {
startEndPoint: PropTypes.object,
map: PropTypes.object,
- projection: PropTypes.string,
measurement: PropTypes.object,
enabled: PropTypes.bool,
uom: PropTypes.object,
changeMeasurementState: PropTypes.func,
+ updateMeasures: PropTypes.func,
resetGeometry: PropTypes.func,
changeGeometry: PropTypes.func,
updateOnMouseMove: PropTypes.bool
@@ -37,6 +42,10 @@ class MeasurementSupport extends React.Component {
};
static defaultProps = {
+ changeMeasurementState: () => {},
+ resetGeometry: () => {},
+ updateMeasures: () => {},
+ changeGeometry: () => {},
startEndPoint: {
startPointOptions: {
radius: 3,
@@ -50,8 +59,10 @@ class MeasurementSupport extends React.Component {
updateOnMouseMove: false
};
+ /**
+ * we assume that only valid features are passed to the draw tools
+ */
componentWillReceiveProps(newProps) {
- this.invalidCoordinates = [];
if (newProps.measurement.geomType && newProps.measurement.geomType !== this.props.measurement.geomType ||
/* check also when a measure tool is enabled
* if so the first condition does not match
@@ -64,56 +75,30 @@ class MeasurementSupport extends React.Component {
if (!newProps.measurement.geomType) {
this.removeDrawInteraction();
}
- /**
- * if invalid coords are sent here just or draw only valid ones
- */
- let ft = newProps.measurement.feature;
let oldFt = this.props.measurement.feature;
- let isNewGeomPresent = ft && ft.geometry;
- if (isNewGeomPresent && !isEqual(ft.geometry, oldFt.geometry) && !isValidGeometry(ft.geometry)) {
- // filtering out the invalid coords because causing errors/crash when reprojecting
- let props = set("measurement.feature.geometry.coordinates", (ft.geometry.type === "Polygon" ? ft.geometry.coordinates[0] : ft.geometry.coordinates)
- .filter((c, i) => {
- const isValid = !isNaN(parseFloat(c[0])) && !isNaN(parseFloat(c[1]));
- if (!isValid) {
- // if some coords are invalid we then need to add it to the feature before updating the state
- this.invalidCoordinates.push({coord: c, index: i});
- }
- return isValid;
- }
- ), newProps);
- if (ft.geometry.type === "Polygon") {
- props = set("measurement.feature.geometry.coordinates", [props.measurement.feature.geometry.coordinates], props);
- }
- this.updateFeatures(props);
- }
+ let newFt = newProps.measurement.feature;
/**
- * this is needed to update the feature drawn by this tool and recalculate the measures,
- * although the recalculation should be moved in the reducer. so we can avoid to to weird stuff here if there is another plugin / component
- * that is going to update the coordinates via UI or any other action
+ * update the feature drawn and recalculate the measures and tooltips
+ * then update the stae with only the new measures calculated
*/
- if (isNewGeomPresent && isValidGeometry(ft.geometry) && newProps.measurement.updatedByUI && (!isEqual(oldFt, ft) || !isEqual(this.props.uom, newProps.uom))) {
- this.updateFeatures(newProps);
+ if (newFt && newFt.geometry && newProps.measurement.updatedByUI && (!isEqual(oldFt, newFt) || !isEqual(this.props.uom, newProps.uom))) {
+ this.updateMeasures(newProps);
}
}
- getPointCoordinate = (coordinate) => {
- return reproject(coordinate, this.props.projection, 'EPSG:4326');
- };
-
render() {
return null;
}
- isPolygon = (feature) => {
- return feature.geometry.type === "Polygon";
+ validateCoords = (coords) => {
+ return coords.filter((c) => !isNaN(parseFloat(c[0])) && !isNaN(parseFloat(c[1])));
}
/**
* This method takes the feature from properties and
* it updated the drawn feature and its measure tooltip
* It must receive only valid coordinates
*/
- updateFeatures = (props) => {
+ updateMeasures = (props) => {
this.replaceFeatures([props.measurement.feature], props);
// update measure tooltip
@@ -158,38 +143,15 @@ class MeasurementSupport extends React.Component {
}
this.source = new ol.source.Vector();
featuresToReplace.forEach((geoJSON) => {
- let geoJSONFT = geoJSON;
- // polygons must have at least 4 points where the first being equal to the last
- if (geoJSONFT.geometry.type === "Polygon" && geoJSONFT.geometry.coordinates[0].length >= 3) {
- if (!isEqual(geoJSONFT.geometry.coordinates[0][0], geoJSONFT.geometry.coordinates[0][geoJSONFT.geometry.coordinates[0].length - 1])) {
- geoJSONFT = set("geometry.coordinates", [geoJSONFT.geometry.coordinates[0].concat([geoJSONFT.geometry.coordinates[0][0]])], geoJSONFT);
- }
- }
- let geometry = reprojectGeoJson(geoJSONFT, "EPSG:4326", this.props.map.getView().getProjection().getCode()).geometry;
+ let geometry = reprojectGeoJson(geoJSON, "EPSG:4326", getProjectionCode(this.props.map)).geometry;
const feature = new ol.Feature({
- geometry: this.createOLGeometry(geometry)
+ geometry: createOLGeometry(geometry)
});
this.source.addFeature(feature);
});
this.measureLayer.setSource(this.source);
};
- createOLGeometry = ({type, coordinates, radius, center}) => {
- let geometry;
- switch (type) {
- case "Point": { geometry = new ol.geom.Point(coordinates ? coordinates : []); break; }
- case "LineString": { geometry = new ol.geom.LineString(coordinates ? coordinates : []); break; }
- case "MultiPoint": { geometry = new ol.geom.MultiPoint(coordinates ? coordinates : []); break; }
- case "MultiLineString": { geometry = new ol.geom.MultiLineString(coordinates ? coordinates : []); break; }
- case "MultiPolygon": { geometry = new ol.geom.MultiPolygon(coordinates ? coordinates : []); break; }
- // defaults is Polygon
- default: { geometry = radius && center ?
- ol.geom.Polygon.fromCircle(new ol.geom.Circle([center.x, center.y], radius), 100) : new ol.geom.Polygon(coordinates ? coordinates : []);
- }
- }
- return geometry;
- };
-
addDrawInteraction = (newProps) => {
let vector;
let draw;
@@ -308,7 +270,7 @@ class MeasurementSupport extends React.Component {
draw.on('drawend', function(evt) {
this.drawing = false;
const geojsonFormat = new ol.format.GeoJSON();
- let newFeature = reprojectGeoJson(geojsonFormat.writeFeatureObject(evt.feature.clone()), this.props.map.getView().getProjection().getCode(), "EPSG:4326");
+ let newFeature = reprojectGeoJson(geojsonFormat.writeFeatureObject(evt.feature.clone()), getProjectionCode(this.props.map), "EPSG:4326");
this.props.changeGeometry(newFeature);
if (this.props.measurement.lineMeasureEnabled) {
// Calculate arc
@@ -388,65 +350,61 @@ class MeasurementSupport extends React.Component {
if (props.measurement.geomType === 'Bearing' && sketchCoords.length > 1) {
// calculate the azimuth as base for bearing information
- bearing = calculateAzimuth(sketchCoords[0], sketchCoords[1], props.projection);
+ bearing = calculateAzimuth(sketchCoords[0], sketchCoords[1], getProjectionCode(props.map));
if (sketchCoords.length > 2) {
this.drawInteraction.sketchCoords_ = [sketchCoords[0], sketchCoords[1], sketchCoords[0]];
+ while (this.sketchFeature.getGeometry().getCoordinates().length > 3) {
+ /*
+ * In some cases, if the user is too quick changing direction after the creation of the second point
+ * (before the draw interaction stops) new point are created in the interaction and have to be removed
+ * note: `> 3` is because the last point of the sketchFeature is the current mouse position
+ */
+ this.drawInteraction.removeLastPoint();
+ }
this.sketchFeature.getGeometry().setCoordinates([sketchCoords[0], sketchCoords[1]]);
this.drawInteraction.sketchFeature_ = this.sketchFeature;
this.drawInteraction.finishDrawing();
}
}
const geojsonFormat = new ol.format.GeoJSON();
- let feature = reprojectGeoJson(geojsonFormat.writeFeatureObject(this.sketchFeature.clone()), props.map.getView().getProjection().getCode(), "EPSG:4326");
+ let feature = reprojectGeoJson(geojsonFormat.writeFeatureObject(this.sketchFeature.clone()), getProjectionCode(props.map), "EPSG:4326");
// it will no longer create 100 points for arcs to put in the state
let newMeasureState = assign({}, props.measurement,
{
- point: props.measurement.geomType === 'Point' ? this.getPointCoordinate(sketchCoords) : null,
- len: props.measurement.geomType === 'LineString' ? calculateDistance(this.reprojectedCoordinates(sketchCoords), props.measurement.lengthFormula) : 0,
+ point: props.measurement.geomType === 'Point' ? reproject(sketchCoords, getProjectionCode(this.props.map), 'EPSG:4326') : null,
+ len: props.measurement.geomType === 'LineString' ? calculateDistance(this.reprojectedCoordinatesIn4326(sketchCoords), props.measurement.lengthFormula) : 0,
area: props.measurement.geomType === 'Polygon' ? this.calculateGeodesicArea(this.sketchFeature.getGeometry().getLinearRing(0).getCoordinates()) : 0,
bearing: props.measurement.geomType === 'Bearing' ? bearing : 0,
lenUnit: props.measurement.lenUnit,
areaUnit: props.measurement.areaUnit,
- updatedByUI
- },
- // feature should not change if the changes comes from ui
- !updatedByUI ? {
feature: set("geometry.coordinates", this.drawing ?
props.measurement.geomType === 'Polygon' ? [dropRight(feature.geometry.coordinates[0], feature.geometry.coordinates[0].length <= 2 ? 0 : 1)] : dropRight(feature.geometry.coordinates) :
feature.geometry.coordinates, feature)
- } : {}
- );
- // checks for invalid coords that needs to be re-added
- if (this.invalidCoordinates.length) {
- let newCoords;
- this.invalidCoordinates.forEach(c => {
- let coords = props.measurement.geomType === 'Polygon' ? newMeasureState.feature.geometry.coordinates[0] : newMeasureState.feature.geometry.coordinates;
- newCoords = slice(coords, 0, c.index);
- newCoords = newCoords.concat([c.coord]);
- newCoords = newCoords.concat(slice(coords, c.index, coords.length));
- newMeasureState = set("feature.geometry.coordinates", props.measurement.geomType === 'Polygon' ? [newCoords] : newCoords, newMeasureState);
- });
-
- if (props.measurement.geomType === 'Polygon' && (!isEqual(newCoords[0], newCoords[newCoords.length - 1]))) {
- newCoords = newCoords.concat([newCoords[0]]);
- newMeasureState = set("feature.geometry.coordinates", [newCoords], newMeasureState);
}
+ );
+ if (updatedByUI) {
+ // update only re-calculated measures
+ this.props.updateMeasures(pick(newMeasureState, ["bearing", "area", "len", "point"]));
+ } else {
+ // update also the feature
+ this.props.changeMeasurementState(newMeasureState);
}
- this.invalidCoordinates = [];
- this.props.changeMeasurementState(newMeasureState);
};
- reprojectedCoordinates = (coordinates) => {
+ reprojectedCoordinatesIn4326 = (coordinates) => {
return coordinates.map((coordinate) => {
- let reprojectedCoordinate = reproject(coordinate, this.props.projection, 'EPSG:4326');
+ let reprojectedCoordinate = reproject(coordinate, getProjectionCode(this.props.map), 'EPSG:4326');
return [reprojectedCoordinate.x, reprojectedCoordinate.y];
});
};
calculateGeodesicArea = (coordinates) => {
- let reprojectedCoordinates = this.reprojectedCoordinates(coordinates);
- return Math.abs(wgs84Sphere.geodesicArea(reprojectedCoordinates));
+ if (coordinates.length >= 4 ) {
+ let reprojectedCoordinatesIn4326 = this.reprojectedCoordinatesIn4326(coordinates);
+ return Math.abs(wgs84Sphere.geodesicArea(reprojectedCoordinatesIn4326));
+ }
+ return 0;
};
/**
@@ -486,10 +444,10 @@ class MeasurementSupport extends React.Component {
const sketchCoords = line.getCoordinates();
if (props.measurement.geomType === 'Bearing' && sketchCoords.length > 1) {
// calculate the azimuth as base for bearing information
- const bearing = calculateAzimuth(sketchCoords[0], sketchCoords[1], props.projection);
+ const bearing = calculateAzimuth(sketchCoords[0], sketchCoords[1], getProjectionCode(props.map));
return getFormattedBearingValue(bearing);
}
- const reprojectedCoords = this.reprojectedCoordinates(sketchCoords);
+ const reprojectedCoords = this.reprojectedCoordinatesIn4326(sketchCoords);
const length = calculateDistance(reprojectedCoords, props.measurement.lengthFormula);
const {label, unit} = props.uom && props.uom.length;
const output = round(convertUom(length, "m", unit), 2);
diff --git a/web/client/components/map/openlayers/Overview.jsx b/web/client/components/map/openlayers/Overview.jsx
index 087175ef76..6557ae6374 100644
--- a/web/client/components/map/openlayers/Overview.jsx
+++ b/web/client/components/map/openlayers/Overview.jsx
@@ -1,8 +1,16 @@
-var PropTypes = require('prop-types');
-var React = require('react');
-var ol = require('openlayers');
-var Layers = require('../../../utils/openlayers/Layers');
-var assign = require('object-assign');
+/**
+ * Copyright 2015, 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 PropTypes = require('prop-types');
+const React = require('react');
+const ol = require('openlayers');
+const Layers = require('../../../utils/openlayers/Layers');
+const assign = require('object-assign');
+const {isFinite} = require('lodash');
require('./overview.css');
@@ -63,7 +71,7 @@ class Overview extends React.Component {
return null;
}
- dragstart = (e) => {
+ dragstart = (event) => {
if (!this.dragging) {
this.dragBox = this.box.cloneNode();
this.dragBox.setAttribute("class", "ol-overview-dargbox");
@@ -79,18 +87,18 @@ class Overview extends React.Component {
} else {
this.offsetStartLeft = parseInt(this.box.style.left.slice(0, -2), 10);
}
- this.mouseStartTop = e.pageY;
- this.mouseStartLeft = e.pageX;
+ this.mouseStartTop = event.pageY;
+ this.mouseStartLeft = event.pageX;
this.dragging = true;
}
};
- draggingel = (e) => {
+ draggingel = (event) => {
if (this.dragging === true) {
- this.dragBox.style.top = this.offsetStartTop + e.pageY - this.mouseStartTop + 'px';
- this.dragBox.style.left = this.offsetStartLeft + e.pageX - this.mouseStartLeft + 'px';
- e.stopPropagation();
- e.preventDefault();
+ this.dragBox.style.top = this.offsetStartTop + event.pageY - this.mouseStartTop + 'px';
+ this.dragBox.style.left = this.offsetStartLeft + event.pageX - this.mouseStartLeft + 'px';
+ event.stopPropagation();
+ event.preventDefault();
}
};
@@ -112,10 +120,12 @@ class Overview extends React.Component {
let mapSize = this.props.map.getSize();
let xMove = offset.left * Math.abs(mapSize[0] / vWidth);
let yMove = offset.top * Math.abs(mapSize[1] / vHeight);
+ xMove = isFinite(xMove) ? xMove : 0;
+ yMove = isFinite(yMove) ? yMove : 0;
let bottomLeft = [0 + xMove, mapSize[1] + yMove];
let topRight = [mapSize[0] + xMove, 0 + yMove];
- let left = this.props.map.getCoordinateFromPixel(bottomLeft);
- let top = this.props.map.getCoordinateFromPixel(topRight);
+ let left = this.props.map.getCoordinateFromPixel(bottomLeft) || [0, 0];
+ let top = this.props.map.getCoordinateFromPixel(topRight) || [0, 0];
let extent = [left[0], left[1], top[0], top[1]];
this.props.map.getView().fit(extent, mapSize, {nearest: true});
};
diff --git a/web/client/components/map/openlayers/__tests__/DrawSupport-test.jsx b/web/client/components/map/openlayers/__tests__/DrawSupport-test.jsx
index a78215f33c..15a414c3b1 100644
--- a/web/client/components/map/openlayers/__tests__/DrawSupport-test.jsx
+++ b/web/client/components/map/openlayers/__tests__/DrawSupport-test.jsx
@@ -12,443 +12,63 @@ const ol = require('openlayers');
const assign = require('object-assign');
const DrawSupport = require('../DrawSupport');
const {DEFAULT_ANNOTATIONS_STYLES} = require('../../../../utils/AnnotationsUtils');
+const {circle, geomCollFeature} = require('../../../../test-resources/drawsupport/features');
-let CIRCLE = {
- type: 'FeatureCollection',
- id: '36835090-23ad-11e8-9839-9bab136db9a3',
- features: [{
- type: 'Feature',
- geometry: {
- type: 'Polygon',
- coordinates: [
- [
- [
- -7.066692092065635,
- 47.17477833929903
- ],
- [
- -7.070957956986268,
- 47.26697075050753
- ],
- [
- -7.083738716328214,
- 47.35863997502234
- ],
- [
- -7.104983930273322,
- 47.44942710493982
- ],
- [
- -7.134609753668168,
- 47.53897854842588
- ],
- [
- -7.172499266922562,
- 47.6269473500946
- ],
- [
- -7.218502937437762,
- 47.71299445745591
- ],
- [
- -7.272439209743323,
- 47.796789930095706
- ],
- [
- -7.334095222013593,
- 47.87801408888858
- ],
- [
- -7.403227646136091,
- 47.95635860315586
- ],
- [
- -7.479563648016411,
- 48.03152751426181
- ],
- [
- -7.562801964329729,
- 48.10323819468144
- ],
- [
- -7.6526140914695295,
- 48.17122224206827
- ],
- [
- -7.748645582001249,
- 48.235226308292674
- ],
- [
- -7.850517443504369,
- 48.29501286380931
- ],
- [
- -7.95782763428237,
- 48.35036089804014
- ],
- [
- -8.07015265003761,
- 48.40106655672712
- ],
- [
- -8.18704919524932,
- 48.44694371741463
- ],
- [
- -8.308055932658505,
- 48.48782450436609
- ],
- [
- -8.432695303955327,
- 48.52355974430404
- ],
- [
- -8.560475414483594,
- 48.55401936438973
- ],
- [
- -8.690891974524225,
- 48.57909273383168
- ],
- [
- -8.823430289496404,
- 48.59868895043517
- ],
- [
- -8.95756729122193,
- 48.612737073283476
- ],
- [
- -9.092773602236358,
- 48.62118630258009
- ],
- [
- -9.228515625000002,
- 48.62400610748772
- ],
- [
- -9.364257647763646,
- 48.62118630258009
- ],
- [
- -9.499463958778072,
- 48.612737073283476
- ],
- [
- -9.633600960503598,
- 48.59868895043517
- ],
- [
- -9.766139275475776,
- 48.57909273383168
- ],
- [
- -9.89655583551641,
- 48.55401936438973
- ],
- [
- -10.024335946044676,
- 48.52355974430404
- ],
- [
- -10.148975317341497,
- 48.48782450436609
- ],
- [
- -10.269982054750683,
- 48.44694371741463
- ],
- [
- -10.386878599962396,
- 48.40106655672712
- ],
- [
- -10.499203615717633,
- 48.35036089804014
- ],
- [
- -10.606513806495634,
- 48.29501286380931
- ],
- [
- -10.708385667998753,
- 48.235226308292674
- ],
- [
- -10.804417158530473,
- 48.17122224206827
- ],
- [
- -10.894229285670272,
- 48.10323819468144
- ],
- [
- -10.977467601983593,
- 48.03152751426181
- ],
- [
- -11.053803603863912,
- 47.95635860315586
- ],
- [
- -11.12293602798641,
- 47.87801408888858
- ],
- [
- -11.184592040256682,
- 47.796789930095706
- ],
- [
- -11.238528312562241,
- 47.71299445745591
- ],
- [
- -11.284531983077443,
- 47.6269473500946
- ],
- [
- -11.322421496331836,
- 47.53897854842588
- ],
- [
- -11.352047319726681,
- 47.44942710493982
- ],
- [
- -11.373292533671789,
- 47.35863997502234
- ],
- [
- -11.386073293013734,
- 47.26697075050753
- ],
- [
- -11.390339157934367,
- 47.17477833929903
- ],
- [
- -11.386073293013734,
- 47.08242559504841
- ],
- [
- -11.373292533671789,
- 46.990277901535556
- ],
- [
- -11.35204731972668,
- 46.8987017170481
- ],
- [
- -11.322421496331836,
- 46.808063084694076
- ],
- [
- -11.284531983077443,
- 46.718726115193576
- ],
- [
- -11.238528312562241,
- 46.63105144927073
- ],
- [
- -11.184592040256682,
- 46.545394707297326
- ],
- [
- -11.12293602798641,
- 46.46210493431348
- ],
- [
- -11.053803603863912,
- 46.381523048960865
- ],
- [
- -10.977467601983593,
- 46.303980305201314
- ],
- [
- -10.894229285670272,
- 46.22979677595146
- ],
- [
- -10.804417158530473,
- 46.15927986793656
- ],
- [
- -10.708385667998753,
- 46.09272287714786
- ],
- [
- -10.60651380649563,
- 46.03040359427646
- ],
- [
- -10.499203615717633,
- 45.972582969388
- ],
- [
- -10.386878599962396,
- 45.919503844897314
- ],
- [
- -10.269982054750683,
- 45.871389765601215
- ],
- [
- -10.148975317341497,
- 45.828443874131516
- ],
- [
- -10.024335946044676,
- 45.79084789970411
- ],
- [
- -9.89655583551641,
- 45.75876124746622
- ],
- [
- -9.766139275475776,
- 45.73232019509079
- ],
- [
- -9.633600960503598,
- 45.711637202538626
- ],
- [
- -9.499463958778076,
- 45.696800340115416
- ],
- [
- -9.364257647763646,
- 45.6878728390993
- ],
- [
- -9.228515625000002,
- 45.684892768315834
- ],
- [
- -9.092773602236358,
- 45.6878728390993
- ],
- [
- -8.95756729122193,
- 45.696800340115416
- ],
- [
- -8.823430289496406,
- 45.711637202538626
- ],
- [
- -8.690891974524225,
- 45.73232019509079
- ],
- [
- -8.560475414483594,
- 45.75876124746622
- ],
- [
- -8.43269530395533,
- 45.79084789970411
- ],
- [
- -8.308055932658508,
- 45.828443874131516
- ],
- [
- -8.187049195249319,
- 45.871389765601215
- ],
- [
- -8.07015265003761,
- 45.919503844897314
- ],
- [
- -7.95782763428237,
- 45.972582969388
- ],
- [
- -7.850517443504371,
- 46.03040359427646
- ],
- [
- -7.7486455820012505,
- 46.09272287714786
- ],
- [
- -7.652614091469531,
- 46.15927986793656
- ],
- [
- -7.562801964329729,
- 46.22979677595146
- ],
- [
- -7.479563648016411,
- 46.3039803052013
- ],
- [
- -7.403227646136092,
- 46.381523048960865
- ],
- [
- -7.334095222013593,
- 46.46210493431348
- ],
- [
- -7.272439209743323,
- 46.545394707297326
- ],
- [
- -7.218502937437762,
- 46.63105144927073
- ],
- [
- -7.172499266922562,
- 46.718726115193576
- ],
- [
- -7.134609753668168,
- 46.808063084694076
- ],
- [
- -7.104983930273322,
- 46.8987017170481
- ],
- [
- -7.083738716328214,
- 46.990277901535556
- ],
- [
- -7.070957956986268,
- 47.08242559504841
- ],
- [
- -7.066692092065635,
- 47.17477833929903
- ]
- ]
- ]
- }
- }],
- newFeature: true,
- properties: {
- id: '36835090-23ad-11e8-9839-9bab136db9a3',
- circles: [0],
- isCircle: true
- },
- style: {
- type: 'Circle',
- Circle: {
- color: '#ffcc33',
- opacity: 1,
- weight: 3,
- fillColor: '#ffffff',
- fillOpacity: 0.2,
- radius: 10
- }
- }
+const viewOptions = {
+ projection: 'EPSG:3857',
+ center: [0, 0],
+ zoom: 5
+};
+let olMap = new ol.Map({
+ target: "map",
+ view: new ol.View(viewOptions)
+});
+olMap.disableEventListener = () => {};
+
+const testHandlers = {
+ onStatusChange: () => {},
+ onSelectFeatures: () => {},
+ onGeometryChanged: () => {},
+ onEndDrawing: () => {},
+ onDrawingFeatures: () => {}
+};
+
+/* used to render the DrawSupport component with some default props*/
+const renderDrawSupport = (props = {}) => {
+ return ReactDOM.render(
+ , document.getElementById("container"));
};
+/**
+ * it renders Drawsupport in edit mode with singleclick Listener enabled and
+ * it dispatches a singleclick mouse event
+*/
+const renderAndClick = (props = {}, options = {}) => {
+ let support = renderDrawSupport();
+ // entering componentWillReceiveProps
+ support = renderDrawSupport({
+ drawStatus: "drawOrEdit",
+ features: [props.feature],
+ options: {
+ drawEnabled: false,
+ editEnabled: true,
+ addClickCallback: true
+ },
+ ...props
+ });
+ support.props.map.dispatchEvent({
+ type: "singleclick",
+ coordinate: options.singleClickCoordiante || [500, 30]
+ });
+ return support;
+};
+
+
describe('Test DrawSupport', () => {
beforeEach((done) => {
document.body.innerHTML = '
';
@@ -457,6 +77,13 @@ describe('Test DrawSupport', () => {
afterEach((done) => {
document.body.innerHTML = '';
+ olMap = new ol.Map({
+ target: "map",
+ view: new ol.View(viewOptions)
+ });
+ olMap.disableEventListener = () => {};
+
+ expect.restoreSpies();
setTimeout(done);
});
@@ -489,19 +116,24 @@ describe('Test DrawSupport', () => {
getView: () => ({getProjection: () => ({getCode: () => "EPSG:3857"})}),
disableEventListener: () => {},
addInteraction: () => {},
+ enableEventListener: () => {},
+ removeInteraction: () => {},
+ removeLayer: () => {},
getInteractions: () => ({
getLength: () => 0
})
};
- const spyAdd = expect.spyOn(fakeMap, "addLayer");
- const spyInteraction = expect.spyOn(fakeMap, "addInteraction");
+ const spyAddLayer = expect.spyOn(fakeMap, "addLayer");
+ const spyAddInteraction = expect.spyOn(fakeMap, "addInteraction");
const support = ReactDOM.render(
, document.getElementById("container"));
expect(support).toExist();
ReactDOM.render(
, document.getElementById("container"));
- expect(spyAdd.calls.length).toBe(1);
- expect(spyInteraction.calls.length).toBe(1);
+ ReactDOM.render(
+ , document.getElementById("container"));
+ expect(spyAddLayer.calls.length).toBe(2);
+ expect(spyAddInteraction.calls.length).toBe(2);
});
it('starts drawing bbox', () => {
@@ -579,9 +211,6 @@ describe('Test DrawSupport', () => {
})
};
- const testHandlers = {
- onStatusChange: () => {}
- };
const ft = {
type: "Feature",
geometry: {
@@ -619,9 +248,6 @@ describe('Test DrawSupport', () => {
})
};
- const testHandlers = {
- onStatusChange: () => {}
- };
const spyChangeStatus = expect.spyOn(testHandlers, "onStatusChange");
const support = ReactDOM.render(
@@ -746,10 +372,6 @@ describe('Test DrawSupport', () => {
})
})
};
- const testHandlers = {
- onEndDrawing: () => {},
- onStatusChange: () => {}
- };
const feature = new ol.Feature({
geometry: new ol.geom.Point(13.0, 43.0),
name: 'My Point'
@@ -762,6 +384,10 @@ describe('Test DrawSupport', () => {
ReactDOM.render(
, document.getElementById("container"));
+ support.drawInteraction.dispatchEvent({
+ type: 'drawstart',
+ feature: feature
+ });
support.drawInteraction.dispatchEvent({
type: 'drawend',
feature: feature
@@ -770,7 +396,7 @@ describe('Test DrawSupport', () => {
expect(spyChangeStatus.calls.length).toBe(1);
});
- it('end drawing with continue', () => {
+ it('end drawing a circle feature ', () => {
const fakeMap = {
addLayer: () => {},
disableEventListener: () => {},
@@ -784,9 +410,46 @@ describe('Test DrawSupport', () => {
})
})
};
- const testHandlers = {
- onEndDrawing: () => {},
- onStatusChange: () => {}
+ const feature = new ol.Feature({
+ geometry: new ol.geom.Circle([13.0, 43.0], 100),
+ name: 'My Point'
+ });
+ const spyEnd = expect.spyOn(testHandlers, "onEndDrawing");
+ const spyChangeStatus = expect.spyOn(testHandlers, "onStatusChange");
+ const support = ReactDOM.render(
+ , document.getElementById("container"));
+ expect(support).toExist();
+ ReactDOM.render(
+ , document.getElementById("container"));
+ support.drawInteraction.dispatchEvent({
+ type: 'drawstart',
+ feature: feature
+ });
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: feature
+ });
+ expect(spyEnd.calls.length).toBe(1);
+ expect(spyChangeStatus.calls.length).toBe(1);
+ });
+
+ it('end drawing with continue', () => {
+ const fakeMap = {
+ addLayer: () => {},
+ disableEventListener: () => {},
+ addInteraction: () => {},
+ getInteractions: () => ({
+ getLength: () => 0
+ }),
+ getView: () => ({
+ getProjection: () => ({
+ getCode: () => 'EPSG:4326'
+ })
+ })
};
const feature = new ol.Feature({
geometry: new ol.geom.Point(13.0, 43.0),
@@ -1478,11 +1141,6 @@ describe('Test DrawSupport', () => {
})
};
- const testHandlers = {
- onEndDrawing: () => {},
- onStatusChange: () => {},
- onGeometryChanged: () => {}
- };
const geoJSON = {
type: 'Feature',
geometry: {
@@ -1537,11 +1195,6 @@ describe('Test DrawSupport', () => {
})
};
- const testHandlers = {
- onEndDrawing: () => {},
- onStatusChange: () => {},
- onGeometryChanged: () => {}
- };
const geoJSON = {
type: 'Feature',
geometry: {
@@ -1599,7 +1252,7 @@ describe('Test DrawSupport', () => {
};
const support = ReactDOM.render(
- , document.getElementById("container"));
+ , document.getElementById("container"));
expect(support).toExist();
const center = [1, 1];
const radius = 100;
@@ -1931,4 +1584,501 @@ describe('Test DrawSupport', () => {
}, 100);
});
+ it('test draw callbacks in edit mode with Polygons feature', (done) => {
+ const feature = {
+ type: 'Feature',
+ geometry: {
+ type: 'Polygon',
+ coordinates: [[
+ [13, 43],
+ [15, 43],
+ [15, 44],
+ [13, 43]
+ ]]
+ },
+ properties: {
+ name: "some name",
+ id: "a-unique-id",
+ canEdit: true
+ },
+ style: [{
+ id: "style-id",
+ color: "#FF0000",
+ opacity: 1,
+ fillColor: "#0000FF",
+ fillOpacity: 1
+ }]
+ };
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ let support = renderAndClick({
+ feature,
+ drawMethod: feature.geometry.type
+ });
+ expect(support).toExist();
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ const ft = spyOnDrawingFeatures.calls[0].arguments[0][0];
+ expect(ft.type).toBe("Feature");
+ expect(ft.geometry.type).toBe("Polygon");
+ expect(ft.properties).toEqual({
+ "name": "some name",
+ "id": "a-unique-id",
+ "canEdit": true
+ });
+ done();
+ });
+ it('test draw callbacks in edit mode with LineString feature', (done) => {
+ const feature = {
+ type: 'Feature',
+ geometry: {
+ type: 'LineString',
+ coordinates: [
+ [13, 43],
+ [15, 43],
+ [15, 44],
+ [13, 43]
+ ]
+ },
+ properties: {
+ name: "some name",
+ id: "a-unique-id",
+ canEdit: true
+ },
+ style: [{
+ id: "style-id",
+ color: "#FF0000",
+ opacity: 1
+ }]
+ };
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ let support = renderAndClick({
+ feature,
+ drawMethod: feature.geometry.type
+ });
+ expect(support).toExist();
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ done();
+ });
+
+ it('test draw callbacks in edit mode with Text feature', (done) => {
+ const feature = {
+ type: 'Feature',
+ geometry: {
+ type: 'Point',
+ coordinates: [13, 43]
+ },
+ properties: {
+ name: "some name",
+ id: "a-unique-id",
+ valueText: "a text",
+ canEdit: true,
+ isText: true
+ },
+ style: [{
+ id: "style-id",
+ color: "#FF0000",
+ label: "a text",
+ opacity: 1
+ }]
+ };
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ let support = renderAndClick({
+ feature,
+ drawMethod: "Text"
+ });
+ expect(support).toExist();
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ done();
+ });
+
+ it('test draw callbacks in edit mode with Circle feature', (done) => {
+ const feature = {
+ type: 'Feature',
+ geometry: {
+ type: 'Point',
+ coordinates: [13, 43]
+ },
+ properties: {
+ name: "some name",
+ id: "a-unique-id",
+ valueText: "a text",
+ canEdit: true,
+ radius: 1111,
+ isCircle: true
+ },
+ style: [{
+ id: "style-id",
+ color: "#FF0000",
+ opacity: 1
+ }]
+ };
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ let support = renderAndClick({
+ feature,
+ drawMethod: "Circle"
+ });
+ expect(support).toExist();
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ done();
+ });
+ it('test drawend callbacks with Circle, transformed int feature collection', (done) => {
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnEndDrawing = expect.spyOn(testHandlers, "onEndDrawing");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ features: [null],
+ drawMethod: "Circle",
+ drawStatus: "drawOrEdit",
+ options: {
+ transformToFeatureCollection: true,
+ drawEnabled: true
+ }
+ });
+ expect(support).toExist();
+ const center = [1300, 4300];
+ const radius = 1000;
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.Circle(center, radius)
+ })
+ });
+ const drawOwner = null;
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnGeometryChanged.calls.length).toBe(1);
+ const ArgsGeometryChanged = spyOnGeometryChanged.calls[0].arguments;
+ expect(ArgsGeometryChanged.length).toBe(5);
+ expect(ArgsGeometryChanged[1]).toBe(drawOwner);
+ expect(ArgsGeometryChanged[2]).toEqual("");
+ expect(ArgsGeometryChanged[3]).toEqual(false);
+ expect(ArgsGeometryChanged[4]).toEqual(true);
+ expect(spyOnEndDrawing).toHaveBeenCalled();
+ expect(spyOnEndDrawing.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnEndDrawing.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(2);
+ expect(ArgsEndDrawing[1]).toBe(drawOwner);
+ expect(ArgsGeometryChanged[0][0]).toEqual(ArgsEndDrawing[0]);
+
+ done();
+ });
+
+ it('test drawend callbacks with Text, transformed int feature collection', (done) => {
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnEndDrawing = expect.spyOn(testHandlers, "onEndDrawing");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ features: [null],
+ drawMethod: "Text",
+ drawStatus: "drawOrEdit",
+ options: {
+ transformToFeatureCollection: true,
+ stopAfterDrawing: true,
+ drawEnabled: true
+ }
+ });
+ expect(support).toExist();
+ const coordinate = [1300, 4300];
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.Point(coordinate)
+ })
+ });
+ const drawOwner = null;
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnGeometryChanged.calls.length).toBe(1);
+ const ArgsGeometryChanged = spyOnGeometryChanged.calls[0].arguments;
+ expect(ArgsGeometryChanged.length).toBe(5);
+ expect(ArgsGeometryChanged[1]).toBe(drawOwner);
+ expect(ArgsGeometryChanged[2]).toEqual("enterEditMode");
+ expect(ArgsGeometryChanged[3]).toEqual(true);
+ expect(ArgsGeometryChanged[4]).toEqual(false);
+ expect(spyOnEndDrawing).toHaveBeenCalled();
+ expect(spyOnEndDrawing.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnEndDrawing.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(2);
+ expect(ArgsEndDrawing[1]).toBe(drawOwner);
+ expect(ArgsGeometryChanged[0][0]).toEqual(ArgsEndDrawing[0]);
+ expect(ArgsEndDrawing[0].features[0].properties.isText).toBe(true);
+ expect(ArgsEndDrawing[0].features[0].properties.valueText).toBe(".");
+ done();
+ });
+ it('test drawend callbacks with Polygon, transformed int feature collection', (done) => {
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnEndDrawing = expect.spyOn(testHandlers, "onEndDrawing");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ features: [null],
+ drawMethod: "Polygon",
+ drawStatus: "drawOrEdit",
+ options: {
+ transformToFeatureCollection: true,
+ stopAfterDrawing: true,
+ drawEnabled: true
+ }
+ });
+ expect(support).toExist();
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.Polygon([[[1300, 4300], [8, 9], [8, 59]]])
+ })
+ });
+ const drawOwner = null;
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnGeometryChanged.calls.length).toBe(1);
+ const ArgsGeometryChanged = spyOnGeometryChanged.calls[0].arguments;
+ expect(ArgsGeometryChanged.length).toBe(5);
+ expect(ArgsGeometryChanged[1]).toBe(drawOwner);
+ expect(ArgsGeometryChanged[2]).toEqual("enterEditMode");
+ expect(ArgsGeometryChanged[3]).toEqual(false);
+ expect(ArgsGeometryChanged[4]).toEqual(false);
+ expect(spyOnEndDrawing).toHaveBeenCalled();
+ expect(spyOnEndDrawing.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnEndDrawing.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(2);
+ expect(ArgsEndDrawing[1]).toBe(drawOwner);
+ expect(ArgsGeometryChanged[0][0]).toEqual(ArgsEndDrawing[0]);
+ expect(ArgsEndDrawing[0].features[0].geometry.coordinates[0].length).toBe(4);
+ done();
+ });
+
+ it('test drawend callbacks with LineString, transformed int feature collection', (done) => {
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnEndDrawing = expect.spyOn(testHandlers, "onEndDrawing");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ features: [null],
+ drawMethod: "LineString",
+ drawStatus: "drawOrEdit",
+ options: {
+ transformToFeatureCollection: true,
+ drawEnabled: true
+ }
+ });
+ expect(support).toExist();
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.LineString([[1300, 4300], [8, 9], [8, 59]])
+ })
+ });
+ const drawOwner = null;
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnGeometryChanged.calls.length).toBe(1);
+ const ArgsGeometryChanged = spyOnGeometryChanged.calls[0].arguments;
+ expect(ArgsGeometryChanged.length).toBe(5);
+ expect(ArgsGeometryChanged[3]).toEqual(false);
+ expect(ArgsGeometryChanged[4]).toEqual(false);
+ expect(spyOnEndDrawing).toHaveBeenCalled();
+ expect(spyOnEndDrawing.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnEndDrawing.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(2);
+ expect(ArgsEndDrawing[1]).toBe(drawOwner);
+ expect(ArgsGeometryChanged[0][0]).toEqual(ArgsEndDrawing[0]);
+ expect(ArgsEndDrawing[0].features[0].geometry.coordinates.length).toBe(3);
+ done();
+ });
+
+ it('test drawend callbacks with Circle, exported as geomColl', (done) => {
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnEndDrawing = expect.spyOn(testHandlers, "onEndDrawing");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ drawMethod: "Circle",
+ drawStatus: "drawOrEdit",
+ features: [geomCollFeature],
+ options: {
+ transformToFeatureCollection: false,
+ drawEnabled: true
+ }
+ });
+ expect(support).toExist();
+ const center = [1300, 4300];
+ const radius = 1000;
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.Circle(center, radius)
+ })
+ });
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnGeometryChanged.calls.length).toBe(1);
+ const ArgsGeometryChanged = spyOnGeometryChanged.calls[0].arguments;
+ expect(ArgsGeometryChanged.length).toBe(5);
+
+ expect(spyOnEndDrawing).toHaveBeenCalled();
+ expect(spyOnEndDrawing.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnEndDrawing.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(2);
+ expect(ArgsEndDrawing[1]).toBe(null);
+ expect(ArgsEndDrawing[0].geometry.type).toBe("GeometryCollection");
+ expect(ArgsEndDrawing[0].geometry.geometries.length).toBe(2);
+
+ done();
+ });
+
+ it('test drawend callbacks with MultiLineString, exported as geomColl', (done) => {
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnEndDrawing = expect.spyOn(testHandlers, "onEndDrawing");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ drawMethod: "MultiLineString",
+ drawStatus: "drawOrEdit",
+ features: [geomCollFeature],
+ options: {
+ transformToFeatureCollection: false,
+ drawEnabled: true
+ }
+ });
+ expect(support).toExist();
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.MultiLineString([[[1300, 4300], [8, 9], [8, 59]]])
+ })
+ });
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnGeometryChanged.calls.length).toBe(1);
+ const ArgsGeometryChanged = spyOnGeometryChanged.calls[0].arguments;
+ expect(ArgsGeometryChanged.length).toBe(5);
+
+ expect(spyOnEndDrawing).toHaveBeenCalled();
+ expect(spyOnEndDrawing.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnEndDrawing.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(2);
+ expect(ArgsEndDrawing[0].geometry.type).toBe("GeometryCollection");
+ expect(ArgsEndDrawing[0].geometry.geometries.length).toBe(2);
+
+ done();
+ });
+
+ it('test drawend callbacks with MultiPoint, exported as geomColl', (done) => {
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnEndDrawing = expect.spyOn(testHandlers, "onEndDrawing");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ drawMethod: "MultiPoint",
+ drawStatus: "drawOrEdit",
+ features: [geomCollFeature],
+ options: {
+ transformToFeatureCollection: false,
+ drawEnabled: true
+ }
+ });
+ expect(support).toExist();
+ support.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.Point([1300, 4300])
+ })
+ });
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnGeometryChanged.calls.length).toBe(1);
+ const ArgsGeometryChanged = spyOnGeometryChanged.calls[0].arguments;
+ expect(ArgsGeometryChanged.length).toBe(5);
+
+ expect(spyOnEndDrawing).toHaveBeenCalled();
+ expect(spyOnEndDrawing.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnEndDrawing.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(2);
+ expect(ArgsEndDrawing[0].geometry.type).toBe("GeometryCollection");
+ expect(ArgsEndDrawing[0].geometry.geometries.length).toBe(2);
+
+ done();
+ });
+ it('test select interaction, retrieving a drawn feature', (done) => {
+ const spyOnSelectFeatures = expect.spyOn(testHandlers, "onSelectFeatures");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ drawMethod: "LineString",
+ drawStatus: "drawOrEdit",
+ features: [geomCollFeature],
+ options: {
+ selected: geomCollFeature,
+ transformToFeatureCollection: false,
+ selectEnabled: true
+ }
+ });
+ expect(support).toExist();
+ const feature = new ol.Feature({
+ geometry: new ol.geom.Point(13.0, 43.0),
+ name: 'My Point'
+ });
+ support.selectInteraction.dispatchEvent({
+ type: 'select',
+ feature: feature
+ });
+ expect(spyOnSelectFeatures).toHaveBeenCalled();
+ done();
+ });
+ it('test modifyend event for modifyInteraction with Circle, exported FeatureCollection', (done) => {
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ drawMethod: "Circle",
+ drawStatus: "drawOrEdit",
+ features: [geomCollFeature],
+ options: {
+ transformToFeatureCollection: true,
+ editEnabled: true
+ }
+ });
+ expect(support).toExist();
+ const center = [1300, 4300];
+ const radius = 1000;
+ support.modifyInteraction.dispatchEvent({
+ type: 'modifyend',
+ features: new ol.Collection(
+ [new ol.Feature({
+ geometry: new ol.geom.Circle(center, radius)
+ })]
+ )
+ });
+ expect(spyOnGeometryChanged).toNotHaveBeenCalled();
+ expect(spyOnDrawingFeatures).toHaveBeenCalled();
+ expect(spyOnDrawingFeatures.calls.length).toBe(1);
+ const ArgsEndDrawing = spyOnDrawingFeatures.calls[0].arguments;
+ expect(ArgsEndDrawing.length).toBe(1);
+
+ done();
+ });
+
+ it('test modifyend event for modifyInteraction with Circle, exported FeatureCollection', (done) => {
+ const spyOnGeometryChanged = expect.spyOn(testHandlers, "onGeometryChanged");
+ const spyOnDrawingFeatures = expect.spyOn(testHandlers, "onDrawingFeatures");
+ let support = renderDrawSupport();
+ support = renderDrawSupport({
+ drawMethod: "Circle",
+ drawStatus: "drawOrEdit",
+ features: [geomCollFeature],
+ options: {
+ transformToFeatureCollection: false,
+ editEnabled: true
+ }
+ });
+ expect(support).toExist();
+ const center = [1300, 4300];
+ const radius = 1000;
+ support.modifyInteraction.dispatchEvent({
+ type: 'modifyend',
+ features: new ol.Collection(
+ [new ol.Feature({
+ geometry: new ol.geom.Circle(center, radius)
+ })]
+ )
+ });
+ expect(spyOnGeometryChanged).toHaveBeenCalled();
+ expect(spyOnDrawingFeatures).toNotHaveBeenCalled();
+
+ done();
+ });
});
diff --git a/web/client/components/map/openlayers/__tests__/LegacyVectorStyle-test.js b/web/client/components/map/openlayers/__tests__/LegacyVectorStyle-test.js
index 852e04d959..06c5175a89 100644
--- a/web/client/components/map/openlayers/__tests__/LegacyVectorStyle-test.js
+++ b/web/client/components/map/openlayers/__tests__/LegacyVectorStyle-test.js
@@ -8,6 +8,8 @@
const expect = require('expect');
const LegacyVectorStyle = require('../LegacyVectorStyle');
const ol = require('openlayers');
+const {geomCollFeature} = require('../../../../test-resources/drawsupport/features');
+const {DEFAULT_ANNOTATIONS_STYLES} = require('../../../../utils/AnnotationsUtils');
describe('Test LegacyVectorStyle', () => {
beforeEach((done) => {
@@ -388,4 +390,26 @@ describe('Test LegacyVectorStyle', () => {
expect(olStroke.getWidth()).toBe(10);
expect(olStroke.getLineDash()).toEqual(['10', '5']);
});
+
+ it('test getStyle with GeometryCollection', () => {
+ const styleFunc = LegacyVectorStyle.getStyle({
+ features: [geomCollFeature],
+ style: {
+ color: "ff0000",
+ opacity: 0.5,
+ ...DEFAULT_ANNOTATIONS_STYLES
+ }
+ }, false, ["textValue"]);
+ expect(styleFunc).toExist();
+
+ const styleGenerated = styleFunc(new ol.Feature({
+ geometry: new ol.geom.GeometryCollection([
+ new ol.geom.LineString([[1, 2], [1, 3]]),
+ new ol.geom.Polygon([[1, 2], [1, 3], [1, 1], [1, 2]]),
+ new ol.geom.Point([1, 20])
+ ])
+ }));
+ expect(styleGenerated).toExist();
+ });
+
});
diff --git a/web/client/components/map/openlayers/__tests__/MeasurementSupport-test.jsx b/web/client/components/map/openlayers/__tests__/MeasurementSupport-test.jsx
index 8bc0978aaf..08fef654f8 100644
--- a/web/client/components/map/openlayers/__tests__/MeasurementSupport-test.jsx
+++ b/web/client/components/map/openlayers/__tests__/MeasurementSupport-test.jsx
@@ -6,17 +6,72 @@
* LICENSE file in the root directory of this source tree.
*/
-var expect = require('expect');
-var React = require('react');
-var ReactDOM = require('react-dom');
-var ol = require('openlayers');
-var MeasurementSupport = require('../MeasurementSupport');
+const expect = require('expect');
+const React = require('react');
+const ReactDOM = require('react-dom');
+const ol = require('openlayers');
+const {round} = require('lodash');
+const MeasurementSupport = require('../MeasurementSupport');
+const {
+ lineFeature,
+ lineFeature3,
+ polyFeatureClosed
+} = require('../../../../test-resources/drawsupport/features');
describe('Openlayers MeasurementSupport', () => {
- var msNode;
- function getMapLayersNum(map) {
- return map.getLayers().getLength();
+ let msNode;
+
+ /* basic objects */
+ const viewOptions = {
+ projection: 'EPSG:3857',
+ center: [0, 0],
+ zoom: 5
+ };
+ let map = new ol.Map({
+ target: "map",
+ view: new ol.View(viewOptions)
+ });
+ const uom = {
+ length: {unit: 'm', label: 'm'},
+ area: {unit: 'sqm', label: 'm²'}
+ };
+
+ const testHandlers = {
+ changeMeasurementState: () => {},
+ updateMeasures: () => {},
+ changeGeometry: () => {}
+ };
+ function getMapLayersNum(olMap) {
+ return olMap.getLayers().getLength();
}
+ /* utility used to render the MeasurementSupport component with some default props*/
+ const renderMeasurement = (props = {}) => {
+ return ReactDOM.render(
+ , msNode);
+ };
+
+ /**
+ * it renders the measure support with draw interaction enabled
+ */
+ const renderWithDrawing = (props = {}) => {
+ let cmp = renderMeasurement();
+ // entering componentWillReceiveProps
+ cmp = renderMeasurement({
+ measurement: {
+ feature: {},
+ geomType: "LineString"
+ },
+ ...props
+ });
+ return cmp;
+ };
beforeEach((done) => {
document.body.innerHTML = '';
@@ -27,104 +82,201 @@ describe('Openlayers MeasurementSupport', () => {
ReactDOM.unmountComponentAtNode(msNode);
document.body.innerHTML = '';
msNode = undefined;
- setTimeout(done);
- });
-
- it('test creation', () => {
- var viewOptions = {
- projection: 'EPSG:3857',
- center: [0, 0],
- zoom: 5
- };
- var map = new ol.Map({
+ expect.restoreSpies();
+ map = new ol.Map({
target: "map",
view: new ol.View(viewOptions)
});
+ setTimeout(done);
+ });
- const cmp = ReactDOM.render(
-
- , msNode);
-
+ it('test creation', () => {
+ const cmp = renderMeasurement();
expect(cmp).toExist();
});
-
it('test if a new layer is added to the map in order to allow drawing.', () => {
- var viewOptions = {
- projection: 'EPSG:3857',
- center: [0, 0],
- zoom: 5
- };
- var map = new ol.Map({
- target: "map",
- view: new ol.View(viewOptions)
- });
-
- let cmp = ReactDOM.render(
-
- , msNode);
+ let cmp = renderMeasurement();
expect(cmp).toExist();
let initialLayersNum = getMapLayersNum(map);
- cmp = ReactDOM.render(
-
- , msNode);
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "LineString",
+ showLabel: true
+ }
+ });
expect(getMapLayersNum(map)).toBeGreaterThan(initialLayersNum);
});
-
it('test if drawing layers will be removed', () => {
- var viewOptions = {
- projection: 'EPSG:3857',
- center: [0, 0],
- zoom: 5
- };
- var map = new ol.Map({
- target: "map",
- view: new ol.View(viewOptions)
- });
-
- let cmp = ReactDOM.render(
-
- , msNode);
+ let cmp = renderMeasurement();
expect(cmp).toExist();
let initialLayersNum = getMapLayersNum(map);
- cmp = ReactDOM.render(
-
- , msNode);
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "Polygon"
+ }
+ });
+
expect(getMapLayersNum(map)).toBeGreaterThan(initialLayersNum);
- cmp = ReactDOM.render(
-
- , msNode);
+ cmp = renderMeasurement();
expect(getMapLayersNum(map)).toBe(initialLayersNum);
});
+ it('test updating distance (LineString) tooltip after change uom', () => {
+ const spyOnChangeMeasurementState = expect.spyOn(testHandlers, "changeMeasurementState");
+ const spyUpdateMeasures = expect.spyOn(testHandlers, "updateMeasures");
+ let cmp = renderWithDrawing();
+ expect(cmp).toExist();
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "LineString",
+ feature: lineFeature,
+ lineMeasureEnabled: true,
+ updatedByUI: true,
+ showLabel: true
+ },
+ uom
+ });
+ expect(spyOnChangeMeasurementState).toNotHaveBeenCalled();
+ expect(spyUpdateMeasures).toHaveBeenCalled();
+ expect(spyUpdateMeasures.calls.length).toBe(1);
+ const measureState = spyUpdateMeasures.calls[0].arguments[0];
+ expect(measureState).toExist();
+ expect(round(measureState.len, 2)).toBe(400787.44);
+ expect(measureState.bearing).toBe(0);
+ expect(measureState.area).toBe(0);
+ expect(measureState.point).toBe(null);
+ });
+ it('test updating Bearing (LineString) tooltip after change uom', () => {
+ const spyUpdateMeasures = expect.spyOn(testHandlers, "updateMeasures");
+ const spyOnChangeMeasurementState = expect.spyOn(testHandlers, "changeMeasurementState");
+ let cmp = renderWithDrawing();
+ expect(cmp).toExist();
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "Bearing",
+ feature: lineFeature,
+ bearingMeasureEnabled: true,
+ updatedByUI: true,
+ showLabel: true
+ },
+ uom
+ });
+ expect(spyOnChangeMeasurementState).toNotHaveBeenCalled();
+ expect(spyUpdateMeasures).toHaveBeenCalled();
+ expect(spyUpdateMeasures.calls.length).toBe(1);
+ const measureState = spyUpdateMeasures.calls[0].arguments[0];
+ expect(measureState).toExist();
+ expect(measureState.len).toBe(0);
+ expect(round(measureState.bearing, 2)).toBe(33.63);
+ expect(measureState.area).toBe(0);
+ expect(measureState.point).toBe(null);
+ });
+ it('test updating area (Polygon) tooltip after change uom', () => {
+ const spyUpdateMeasures = expect.spyOn(testHandlers, "updateMeasures");
+ const spyOnChangeMeasurementState = expect.spyOn(testHandlers, "changeMeasurementState");
+ let cmp = renderWithDrawing();
+ expect(cmp).toExist();
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "Polygon",
+ feature: polyFeatureClosed,
+ areaMeasureEnabled: true,
+ updatedByUI: true,
+ showLabel: false
+ },
+ uom
+ });
+ expect(spyOnChangeMeasurementState).toNotHaveBeenCalled();
+ expect(spyUpdateMeasures).toHaveBeenCalled();
+ expect(spyUpdateMeasures.calls.length).toBe(1);
+ const measureState = spyUpdateMeasures.calls[0].arguments[0];
+ expect(measureState).toExist();
+ expect(round(measureState.area, 2)).toBe(49490132941.51);
+ expect(measureState.bearing).toBe(0);
+ });
+
+ it('test drawInteraction callbacks for a distance (LineString)', () => {
+ const spyOnChangeMeasurementState = expect.spyOn(testHandlers, "changeMeasurementState");
+ const spyUpdateMeasures = expect.spyOn(testHandlers, "updateMeasures");
+ const spyOnChangeGeometry = expect.spyOn(testHandlers, "changeGeometry");
+ let cmp = renderWithDrawing();
+ expect(cmp).toExist();
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "LineString",
+ feature: lineFeature,
+ lineMeasureEnabled: true,
+ updatedByUI: false,
+ showLabel: true
+ },
+ uom
+ });
+ cmp.drawInteraction.dispatchEvent({
+ type: 'drawstart',
+ feature: new ol.Feature({
+ geometry: new ol.geom.LineString([[13.0, 43.0], [13.0, 40.0]]),
+ name: 'My line with 2 points'
+ })
+ });
+ cmp.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.LineString([[13.0, 43.0], [13.0, 40.0], [11.0, 41.0]]),
+ name: 'My line with 3 points'
+ })
+ });
+ expect(spyOnChangeMeasurementState).toNotHaveBeenCalled();
+ expect(spyUpdateMeasures).toNotHaveBeenCalled();
+ expect(spyOnChangeGeometry).toHaveBeenCalled();
+ const changedFeature = spyOnChangeGeometry.calls[0].arguments[0];
+ expect(changedFeature.type).toBe("Feature");
+ expect(changedFeature.geometry.coordinates.length).toBe(3);
+
+ });
+ it('test drawing a distance (LineString) and moving pointer', () => {
+ let cmp = renderWithDrawing();
+ expect(cmp).toExist();
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "LineString",
+ feature: lineFeature,
+ lineMeasureEnabled: true,
+ updatedByUI: true,
+ showLabel: true
+ },
+ uom
+ });
+ cmp.drawInteraction.dispatchEvent({
+ type: 'drawstart',
+ feature: new ol.Feature({
+ geometry: new ol.geom.LineString([[13.0, 43.0], [13.0, 40.0]]),
+ name: 'My line with 2 points'
+ })
+ });
+ cmp.drawInteraction.dispatchEvent({
+ type: 'drawend',
+ feature: new ol.Feature({
+ geometry: new ol.geom.LineString([[13.0, 43.0], [13.0, 40.0], [11.0, 41.0]]),
+ name: 'My line with 3 points'
+ })
+ });
+ cmp = renderMeasurement({
+ measurement: {
+ geomType: "LineString",
+ feature: lineFeature3,
+ lineMeasureEnabled: true,
+ updatedByUI: true,
+ showLabel: true
+ },
+ uom
+ });
+ map.dispatchEvent({
+ type: 'pointermove',
+ coordinate: [100, 400]
+ });
+ expect(cmp.helpTooltip.getPosition()).toEqual([100, 400]);
+
+ });
+
});
diff --git a/web/client/components/map/openlayers/__tests__/Overview-test.jsx b/web/client/components/map/openlayers/__tests__/Overview-test.jsx
index c723461ccc..949c75777c 100644
--- a/web/client/components/map/openlayers/__tests__/Overview-test.jsx
+++ b/web/client/components/map/openlayers/__tests__/Overview-test.jsx
@@ -5,11 +5,11 @@
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
-var expect = require('expect');
-var React = require('react');
-var ReactDOM = require('react-dom');
-var ol = require('openlayers');
-var Overview = require('../Overview');
+const expect = require('expect');
+const React = require('react');
+const ReactDOM = require('react-dom');
+const ol = require('openlayers');
+const Overview = require('../Overview');
describe('Openlayers Overview component', () => {
@@ -46,4 +46,28 @@ describe('Openlayers Overview component', () => {
const overview = domMap.getElementsByClassName('ol-overviewmap');
expect(overview.length).toBe(1);
});
+
+ it('testing mouse events', () => {
+ const ov = ReactDOM.render(, document.getElementById("container"));
+ expect(ov).toExist();
+ const domMap = map.getViewport();
+ const overview = domMap.getElementsByClassName('ol-overviewmap');
+ expect(overview.length).toBe(1);
+ ov.box.onmousedown({
+ pageX: 1,
+ pageY: 1
+ });
+ ov.box.onmousemove({
+ pageX: 3,
+ pageY: 3,
+ stopPropagation: () => {},
+ preventDefault: () => {}
+ });
+ ov.box.onmouseup({
+ pageX: 3,
+ pageY: 3
+ });
+ expect(ov.box.onmouseup).toBe(null);
+ expect(ov.box.onmousemove).toBe(null);
+ });
});
diff --git a/web/client/components/mapcontrols/annotations/CoordinatesEditor.jsx b/web/client/components/mapcontrols/annotations/CoordinatesEditor.jsx
index 8514b5e200..5a314b4f75 100644
--- a/web/client/components/mapcontrols/annotations/CoordinatesEditor.jsx
+++ b/web/client/components/mapcontrols/annotations/CoordinatesEditor.jsx
@@ -70,9 +70,9 @@ class CoordinateEditor extends React.Component {
"Polygon": {min: 3, add: true, remove: true, validation: "validateCoordinates", notValid: "annotations.editor.notValidPolyline"},
"LineString": {min: 2, add: true, remove: true, validation: "validateCoordinates", notValid: "annotations.editor.notValidPolyline"},
"MultiPoint": {min: 2, add: true, remove: true, validation: "validateCoordinates", notValid: "annotations.editor.notValidPolyline"},
- "Point": {min: 1, add: false, remove: false, validation: "validateCoordinates", notValid: "annotations.editor.notValidMarker"},
- "Circle": {add: false, remove: false, validation: "validateCircle", notValid: "annotations.editor.notValidCircle"},
- "Text": {add: false, remove: false, validation: "validateText", notValid: "annotations.editor.notValidText"}
+ "Point": {min: 1, max: 1, add: true, remove: false, validation: "validateCoordinates", notValid: "annotations.editor.notValidMarker"},
+ "Circle": {min: 1, max: 1, add: true, remove: false, validation: "validateCircle", notValid: "annotations.editor.notValidCircle"},
+ "Text": {min: 1, max: 1, add: true, remove: false, validation: "validateText", notValid: "annotations.editor.notValidText"}
},
transitionProps: {
transitionName: "switch-panel-transition",
@@ -191,6 +191,9 @@ class CoordinateEditor extends React.Component {
onClick: () => {
let tempComps = [...this.props.components];
tempComps = tempComps.concat([{lat: "", lon: ""}]);
+ if (this.props.type === "Polygon") {
+ tempComps = this.addCoordPolygon(tempComps);
+ }
this.props.onChange(tempComps, this.props.properties.radius, this.props.properties.valueText);
}
}
@@ -211,13 +214,13 @@ class CoordinateEditor extends React.Component {
{this.props.type === "Circle" && this.renderCircle()}
{this.props.type === "Text" && this.renderText()}
-
-
- {
- this.props.type === "Circle" && Center
- }
-
-
+ {
+ this.props.type === "Circle" &&
+
+
+
+
+ }
{!(!this.props.components || this.props.components.length === 0) &&
@@ -228,7 +231,7 @@ class CoordinateEditor extends React.Component {
}
-
+
{this.props.components.map((component, idx) => {
if (this.props.isMouseEnterEnabled || this.props.type === "LineString" || this.props.type === "Polygon" || this.props.type === "MultiPoint") {
@@ -294,12 +297,14 @@ class CoordinateEditor extends React.Component {
);
}
- validateCoordinates = (components = this.props.components, remove = false) => {
+ validateCoordinates = (components = this.props.components, remove = false, idx) => {
if (components && components.length) {
const validComponents = components.filter(validateCoords);
if (remove) {
- return validComponents.length > this.props.componentsValidation[this.props.type].min;
+ return validComponents.length > this.props.componentsValidation[this.props.type].min ||
+ // if there are at least the min number of valid points, then you can delete the other invalid ones
+ validComponents.length >= this.props.componentsValidation[this.props.type].min && !validateCoords(components[idx]);
}
return validComponents.length >= this.props.componentsValidation[this.props.type].min;
}
@@ -325,7 +330,7 @@ class CoordinateEditor extends React.Component {
addCoordPolygon = (components) => {
if (this.props.type === "Polygon") {
const validComponents = components.filter(validateCoords);
- return components.concat([validComponents[0]]);
+ return components.concat([validComponents.length ? validComponents[0] : {lat: "", lon: ""}]);
}
return components;
}
diff --git a/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx b/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx
index e8b499beb1..ba74a527a2 100644
--- a/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx
+++ b/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx
@@ -12,40 +12,53 @@ const React = require('react');
const uuidv1 = require('uuid/v1');
const assign = require('object-assign');
-const getAnnotationStyle = (type, defaultStyle = DEFAULT_ANNOTATIONS_STYLES) => {
- return assign({}, defaultStyle[type], {type});
-};
const DropdownButtonT = tooltip(DropdownButton);
-const DropdownFeatureType = ({onClick = () => {}, onStartDrawing = () => {}, onAddText = () => {}, onSetStyle = () => {}, bsStyle = "primary", ...props} = {}) => (
- } disabled={!!props.disabled} noCaret>
+const DropdownFeatureType = ({
+ onClick = () => {},
+ onStartDrawing = () => {},
+ onAddText = () => {},
+ onSetStyle = () => {},
+ titles = {},
+ glyph = "",
+ bsStyle = "primary",
+ ...props
+} = {}) => (
+ }
+ disabled={!!props.disabled}
+ noCaret>
);
diff --git a/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js b/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js
index 11a0384bad..2180f6998e 100644
--- a/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js
+++ b/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright 2015-2016, GeoSolutions Sas.
* All rights reserved.
*
diff --git a/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js b/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js
index 4b19de324d..4d68f2e555 100644
--- a/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js
+++ b/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js
@@ -9,8 +9,8 @@ const expect = require('expect');
const React = require('react');
const ReactDOM = require('react-dom');
-const AnnotationsEditor = require('../AnnotationsEditor');
+const AnnotationsEditor = require('../AnnotationsEditor');
const TestUtils = require('react-dom/test-utils');
const actions = {
onChangeProperties: () => {},
diff --git a/web/client/components/mapcontrols/annotations/__tests__/CoordinatesEditor-test.js b/web/client/components/mapcontrols/annotations/__tests__/CoordinatesEditor-test.js
new file mode 100644
index 0000000000..fcc5d8b106
--- /dev/null
+++ b/web/client/components/mapcontrols/annotations/__tests__/CoordinatesEditor-test.js
@@ -0,0 +1,716 @@
+/*
+ * 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 expect = require('expect');
+
+const React = require('react');
+const ReactDOM = require('react-dom');
+const CoordinatesEditor = require('../CoordinatesEditor');
+const TestUtils = require('react-dom/test-utils');
+
+const testHandlers = {
+ onChange: () => {},
+ onHighlightPoint: () => {},
+ onChangeRadius: () => {},
+ onChangeText: () => {},
+ onSetInvalidSelected: () => {}
+};
+
+describe("test the CoordinatesEditor Panel", () => {
+ beforeEach((done) => {
+ document.body.innerHTML = '';
+ setTimeout(done);
+ });
+
+ afterEach((done) => {
+ ReactDOM.unmountComponentAtNode(document.getElementById("container"));
+ document.body.innerHTML = '';
+ setTimeout(done);
+ expect.restoreSpies();
+ });
+
+ it('CoordinatesEditor rendering with defaults', () => {
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+ });
+
+ it('CoordinatesEditor as marker editor with base input coordinates', () => {
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const spans = TestUtils.scryRenderedDOMComponentsWithTag(editor, "span");
+ expect(spans).toExist();
+ expect(spans[0].innerText).toBe("annotations.editor.title.Point");
+
+ const exclamationMark = TestUtils.findRenderedDOMComponentWithClass(editor, "glyphicon-exclamation-mark");
+ expect(exclamationMark).toExist();
+
+ const format = TestUtils.findRenderedDOMComponentWithClass(editor, "glyphicon-cog");
+ expect(format).toExist();
+
+ const plus = TestUtils.scryRenderedDOMComponentsWithClass(editor, "glyphicon-plus");
+ expect(plus.length).toBe(0);
+ });
+
+ it('CoordinatesEditor as Polygon editor, valid input coordinate, changing coords', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }, {
+ lat: 6,
+ lon: 6
+ }, {
+ lat: 6,
+ lon: 6
+ }];
+
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const input = inputs[0];
+ input.value = 15;
+ TestUtils.Simulate.change(input);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith({ lat: 15, lon: 10 });
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: 15, lon: 10 },
+ {lat: 6, lon: 6 },
+ {lat: 6, lon: 6 },
+ { lat: 15, lon: 10 }
+ ], undefined, undefined);
+
+ input.value = "";
+ TestUtils.Simulate.change(input);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalledWith("coords", [[10, "" ], [6, 6 ], [6, 6]]);
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: "", lon: 10 },
+ { lat: 6, lon: 6 },
+ { lat: 6, lon: 6 },
+ { lat: "", lon: 10 }
+ ], undefined, undefined);
+ });
+
+ it('CoordinatesEditor as LineString editor, valid input coordinate, changing coords', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }, {
+ lat: 6,
+ lon: 6
+ }];
+
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const input = inputs[0];
+ input.value = 15;
+ TestUtils.Simulate.change(input);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith({ lat: 15, lon: 10 });
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: 15, lon: 10 },
+ {lat: 6, lon: 6 }
+ ], undefined, undefined);
+
+ input.value = "";
+ TestUtils.Simulate.change(input);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalledWith("coords", [[10, "" ], [6, 6 ]]);
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: "", lon: 10 },
+ {lat: 6, lon: 6 }
+ ], undefined, undefined);
+ });
+
+ it('CoordinatesEditor as Circle editor, valid input coordinate, changing coords, isMouseLeaveEnabled=true', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }];
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputRadius = inputs[0];
+ inputRadius.value = 1000;
+ const inputCoord = inputs[1];
+ inputCoord.value = 15;
+ TestUtils.Simulate.change(inputCoord);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith({ lat: 15, lon: 10 });
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: 15, lon: 10 }
+ ], 1000, undefined);
+
+ inputCoord.value = "";
+ TestUtils.Simulate.change(inputCoord);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith(null);
+ expect(spyOnSetInvalidSelected).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalledWith("coords", [[10, "" ]]);
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: "", lon: 10 }
+ ], 1000, undefined);
+ });
+
+ it('CoordinatesEditor as Circle editor, valid input coordinate, changing coords, isMouseLeaveEnabled=false', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }];
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputRadius = inputs[0];
+ inputRadius.value = 1000;
+ const inputCoord = inputs[1];
+
+ inputCoord.value = "";
+ TestUtils.Simulate.change(inputCoord);
+ expect(spyOnHighlightPoint).toNotHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalledWith("coords", [[10, "" ]]);
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([{ lat: "", lon: 10 }], 1000, undefined);
+ });
+
+ it('CoordinatesEditor as Circle editor, valid input coordinate, changing radius with valid value', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }];
+ const spyOnChangeRadius = expect.spyOn(testHandlers, "onChangeRadius");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputRadius = inputs[0];
+ inputRadius.value = 10000;
+ TestUtils.Simulate.change(inputRadius);
+ expect(spyOnChangeRadius).toHaveBeenCalled();
+ expect(spyOnChangeRadius).toHaveBeenCalledWith(10000, [[10, 10]]);
+ expect(spyOnSetInvalidSelected).toNotHaveBeenCalled();
+ });
+
+
+ it('CoordinatesEditor as Circle editor, valid input coordinate, changing radius, invalid center', () => {
+ const components = [{
+ lat: "",
+ lon: ""
+ }];
+ const spyOnChangeRadius = expect.spyOn(testHandlers, "onChangeRadius");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputRadius = inputs[0];
+ inputRadius.value = 10000;
+ TestUtils.Simulate.change(inputRadius);
+ expect(spyOnChangeRadius).toHaveBeenCalled();
+ expect(spyOnChangeRadius).toHaveBeenCalledWith(10000, []);
+ expect(spyOnSetInvalidSelected).toNotHaveBeenCalled();
+ });
+
+
+ it('CoordinatesEditor as Circle editor, valid input coordinate, changing invalid radius, invalid center', () => {
+ const components = [{
+ lat: "",
+ lon: ""
+ }];
+ const spyOnChangeRadius = expect.spyOn(testHandlers, "onChangeRadius");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputRadius = inputs[0];
+ inputRadius.value = "";
+ TestUtils.Simulate.change(inputRadius);
+ expect(spyOnChangeRadius).toHaveBeenCalled();
+ expect(spyOnChangeRadius).toHaveBeenCalledWith(null, [["", ""]]);
+ expect(spyOnSetInvalidSelected).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalledWith("radius", [["", ""]]);
+ });
+
+ it('CoordinatesEditor as Text editor, valid input coordinate, changing coords, isMouseLeaveEnabled=true', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }];
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const spyOnChangeText = expect.spyOn(testHandlers, "onChangeText");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputText = inputs[0];
+ inputText.value = "myTextAnnotation";
+ const inputCoord = inputs[1];
+ inputCoord.value = 15;
+ TestUtils.Simulate.change(inputCoord);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith({ lat: 15, lon: 10 });
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChangeText).toNotHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: 15, lon: 10 }
+ ], undefined, "myTextAnnotation");
+
+ inputCoord.value = "";
+ TestUtils.Simulate.change(inputCoord);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith(null);
+ expect(spyOnSetInvalidSelected).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalledWith("coords", [[10, "" ]]);
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnChangeText).toNotHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalledWith([
+ { lat: "", lon: 10 }
+ ], undefined, "myTextAnnotation");
+ });
+
+ it('CoordinatesEditor as Text editor, valid input coordinate, changing text, isMouseLeaveEnabled=true', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }];
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const spyOnChangeText = expect.spyOn(testHandlers, "onChangeText");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputText = inputs[0];
+ inputText.value = "my new Text Annotation";
+ TestUtils.Simulate.change(inputText);
+
+ expect(spyOnHighlightPoint).toNotHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toNotHaveBeenCalled();
+ expect(spyOnChange).toNotHaveBeenCalled();
+ expect(spyOnChangeText).toHaveBeenCalled();
+ expect(spyOnChangeText).toHaveBeenCalledWith("my new Text Annotation", [[10, 10]]);
+ });
+
+
+ it('CoordinatesEditor as Text editor, valid input coordinate, changing text, invalid point', () => {
+ const components = [{
+ lat: "",
+ lon: ""
+ }];
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const spyOnChangeText = expect.spyOn(testHandlers, "onChangeText");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputText = inputs[0];
+ inputText.value = "my new Text Annotation";
+ TestUtils.Simulate.change(inputText);
+
+ expect(spyOnHighlightPoint).toNotHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toNotHaveBeenCalled();
+ expect(spyOnChange).toNotHaveBeenCalled();
+ expect(spyOnChangeText).toHaveBeenCalled();
+ expect(spyOnChangeText).toHaveBeenCalledWith("my new Text Annotation", [["", ""]]);
+ });
+
+
+ it('CoordinatesEditor as Text editor, valid input coordinate, changing with invalid text, invalid point', () => {
+ const components = [{
+ lat: "",
+ lon: ""
+ }];
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const spyOnChangeText = expect.spyOn(testHandlers, "onChangeText");
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(editor, "input");
+ expect(inputs).toExist();
+ const inputText = inputs[0];
+ inputText.value = "";
+ TestUtils.Simulate.change(inputText);
+
+ expect(spyOnHighlightPoint).toNotHaveBeenCalled();
+ expect(spyOnChange).toNotHaveBeenCalled();
+ expect(spyOnChangeText).toHaveBeenCalled();
+ expect(spyOnChangeText).toHaveBeenCalledWith("", [["", ""]]);
+ expect(spyOnSetInvalidSelected).toHaveBeenCalled();
+ expect(spyOnSetInvalidSelected).toHaveBeenCalledWith("text", [["", ""]]);
+ });
+
+ it('CoordinatesEditor as LineString editor, valid input coordinate, mouse enter/leave', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }, {
+ lat: 6,
+ lon: 6
+ }];
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const rows = TestUtils.scryRenderedDOMComponentsWithClass(editor, "coordinateRow");
+ const firstRow = rows[0];
+ TestUtils.Simulate.mouseEnter(firstRow);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith({lat: 10, lon: 10});
+ TestUtils.Simulate.mouseLeave(firstRow);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith(null);
+ });
+
+ it('CoordinatesEditor as LineString editor, 3 valid input coordinate, remove first row', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }, {
+ lat: 8,
+ lon: 8
+ }, {
+ lat: 6,
+ lon: 6
+ }];
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ let buttons = TestUtils.scryRenderedDOMComponentsWithTag(editor, "button");
+ let firstDelButton = buttons[3];
+ TestUtils.Simulate.click(firstDelButton);
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith({ lat: 8, lon: 8 });
+ });
+
+ it('CoordinatesEditor as LineString editor, 2 valid input coordinate, cannot remove first row trash disabled', () => {
+ const components = [{
+ lat: 10,
+ lon: 10
+ }, {
+ lat: 6,
+ lon: 6
+ }];
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ let buttons = TestUtils.scryRenderedDOMComponentsWithTag(editor, "button");
+ let firstDelButton = buttons[3];
+ TestUtils.Simulate.click(firstDelButton);
+ expect(spyOnHighlightPoint).toNotHaveBeenCalled();
+ expect(firstDelButton.disabled).toBe(true);
+ });
+
+ it('CoordinatesEditor as LineString editor, 4 rows, remove first invalid row', () => {
+ const components = [{
+ lat: "",
+ lon: ""
+ }, {
+ lat: 8,
+ lon: 8
+ }, {
+ lat: 8,
+ lon: 8
+ }, {
+ lat: 6,
+ lon: 6
+ }];
+ const spyOnSetInvalidSelected = expect.spyOn(testHandlers, "onSetInvalidSelected");
+ const spyOnHighlightPoint = expect.spyOn(testHandlers, "onHighlightPoint");
+ const spyOnChange = expect.spyOn(testHandlers, "onChange");
+
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ let buttons = TestUtils.scryRenderedDOMComponentsWithTag(editor, "button");
+ let firstDelButton = buttons[3];
+ TestUtils.Simulate.click(firstDelButton);
+ expect(spyOnSetInvalidSelected).toNotHaveBeenCalled();
+ expect(spyOnChange).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalled();
+ expect(spyOnHighlightPoint).toHaveBeenCalledWith({ lat: 8, lon: 8 });
+ });
+
+ it('CoordinatesEditor as LineString, 4 rows, only invalid rows are not disabled', () => {
+ const components = [{
+ lat: 5,
+ lon: ""
+ }, {
+ lat: 8,
+ lon: 8
+ }, {
+ lat: 8,
+ lon: 8
+ },
+ {
+ lat: "",
+ lon: ""
+ }];
+
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const buttons = TestUtils.scryRenderedDOMComponentsWithTag(editor, "button");
+ expect(buttons.length).toBe(7);
+ expect(buttons[3].disabled).toBe(false);
+ expect(buttons[4].disabled).toBe(true);
+ expect(buttons[5].disabled).toBe(true);
+ expect(buttons[6].disabled).toBe(false);
+ });
+ it('CoordinatesEditor as Polygon, 5 rows, only invalid rows are not disabled', () => {
+ const components = [{
+ lat: 5,
+ lon: ""
+ }, {
+ lat: 7,
+ lon: 7
+ }, {
+ lat: 8,
+ lon: 8
+ }, {
+ lat: 6,
+ lon: 6
+ },
+ {
+ lat: "",
+ lon: ""
+ }];
+
+ const editor = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(editor).toExist();
+
+ const buttons = TestUtils.scryRenderedDOMComponentsWithTag(editor, "button");
+ expect(buttons.length).toBe(8);
+ expect(buttons[3].disabled).toBe(false);
+ expect(buttons[4].disabled).toBe(true);
+ expect(buttons[5].disabled).toBe(true);
+ expect(buttons[6].disabled).toBe(true);
+ expect(buttons[7].disabled).toBe(false);
+ });
+
+});
diff --git a/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js b/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js
new file mode 100644
index 0000000000..271d2d7872
--- /dev/null
+++ b/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js
@@ -0,0 +1,123 @@
+/*
+ * 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 expect = require('expect');
+
+const React = require('react');
+const ReactDOM = require('react-dom');
+const DropdownFeatureType = require('../DropdownFeatureType');
+
+const titles = {
+ marker: "marker",
+ line: "line",
+ polygon: "polygon",
+ circle: "circle",
+ text: "text"
+};
+
+const testSpies = (spies, button) => {
+ expect(button).toExist();
+ button.click();
+ spies.forEach(spy => {
+ expect(spy).toHaveBeenCalled();
+ });
+};
+
+const resetSpies = (spies) => {
+ spies.forEach(spy => {
+ spy.restore();
+ });
+};
+
+describe("test the DropdownFeatureType Panel", () => {
+ beforeEach((done) => {
+ document.body.innerHTML = '';
+ setTimeout(done);
+ });
+
+ afterEach((done) => {
+ ReactDOM.unmountComponentAtNode(document.getElementById("container"));
+ document.body.innerHTML = '';
+ setTimeout(done);
+ });
+
+ it('DropdownFeatureType rendering with defaults', () => {
+ ReactDOM.render(
+ , document.getElementById("container")
+ );
+ const items = document.getElementsByTagName("li");
+ expect(items).toExist();
+ expect(items.length).toBe(5);
+ const spans = document.getElementsByTagName("span");
+ expect(spans).toExist();
+ expect(spans.length).toBe(6);
+ expect(spans[0].className).toBe("glyphicon glyphicon-pencil-add");
+ expect(spans[1].className).toBe("glyphicon glyphicon-point");
+ expect(spans[2].className).toBe("glyphicon glyphicon-line");
+ expect(spans[3].className).toBe("glyphicon glyphicon-polygon");
+ expect(spans[4].className).toBe("glyphicon glyphicon-text-colour");
+ expect(spans[5].className).toBe("glyphicon glyphicon-1-circle");
+ });
+
+ it('DropdownFeatureType testing the actions', () => {
+
+ const testHandlers = {
+ onClick: () => {},
+ onStartDrawing: () => {},
+ onSetStyle: () => {},
+ onAddText: () => {}
+ };
+
+ const spyOnClick = expect.spyOn(testHandlers, 'onClick');
+ const spyOnSetStyle = expect.spyOn(testHandlers, 'onSetStyle');
+ const spyOnStartDrawing = expect.spyOn(testHandlers, 'onStartDrawing');
+ const spyOnAddText = expect.spyOn(testHandlers, 'onAddText');
+
+ const spies = [spyOnClick, spyOnSetStyle, spyOnStartDrawing];
+ ReactDOM.render(
+ , document.getElementById("container")
+ );
+ const buttons = document.getElementsByTagName("a");
+
+ const marker = buttons[0];
+ testSpies(spies, marker);
+ expect(spyOnClick).toHaveBeenCalledWith("Point");
+ resetSpies(spies);
+
+ const line = buttons[1];
+ testSpies(spies, line);
+ expect(spyOnClick).toHaveBeenCalledWith("LineString");
+ resetSpies(spies);
+
+ const polygon = buttons[2];
+ testSpies(spies, polygon);
+ expect(spyOnClick).toHaveBeenCalledWith("Polygon");
+ resetSpies(spies);
+
+ const text = buttons[3];
+ testSpies([...spies, spyOnAddText], text);
+ expect(spyOnClick).toHaveBeenCalledWith("Text");
+ resetSpies(spies);
+
+ const circle = buttons[4];
+ testSpies(spies, circle);
+ expect(spyOnClick).toHaveBeenCalledWith("Circle");
+ resetSpies(spies);
+ });
+});
diff --git a/web/client/components/mapcontrols/annotations/__tests__/MeasureEditor-test.js b/web/client/components/mapcontrols/annotations/__tests__/MeasureEditor-test.js
index 215ba1d6a3..e618f3f466 100644
--- a/web/client/components/mapcontrols/annotations/__tests__/MeasureEditor-test.js
+++ b/web/client/components/mapcontrols/annotations/__tests__/MeasureEditor-test.js
@@ -1,3 +1,10 @@
+/*
+ * 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 ReactTestUtils = require('react-dom/test-utils');
diff --git a/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js b/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js
index c987abbdb7..b42814fe00 100644
--- a/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js
+++ b/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright 2018, GeoSolutions Sas.
* All rights reserved.
*
@@ -12,7 +12,6 @@ const ReactDOM = require('react-dom');
const SelectAnnotationsFile = require('../SelectAnnotationsFile');
-
describe("test the SelectAnnotationsFile modal", () => {
beforeEach((done) => {
document.body.innerHTML = '';
diff --git a/web/client/components/mapcontrols/measure/MeasureComponent.jsx b/web/client/components/mapcontrols/measure/MeasureComponent.jsx
index f7f5a0dfe7..00c54adadb 100644
--- a/web/client/components/mapcontrols/measure/MeasureComponent.jsx
+++ b/web/client/components/mapcontrols/measure/MeasureComponent.jsx
@@ -9,7 +9,7 @@ const PropTypes = require('prop-types');
const React = require('react');
const {DropdownList} = require('react-widgets');
const {ButtonToolbar, Tooltip, Glyphicon, Grid, Row, Col, FormGroup} = require('react-bootstrap');
-const {isEqual, round, get, dropRight} = require('lodash');
+const {isEqual, round, get} = require('lodash');
const NumberFormat = require('../../I18N/Number');
const Message = require('../../I18N/Message');
@@ -253,9 +253,6 @@ class MeasureComponent extends React.Component {
render() {
const geomType = (get(this.props.measurement, 'feature.geometry.type') || '').toLowerCase();
let coords = (get(this.props.measurement, geomType.indexOf('polygon') !== -1 ? 'feature.geometry.coordinates[0]' : 'feature.geometry.coordinates') || []).map(coordinate => ({lon: coordinate[0], lat: coordinate[1]}));
- if (geomType.indexOf('polygon') !== -1) {
- coords = dropRight(coords);
- }
return (
{
const coordEditorPanel = TestUtils.findRenderedDOMComponentWithClass(cmp, 'ms2-border-layout-body');
expect(coordEditorPanel).toExist();
});
+
+ it('rendering a coordinate editor for Polygons with 4 empty rows', () => {
+ let measurement = {
+ lineMeasureEnabled: false,
+ areaMeasureEnabled: true,
+ bearingMeasureEnabled: false,
+ geomType: 'Polygon',
+ feature: {
+ type: "Feature",
+ geometry: {
+ type: "Polygon",
+ coordinates: [[["", ""], ["", ""], ["", ""], ["", ""]]]
+ },
+ properties: {}
+ },
+ len: 0,
+ area: 0,
+ bearing: 0
+ };
+ let cmp = ReactDOM.render(
+ , document.getElementById("container")
+ );
+ expect(cmp).toExist();
+ const coordEditorPanel = TestUtils.findRenderedDOMComponentWithClass(cmp, 'ms2-border-layout-body');
+ const coordinateRows = TestUtils.scryRenderedDOMComponentsWithClass(cmp, 'coordinateRow');
+ expect(coordEditorPanel).toExist();
+ expect(coordinateRows.length).toBe(4);
+
+ });
});
diff --git a/web/client/components/mapcontrols/measure/measure.css b/web/client/components/mapcontrols/measure/measure.css
index 4f96570d85..6cc4531db9 100644
--- a/web/client/components/mapcontrols/measure/measure.css
+++ b/web/client/components/mapcontrols/measure/measure.css
@@ -23,12 +23,12 @@
}
.measure-value {
+ /* this is necessary to show the uom list correctly,
+ * otherwise the list will be hidden since it exceeds the modal
+ */
font-family: Menlo, Monaco, Consolas, Courier New, monospace;
}
-{
-/* this is necessary to show the uom list correctly,
- * otherwise the list will be hidden since it exceeds the modal
- */}
+
#measure .modal-body > div[role="body"] > div {
overflow: visible!important;
}
diff --git a/web/client/components/misc/coordinateeditors/CoordinatesRow.jsx b/web/client/components/misc/coordinateeditors/CoordinatesRow.jsx
index 540fd55922..ebbfe5e550 100644
--- a/web/client/components/misc/coordinateeditors/CoordinatesRow.jsx
+++ b/web/client/components/misc/coordinateeditors/CoordinatesRow.jsx
@@ -50,10 +50,14 @@ class CoordinatesRow extends React.Component {
return (
{
- if (this.props.onMouseEnter) {
+ if (this.props.onMouseEnter && this.props.component.lat && this.props.component.lon) {
this.props.onMouseEnter(this.props.component);
}
- }} onMouseLeave={this.props.onMouseLeave}>
+ }} onMouseLeave={() => {
+ if (this.props.component.lat && this.props.component.lon) {
+ this.props.onMouseLeave();
+ }
+ }}>
{this.props.isDraggable ? this.props.connectDragSource(dragButton) : dragButton}
diff --git a/web/client/components/misc/enhancers/draggableContainer.jsx b/web/client/components/misc/enhancers/draggableContainer.jsx
index f2a9f9efc8..5953ac7744 100644
--- a/web/client/components/misc/enhancers/draggableContainer.jsx
+++ b/web/client/components/misc/enhancers/draggableContainer.jsx
@@ -8,7 +8,7 @@ module.exports = compose(
dragDropContext(html5Backend),
branch(
({isDraggable = true}) => isDraggable,
- Component => ({onSort, isDraggable, items, ...props}) => {
+ Component => ({onSort, isDraggable, items = [], ...props}) => {
const draggableItems = items.map((item, sortId) => ({...item, onSort, isDraggable, sortId, key: sortId}));
return ;
}
diff --git a/web/client/components/misc/enhancers/tooltip.jsx b/web/client/components/misc/enhancers/tooltip.jsx
index a88c7bbcfd..ecc25170c1 100644
--- a/web/client/components/misc/enhancers/tooltip.jsx
+++ b/web/client/components/misc/enhancers/tooltip.jsx
@@ -10,7 +10,7 @@ const {branch} = require('recompose');
const { Tooltip } = require('react-bootstrap');
const OverlayTrigger = require('../OverlayTrigger');
const Message = require('../../I18N/Message');
-
+const {omit} = require('lodash');
/**
* Tooltip enhancer. Enhances an object adding a tooltip (with i18n support).
* It is applied only if props contains `tooltip` or `tooltipId`. It have to be applied to a React (functional) component
@@ -34,4 +34,7 @@ module.exports = branch(
trigger={tooltipTrigger}
key={keyProp}
placement={tooltipPosition}
- overlay={{tooltipId ? : tooltip}}>));
+ overlay={{tooltipId ? : tooltip}}>),
+ // avoid to pass non needed props
+ (Wrapped) => (props) => {props.children}
+);
diff --git a/web/client/epics/__tests__/annotations-test.js b/web/client/epics/__tests__/annotations-test.js
index 6353182f75..38927ae692 100644
--- a/web/client/epics/__tests__/annotations-test.js
+++ b/web/client/epics/__tests__/annotations-test.js
@@ -47,6 +47,141 @@ const ft = {
}
};
+
+const annotationsLayerWithTextFeature = {
+ "flat": [
+ {
+ "id": "annotations",
+ "features": [
+ {
+ type: "FeatureCollection",
+ features: [{
+ "properties": {
+ "id": "1",
+ isText: true,
+ valueText: "my text"
+ },
+ "type": "Feature",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ 1,
+ 1
+ ]
+ }
+ }],
+ style: {
+ type: "Text",
+ id: "id.1.text.5",
+ "Text": {
+ color: "#FF0000",
+ font: "Arial 14px",
+ label: "my text"
+ }
+ }
+ }
+ ]
+ }
+ ]
+};
+
+const annotationsLayerWithCircleFeature = {
+ "flat": [
+ {
+ "id": "annotations",
+ "features": [
+ {
+ type: "FeatureCollection",
+ features: [{
+ "properties": {
+ "id": "1",
+ isCircle: true,
+ center: []
+ },
+ "type": "Feature",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ 1,
+ 1
+ ]
+ }
+ }],
+ style: {
+ type: "Circle",
+ id: "id.1.2.3.4.5",
+ "Circle": {
+ color: "#FF0000"
+ }
+ }
+ }
+ ]
+ }
+ ]
+};
+const annotationsLayerWithLineStringFeature = {
+ "flat": [
+ {
+ "id": "annotations",
+ "features": [
+ {
+ type: "FeatureCollection",
+ features: [{
+ "properties": {
+ "id": "1"
+ },
+ "type": "Feature",
+ "geometry": {
+ "type": "LineString",
+ "coordinates": [
+ [ 1, 1 ],
+ [ 12, 12 ]
+ ]
+ }
+ }],
+ style: {
+ type: "LineString",
+ id: "id.1.2.3.4.5",
+ "LineString": {
+ color: "#FF0000"
+ }
+ }
+ }
+ ]
+ }
+ ]
+};
+const annotationsLayerWithPointFeatureAndSymbol = {
+ "flat": [
+ {
+ "id": "annotations",
+ "features": [
+ {
+ type: "FeatureCollection",
+ features: [{
+ "properties": {
+ "id": "1"
+ },
+ "type": "Feature",
+ "geometry": {
+ "type": "LineString",
+ "coordinates": [
+ [ 1, 1 ],
+ [ 12, 12 ]
+ ]
+ },
+ style: [{
+ type: "Point",
+ id: "id.1.2.3.4.5",
+ iconUrl: "/path/symbol.svg",
+ symbolUrlCustomized: "/path/symbol.svg"
+ }]
+ }]
+ }
+ ]
+ }
+ ]
+};
describe('annotations Epics', () => {
let store;
const defaultState = {
@@ -102,6 +237,31 @@ describe('annotations Epics', () => {
const action = setStyle({});
store.dispatch(action);
});
+ it('MAP_CONFIG_LOADED with missing annotations layer', (done) => {
+ const state = {
+ annotations: {
+ editing: {
+ style: {}
+ },
+ originalStyle: {}
+ },
+ layers: {
+ flat: []
+ }
+ };
+ testEpic(addTimeoutEpic(addAnnotationsLayerEpic, 88), 1, configureMap({}), actions => {
+ expect(actions.length).toBe(1);
+ actions.map((action) => {
+ switch (action.type) {
+ case TEST_TIMEOUT:
+ break;
+ default:
+ expect(false).toBe(true);
+ }
+ });
+ done();
+ }, state);
+ });
it('add annotations layer on first save', (done) => {
store = mockStore({
annotations: {
@@ -126,7 +286,7 @@ describe('annotations Epics', () => {
store.dispatch(action);
});
- it('update annotations layer', (done) => {
+ it('update annotations layer, MAP_CONFIG_LOADED', (done) => {
let action = configureMap({});
store.subscribe(() => {
@@ -151,6 +311,96 @@ describe('annotations Epics', () => {
});
editAnnotation('1')(store.dispatch, store.getState);
});
+ it('update annotations layer with LineString Feature, with old style structure, MAP_CONFIG_LOADED', (done) => {
+ let action = configureMap({});
+
+ store = mockStore({
+ annotations: {
+ editing: {
+ style: {}
+ },
+ originalStyle: {}
+ },
+ layers: annotationsLayerWithLineStringFeature
+ });
+ store.subscribe(() => {
+ const actions = store.getActions();
+ if (actions.length >= 2) {
+ expect(actions[1].type).toBe(UPDATE_NODE);
+ done();
+ }
+ });
+
+ store.dispatch(action);
+ });
+ it('update annotations layer with text Feature, with old style structure, MAP_CONFIG_LOADED', (done) => {
+ let action = configureMap({});
+
+ store = mockStore({
+ annotations: {
+ editing: {
+ style: {}
+ },
+ originalStyle: {}
+ },
+ layers: annotationsLayerWithTextFeature
+ });
+ store.subscribe(() => {
+ const actions = store.getActions();
+ if (actions.length >= 2) {
+ expect(actions[1].type).toBe(UPDATE_NODE);
+ done();
+ }
+ });
+
+ store.dispatch(action);
+ });
+ it('update annotations layer with Point Feature, with new symbol style structure, MAP_CONFIG_LOADED', (done) => {
+ let action = configureMap({});
+
+ store = mockStore({
+ annotations: {
+ editing: {
+ style: {}
+ },
+ originalStyle: {}
+ },
+ layers: annotationsLayerWithPointFeatureAndSymbol
+ });
+ store.subscribe(() => {
+ const actions = store.getActions();
+ if (actions.length >= 2) {
+ expect(actions[1].type).toBe(UPDATE_NODE);
+ expect(actions[1].options.features[0].features[0].style[0].symbolUrlCustomized).toBe(undefined);
+ done();
+ }
+ });
+
+ store.dispatch(action);
+ });
+ it('update annotations layer with Circle Feature, with old style structure, MAP_CONFIG_LOADED', (done) => {
+ let action = configureMap({});
+
+ store = mockStore({
+ annotations: {
+ editing: {
+ style: {}
+ },
+ originalStyle: {}
+ },
+ layers: annotationsLayerWithCircleFeature
+ });
+ store.subscribe(() => {
+ const actions = store.getActions();
+ if (actions.length >= 2) {
+ expect(actions[1].type).toBe(UPDATE_NODE);
+ expect(actions[1].options.features[0].features[0].style.length).toBe(2);
+ done();
+ }
+ });
+
+ store.dispatch(action);
+ });
/**
TOFIX:
. some previous test seems to break this test, uncomment the following check about CLOSE_IDENTIFY when solved.
diff --git a/web/client/epics/annotations.js b/web/client/epics/annotations.js
index c10f869c1b..ab3d3dd48b 100644
--- a/web/client/epics/annotations.js
+++ b/web/client/epics/annotations.js
@@ -45,15 +45,22 @@ const {changeDrawingStatus} = require('../actions/draw');
* @type {Object}
*/
+/**
+ * TODO test this and move it into utils
+*/
const validateFeatureCollection = (feature) => {
let features = feature.features.map(f => {
let coords = [];
+ if (!f.geometry ) {
+ return f;
+ }
if (f.geometry.type === "LineString" || f.geometry.type === "MultiPoint") {
coords = f.geometry.coordinates.filter(validateCoordsArray);
} else if (f.geometry.type === "Polygon") {
- coords = [f.geometry.coordinates[0].filter(validateCoordsArray)];
+ coords = f.geometry.coordinates[0] ? [f.geometry.coordinates[0].filter(validateCoordsArray)] : [[]];
} else {
- coords = [f.geometry.coordinates].filter(validateCoordsArray)[0];
+ coords = [f.geometry.coordinates].filter(validateCoordsArray);
+ coords = coords.length ? coords[0] : [];
}
return set("geometry.coordinates", coords, f);
});
diff --git a/web/client/epics/measurement.js b/web/client/epics/measurement.js
index 58df8166ca..7867d91284 100644
--- a/web/client/epics/measurement.js
+++ b/web/client/epics/measurement.js
@@ -9,7 +9,7 @@
const Rx = require('rxjs');
const {ADD_MEASURE_AS_ANNOTATION} = require('../actions/measurement');
const {getStartEndPointsForLinestring, DEFAULT_ANNOTATIONS_STYLES, STYLE_TEXT} = require('../utils/AnnotationsUtils');
-const {convertUom, getFormattedBearingValue} = require('../utils/MeasureUtils');
+const {convertUom, getFormattedBearingValue, validateFeatureCoordinates} = require('../utils/MeasureUtils');
const LocaleUtils = require('../utils/LocaleUtils');
const {addLayer, updateNode} = require('../actions/layers');
const {toggleControl, SET_CONTROL_PROPERTY} = require('../actions/controls');
@@ -59,7 +59,9 @@ const convertMeasureToGeoJSON = (measureGeometry, value, uom, id, measureTool, s
},
{
type: "Feature",
- geometry: {...measureGeometry, type: isLineString(state) ? "MultiPoint" : measureGeometry.type},
+ geometry: {
+ coordinates: validateFeatureCoordinates(measureGeometry),
+ type: isLineString(state) ? "MultiPoint" : measureGeometry.type},
properties: {
isValidFeature: true,
useGeodesicLines: isLineString(state), // this is reduntant? remove it, check in the codebase where is used and use the geom dta instad
diff --git a/web/client/plugins/map/index.js b/web/client/plugins/map/index.js
index 0164bc814b..aeaede8ae3 100644
--- a/web/client/plugins/map/index.js
+++ b/web/client/plugins/map/index.js
@@ -11,7 +11,8 @@ const React = require('react');
const {creationError, changeMapView, clickOnMap} = require('../../actions/map');
const {layerLoading, layerLoad, layerError} = require('../../actions/layers');
const {changeMousePosition} = require('../../actions/mousePosition');
-const {changeMeasurementState, changeGeometry, resetGeometry} = require('../../actions/measurement');
+const {changeMeasurementState, changeGeometry, resetGeometry, updateMeasures} = require('../../actions/measurement');
+const {measurementSelector} = require('../../selectors/measurement');
const {changeSelectionState} = require('../../actions/selection');
const {changeLocateState, onLocateError} = require('../../actions/locate');
const {changeDrawingStatus, endDrawing, setCurrentStyle, geometryChanged, drawStopped, selectFeatures, drawingFeatures} = require('../../actions/draw');
@@ -46,7 +47,8 @@ module.exports = (mapType, actions) => {
const MeasurementSupport = connect((state) => ({
enabled: state.controls && state.controls.measure && state.controls.measure.enabled || false,
- measurement: state.measurement || {},
+ // TODO TEST selector to validate the feature: filter the coords, if length >= minValue return ft validated (close the polygon) else empty ft
+ measurement: measurementSelector(state),
useTreshold: state.measurement && state.measurement.useTreshold || null,
uom: state.measurement && state.measurement.uom || {
length: {unit: 'm', label: 'm'},
@@ -54,6 +56,7 @@ module.exports = (mapType, actions) => {
}
}), {
changeMeasurementState,
+ updateMeasures,
resetGeometry,
changeGeometry
})(components.MeasurementSupport || Empty);
diff --git a/web/client/reducers/__tests__/measurement-test.js b/web/client/reducers/__tests__/measurement-test.js
index 4534fff220..1d38d2247f 100644
--- a/web/client/reducers/__tests__/measurement-test.js
+++ b/web/client/reducers/__tests__/measurement-test.js
@@ -15,6 +15,7 @@ const {
changeFormatMeasurement,
resetGeometry,
changeGeometry,
+ updateMeasures,
init
} = require('../../actions/measurement');
const {RESET_CONTROLS, setControlProperty} = require('../../actions/controls');
@@ -162,5 +163,18 @@ describe('Test the measurement reducer', () => {
expect(state.lineMeasureEnabled).toEqual(true);
expect(state.geomType).toEqual("LineString");
});
+ it('UPDATE_MEASURES', () => {
+ let state = measurement({
+ geomType: "LineString",
+ lineMeasureEnabled: true,
+ areaMeasureEnabled: false,
+ bearingMeasureEnabled: false,
+ len: 0,
+ area: 700
+ }, updateMeasures({len: 12430, area: 0}));
+ expect(state.len).toEqual(12430);
+ expect(state.area).toEqual(0);
+ expect(state.geomType).toEqual("LineString");
+ });
});
diff --git a/web/client/reducers/annotations.js b/web/client/reducers/annotations.js
index 52e850e4b6..df3d4ac139 100644
--- a/web/client/reducers/annotations.js
+++ b/web/client/reducers/annotations.js
@@ -23,7 +23,7 @@ const {REMOVE_ANNOTATION, CONFIRM_REMOVE_ANNOTATION, CANCEL_REMOVE_ANNOTATION, C
CHANGE_FORMAT, UPDATE_SYMBOLS, ERROR_SYMBOLS
} = require('../actions/annotations');
-const {validateCoordsArray, getAvailableStyler, DEFAULT_ANNOTATIONS_STYLES, convertGeoJSONToInternalModel, addIds, validateFeature, getComponents, updateAllStyles} = require('../utils/AnnotationsUtils');
+const {validateCoordsArray, getAvailableStyler, DEFAULT_ANNOTATIONS_STYLES, convertGeoJSONToInternalModel, addIds, validateFeature, getComponents, updateAllStyles, getBaseCoord} = require('../utils/AnnotationsUtils');
const {set} = require('../utils/ImmutableUtils');
const {head, findIndex, isNil, slice, castArray} = require('lodash');
@@ -37,8 +37,6 @@ const fixCoordinates = (coords, type) => {
}
};
-const {getBaseCoord} = require('../utils/AnnotationsUtils');
-
function annotations(state = { validationErrors: {} }, action) {
switch (action.type) {
case CHANGED_SELECTED: {
diff --git a/web/client/reducers/measurement.js b/web/client/reducers/measurement.js
index ee225ff1e2..e8bca7e5ea 100644
--- a/web/client/reducers/measurement.js
+++ b/web/client/reducers/measurement.js
@@ -14,11 +14,13 @@ const {
CHANGED_GEOMETRY,
CHANGE_FORMAT,
CHANGE_COORDINATES,
+ UPDATE_MEASURES,
INIT
} = require('../actions/measurement');
-const {set} = require('../utils/ImmutableUtils');
-
const {TOGGLE_CONTROL, RESET_CONTROLS, SET_CONTROL_PROPERTY} = require('../actions/controls');
+const {set} = require('../utils/ImmutableUtils');
+const {isPolygon} = require('../utils/openlayers/DrawUtils');
+const {dropRight} = require('lodash');
const assign = require('object-assign');
const defaultState = {
@@ -61,7 +63,14 @@ function measurement(state = defaultState, action) {
}
});
}
- case CHANGE_MEASUREMENT_STATE:
+ case CHANGE_MEASUREMENT_STATE: {
+ let feature = action.feature;
+ if (isPolygon(feature)) {
+ /* in the state the polygon is always not closed (the feature come closed from the measureSupport)
+ * a selector validates the feature and it closes the polygon adding first valid coord
+ */
+ feature = set("geometry.coordinates[0]", dropRight(feature.geometry.coordinates[0]), feature);
+ }
return assign({}, state, {
lineMeasureEnabled: action.lineMeasureEnabled,
areaMeasureEnabled: action.areaMeasureEnabled,
@@ -73,8 +82,19 @@ function measurement(state = defaultState, action) {
bearing: action.bearing,
lenUnit: action.lenUnit,
areaUnit: action.areaUnit,
- feature: set("properties.disabled", state.feature.properties.disabled, action.feature)
+ feature: set("properties.disabled", state.feature.properties.disabled, feature)
});
+ }
+ case UPDATE_MEASURES: {
+ const {point, len, area, bearing} = action.measures;
+ return {
+ ...state,
+ point,
+ len,
+ area,
+ bearing
+ };
+ }
case RESET_GEOMETRY: {
let newState = set("feature.properties.disabled", true, state);
return {
@@ -170,16 +190,25 @@ function measurement(state = defaultState, action) {
}
case CHANGE_COORDINATES: {
let coordinates = action.coordinates.map(c => ([c.lon, c.lat]));
- let newState = set("feature.geometry.coordinates", state.areaMeasureEnabled ? [coordinates] : coordinates, state);
- newState = set("feature.type", "Feature", newState);
- newState = set("feature.properties.disabled", coordinates
- .filter((c) => {
- const isValid = !isNaN(parseFloat(c[0])) && !isNaN(parseFloat(c[1]));
- return isValid;
- }
- ).length !== coordinates.length, newState);
- newState = set("updatedByUI", true, newState);
- return set("feature.geometry.type", newState.bearingMeasureEnabled ? "LineString" : newState.geomType, newState);
+ // wrap in an array for polygon geom
+ coordinates = state.areaMeasureEnabled ? dropRight(coordinates) : coordinates;
+ return {
+ ...state,
+ feature: {
+ type: "Feature",
+ properties: {
+ disabled: coordinates.filter((c) => {
+ const isValid = !isNaN(parseFloat(c[0])) && !isNaN(parseFloat(c[1]));
+ return isValid;
+ }).length !== coordinates.length
+ },
+ geometry: {
+ type: state.bearingMeasureEnabled ? "LineString" : state.geomType,
+ coordinates: state.areaMeasureEnabled ? [coordinates] : coordinates
+ }
+ },
+ updatedByUI: true
+ };
}
default:
return state;
diff --git a/web/client/selectors/__tests__/measurement-test.js b/web/client/selectors/__tests__/measurement-test.js
index 5f4a628296..75ebf35135 100644
--- a/web/client/selectors/__tests__/measurement-test.js
+++ b/web/client/selectors/__tests__/measurement-test.js
@@ -10,8 +10,16 @@
const expect = require('expect');
const {
isCoordinateEditorEnabledSelector,
- showAddAsAnnotationSelector
+ showAddAsAnnotationSelector,
+ measurementSelector,
+ getValidFeatureSelector
} = require('../measurement');
+const {
+ polyFeatureNotClosedInvalid,
+ polyFeatureNotClosed,
+ lineFeature3,
+ lineFeatureWithoutGeom
+} = require('../../test-resources/drawsupport/features');
describe('Test maptype', () => {
it('test isCoordinateEditorEnabledSelector', () => {
@@ -37,4 +45,37 @@ describe('Test maptype', () => {
expect(retval).toExist();
expect(retval).toBe(true);
});
+ it('test getValidFeatureSelector no feature geom', () => {
+ expect(getValidFeatureSelector({
+ measurement: {
+ feature: lineFeatureWithoutGeom
+ }
+ })).toEqual(lineFeatureWithoutGeom);
+ });
+ it('test measurementSelector', () => {
+ let retval = measurementSelector({
+ measurement: {
+ showAddAsAnnotation: true,
+ feature: polyFeatureNotClosedInvalid
+ }
+ });
+ expect(retval).toExist();
+ expect(retval.feature.geometry.coordinates).toEqual( [ [ [ 0, 1 ], [ 0, 5 ], [ 2, 1 ], [ 0, 1 ] ] ] );
+
+ retval = measurementSelector({
+ measurement: {
+ showAddAsAnnotation: true,
+ feature: polyFeatureNotClosed
+ }
+ });
+ expect(retval.feature.geometry.coordinates).toEqual( [[[3, 1], [0, 5], [3, 3], [3, 1]]] );
+
+ retval = measurementSelector({
+ measurement: {
+ showAddAsAnnotation: true,
+ feature: lineFeature3
+ }
+ });
+ expect(retval.feature.geometry.coordinates).toEqual( lineFeature3.geometry.coordinates );
+ });
});
diff --git a/web/client/selectors/measurement.js b/web/client/selectors/measurement.js
index 29da494e89..c3b64015e8 100644
--- a/web/client/selectors/measurement.js
+++ b/web/client/selectors/measurement.js
@@ -8,6 +8,8 @@
const { isOpenlayers } = require('../selectors/maptype');
const { showCoordinateEditorSelector } = require('../selectors/controls');
+const { set } = require('../utils/ImmutableUtils');
+const { validateFeatureCoordinates } = require('../utils/MeasureUtils');
/**
* selects measurement state
@@ -16,7 +18,6 @@ const { showCoordinateEditorSelector } = require('../selectors/controls');
* @static
*/
-
/**
* selects the showCoordinateEditor flag from state
* @memberof selectors.measurement
@@ -24,10 +25,32 @@ const { showCoordinateEditorSelector } = require('../selectors/controls');
* @return {boolean} the showCoordinateEditor in the state
*/
const isCoordinateEditorEnabledSelector = (state) => showCoordinateEditorSelector(state) && !state.measurement.isDrawing && isOpenlayers(state);
-
const showAddAsAnnotationSelector = (state) => state && state.measurement && state.measurement.showAddAsAnnotation;
+/**
+ * validating feature that can contain invalid coordinates
+ * polygons needs to be closed fro being drawing
+ * if the number of valid coords is < min for that geomType then
+ * return empty coordinates
+*/
+const getValidFeatureSelector = (state) => {
+ let feature = state.measurement.feature;
+ if (feature.geometry) {
+ feature = set("geometry.coordinates", validateFeatureCoordinates(feature.geometry || {}), feature);
+ }
+ return feature;
+};
+
+const measurementSelector = (state) => {
+ return state.measurement && {
+ ...state.measurement,
+ feature: getValidFeatureSelector(state)
+ } || {};
+};
+
module.exports = {
+ measurementSelector,
+ getValidFeatureSelector,
isCoordinateEditorEnabledSelector,
showAddAsAnnotationSelector
};
diff --git a/web/client/test-resources/drawsupport/features.js b/web/client/test-resources/drawsupport/features.js
index 3bb169b480..43761db7dc 100644
--- a/web/client/test-resources/drawsupport/features.js
+++ b/web/client/test-resources/drawsupport/features.js
@@ -52,5 +52,528 @@ module.exports = {
},
id: "multipolygon",
properties: {}
+ },
+ lineFeatureInvalid: {
+ type: "Feature",
+ geometry: {
+ type: "LineString",
+ coordinates: [[0, 1], [2, 4], [2, ""]]
+ },
+ properties: {}
+ },
+ lineFeatureInvalid2: {
+ type: "Feature",
+ geometry: {
+ type: "LineString",
+ coordinates: [[0, 1], [2, ""]]
+ },
+ properties: {}
+ },
+ lineFeature: {
+ type: "Feature",
+ geometry: {
+ type: "LineString",
+ coordinates: [[0, 1], [2, 4]]
+ },
+ properties: {}
+ },
+ lineFeature3: {
+ type: "Feature",
+ geometry: {
+ type: "LineString",
+ coordinates: [[13.0, 43.0], [13.0, 40.0], [11.0, 41.0]]
+ },
+ properties: {}
+ },
+ lineFeatureWithoutGeom: {
+ type: "Feature",
+ geometry: undefined,
+ properties: {}
+ },
+ geomCollFeature: {
+ type: "Feature",
+ geometry: {
+ type: "GeometryCollection",
+ geometries: [{
+ type: "LineString",
+ coordinates: [[0, 1], [2, 4]]
+ }]
+ },
+ properties: {}
+ },
+ polyFeatureClosed: {
+ type: "Feature",
+ geometry: {
+ type: "Polygon",
+ coordinates: [[[0, 1], [0, 5], [2, 1], [0, 1]]]
+ },
+ properties: {}
+ },
+ polyFeatureClosed2: {
+ type: "Feature",
+ geometry: {
+ type: "Polygon",
+ coordinates: [[[0, 1], [0, 5], [2, 5], [0, 1]]]
+ },
+ properties: {}
+ },
+ polyFeatureNotClosed: {
+ type: "Feature",
+ geometry: {
+ type: "Polygon",
+ coordinates: [[[3, 1], [0, 5], [3, 3]]]
+ },
+ properties: {}
+ },
+ polyFeatureNotClosedInvalid: {
+ type: "Feature",
+ geometry: {
+ type: "Polygon",
+ coordinates: [[[0, 1], [0, 5], [2, 1], ["", 1]]]
+ },
+ properties: {}
+ },
+ polyFeatureNotClosedInvalid2: {
+ type: "Feature",
+ geometry: {
+ type: "Polygon",
+ coordinates: [[[0, 1], [0, 5], ["", 1]]]
+ },
+ properties: {}
+ },
+ circle: {
+ type: 'FeatureCollection',
+ id: '36835090-23ad-11e8-9839-9bab136db9a3',
+ newFeature: true,
+ properties: {
+ id: '36835090-23ad-11e8-9839-9bab136db9a3',
+ circles: [0],
+ isCircle: true
+ },
+ style: {
+ type: 'Circle',
+ Circle: {
+ color: '#ffcc33',
+ opacity: 1,
+ weight: 3,
+ fillColor: '#ffffff',
+ fillOpacity: 0.2,
+ radius: 10
+ }
+ },
+ features: [{
+ type: 'Feature',
+ geometry: {
+ type: 'Polygon',
+ coordinates: [
+ [
+ [
+ -7.066692092065635,
+ 47.17477833929903
+ ],
+ [
+ -7.070957956986268,
+ 47.26697075050753
+ ],
+ [
+ -7.083738716328214,
+ 47.35863997502234
+ ],
+ [
+ -7.104983930273322,
+ 47.44942710493982
+ ],
+ [
+ -7.134609753668168,
+ 47.53897854842588
+ ],
+ [
+ -7.172499266922562,
+ 47.6269473500946
+ ],
+ [
+ -7.218502937437762,
+ 47.71299445745591
+ ],
+ [
+ -7.272439209743323,
+ 47.796789930095706
+ ],
+ [
+ -7.334095222013593,
+ 47.87801408888858
+ ],
+ [
+ -7.403227646136091,
+ 47.95635860315586
+ ],
+ [
+ -7.479563648016411,
+ 48.03152751426181
+ ],
+ [
+ -7.562801964329729,
+ 48.10323819468144
+ ],
+ [
+ -7.6526140914695295,
+ 48.17122224206827
+ ],
+ [
+ -7.748645582001249,
+ 48.235226308292674
+ ],
+ [
+ -7.850517443504369,
+ 48.29501286380931
+ ],
+ [
+ -7.95782763428237,
+ 48.35036089804014
+ ],
+ [
+ -8.07015265003761,
+ 48.40106655672712
+ ],
+ [
+ -8.18704919524932,
+ 48.44694371741463
+ ],
+ [
+ -8.308055932658505,
+ 48.48782450436609
+ ],
+ [
+ -8.432695303955327,
+ 48.52355974430404
+ ],
+ [
+ -8.560475414483594,
+ 48.55401936438973
+ ],
+ [
+ -8.690891974524225,
+ 48.57909273383168
+ ],
+ [
+ -8.823430289496404,
+ 48.59868895043517
+ ],
+ [
+ -8.95756729122193,
+ 48.612737073283476
+ ],
+ [
+ -9.092773602236358,
+ 48.62118630258009
+ ],
+ [
+ -9.228515625000002,
+ 48.62400610748772
+ ],
+ [
+ -9.364257647763646,
+ 48.62118630258009
+ ],
+ [
+ -9.499463958778072,
+ 48.612737073283476
+ ],
+ [
+ -9.633600960503598,
+ 48.59868895043517
+ ],
+ [
+ -9.766139275475776,
+ 48.57909273383168
+ ],
+ [
+ -9.89655583551641,
+ 48.55401936438973
+ ],
+ [
+ -10.024335946044676,
+ 48.52355974430404
+ ],
+ [
+ -10.148975317341497,
+ 48.48782450436609
+ ],
+ [
+ -10.269982054750683,
+ 48.44694371741463
+ ],
+ [
+ -10.386878599962396,
+ 48.40106655672712
+ ],
+ [
+ -10.499203615717633,
+ 48.35036089804014
+ ],
+ [
+ -10.606513806495634,
+ 48.29501286380931
+ ],
+ [
+ -10.708385667998753,
+ 48.235226308292674
+ ],
+ [
+ -10.804417158530473,
+ 48.17122224206827
+ ],
+ [
+ -10.894229285670272,
+ 48.10323819468144
+ ],
+ [
+ -10.977467601983593,
+ 48.03152751426181
+ ],
+ [
+ -11.053803603863912,
+ 47.95635860315586
+ ],
+ [
+ -11.12293602798641,
+ 47.87801408888858
+ ],
+ [
+ -11.184592040256682,
+ 47.796789930095706
+ ],
+ [
+ -11.238528312562241,
+ 47.71299445745591
+ ],
+ [
+ -11.284531983077443,
+ 47.6269473500946
+ ],
+ [
+ -11.322421496331836,
+ 47.53897854842588
+ ],
+ [
+ -11.352047319726681,
+ 47.44942710493982
+ ],
+ [
+ -11.373292533671789,
+ 47.35863997502234
+ ],
+ [
+ -11.386073293013734,
+ 47.26697075050753
+ ],
+ [
+ -11.390339157934367,
+ 47.17477833929903
+ ],
+ [
+ -11.386073293013734,
+ 47.08242559504841
+ ],
+ [
+ -11.373292533671789,
+ 46.990277901535556
+ ],
+ [
+ -11.35204731972668,
+ 46.8987017170481
+ ],
+ [
+ -11.322421496331836,
+ 46.808063084694076
+ ],
+ [
+ -11.284531983077443,
+ 46.718726115193576
+ ],
+ [
+ -11.238528312562241,
+ 46.63105144927073
+ ],
+ [
+ -11.184592040256682,
+ 46.545394707297326
+ ],
+ [
+ -11.12293602798641,
+ 46.46210493431348
+ ],
+ [
+ -11.053803603863912,
+ 46.381523048960865
+ ],
+ [
+ -10.977467601983593,
+ 46.303980305201314
+ ],
+ [
+ -10.894229285670272,
+ 46.22979677595146
+ ],
+ [
+ -10.804417158530473,
+ 46.15927986793656
+ ],
+ [
+ -10.708385667998753,
+ 46.09272287714786
+ ],
+ [
+ -10.60651380649563,
+ 46.03040359427646
+ ],
+ [
+ -10.499203615717633,
+ 45.972582969388
+ ],
+ [
+ -10.386878599962396,
+ 45.919503844897314
+ ],
+ [
+ -10.269982054750683,
+ 45.871389765601215
+ ],
+ [
+ -10.148975317341497,
+ 45.828443874131516
+ ],
+ [
+ -10.024335946044676,
+ 45.79084789970411
+ ],
+ [
+ -9.89655583551641,
+ 45.75876124746622
+ ],
+ [
+ -9.766139275475776,
+ 45.73232019509079
+ ],
+ [
+ -9.633600960503598,
+ 45.711637202538626
+ ],
+ [
+ -9.499463958778076,
+ 45.696800340115416
+ ],
+ [
+ -9.364257647763646,
+ 45.6878728390993
+ ],
+ [
+ -9.228515625000002,
+ 45.684892768315834
+ ],
+ [
+ -9.092773602236358,
+ 45.6878728390993
+ ],
+ [
+ -8.95756729122193,
+ 45.696800340115416
+ ],
+ [
+ -8.823430289496406,
+ 45.711637202538626
+ ],
+ [
+ -8.690891974524225,
+ 45.73232019509079
+ ],
+ [
+ -8.560475414483594,
+ 45.75876124746622
+ ],
+ [
+ -8.43269530395533,
+ 45.79084789970411
+ ],
+ [
+ -8.308055932658508,
+ 45.828443874131516
+ ],
+ [
+ -8.187049195249319,
+ 45.871389765601215
+ ],
+ [
+ -8.07015265003761,
+ 45.919503844897314
+ ],
+ [
+ -7.95782763428237,
+ 45.972582969388
+ ],
+ [
+ -7.850517443504371,
+ 46.03040359427646
+ ],
+ [
+ -7.7486455820012505,
+ 46.09272287714786
+ ],
+ [
+ -7.652614091469531,
+ 46.15927986793656
+ ],
+ [
+ -7.562801964329729,
+ 46.22979677595146
+ ],
+ [
+ -7.479563648016411,
+ 46.3039803052013
+ ],
+ [
+ -7.403227646136092,
+ 46.381523048960865
+ ],
+ [
+ -7.334095222013593,
+ 46.46210493431348
+ ],
+ [
+ -7.272439209743323,
+ 46.545394707297326
+ ],
+ [
+ -7.218502937437762,
+ 46.63105144927073
+ ],
+ [
+ -7.172499266922562,
+ 46.718726115193576
+ ],
+ [
+ -7.134609753668168,
+ 46.808063084694076
+ ],
+ [
+ -7.104983930273322,
+ 46.8987017170481
+ ],
+ [
+ -7.083738716328214,
+ 46.990277901535556
+ ],
+ [
+ -7.070957956986268,
+ 47.08242559504841
+ ],
+ [
+ -7.066692092065635,
+ 47.17477833929903
+ ]
+ ]
+ ]
+ }
+ }]
}
};
diff --git a/web/client/themes/default/less/annotations.less b/web/client/themes/default/less/annotations.less
index c0729218be..b3fb770a8b 100644
--- a/web/client/themes/default/less/annotations.less
+++ b/web/client/themes/default/less/annotations.less
@@ -256,56 +256,6 @@
margin-top: 0px;
}
}
- /*display: flex;
- flex-direction: column;
- span {
- flex: 1 1 0%;
- display: flex;
- .mapstore-annotations-info-viewer {
- width: 100%;
- .mapstore-annotations-info-viewer-items {
- display: flex;
- .container-fluid {
- flex: 1;
- display: flex;
- flex-direction: column;
- .row {
- flex: 1;
- display: flex;
- flex-direction: column;
- &:first-child {
- flex: 1;
- display: flex;
- flex-direction: column;
- &:first-child {
- margin-bottom: 15px;
- }
- span:nth-child(2){
- flex: 1;
- display: flex;
- flex-direction: column;
- div:nth-child(2){
- flex: 1;
- display: flex;
- .quill{
- flex: 1;
- display: flex;
- flex-direction: column;
- .ql-container {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }*/
-
.msSideGrid {
height: ~'calc(100% - 161px)';
diff --git a/web/client/translations/data.de-DE b/web/client/translations/data.de-DE
index f2733c7593..a46be9f315 100644
--- a/web/client/translations/data.de-DE
+++ b/web/client/translations/data.de-DE
@@ -890,6 +890,7 @@
"MultiPoint": "LineString-Editor",
"Text": "Text-Editor"
},
+ "center": "Center",
"add": "Fügen Sie neue Koordinaten hinzu",
"addByClick": "Fügen Sie neue Koordinaten hinzu, indem Sie auf die Plus-Schaltfläche oder auf die Karte klicken",
"valid": "Geometrie ist gültig",
diff --git a/web/client/translations/data.en-US b/web/client/translations/data.en-US
index 01c5ec6ac9..2f3b3c7bea 100644
--- a/web/client/translations/data.en-US
+++ b/web/client/translations/data.en-US
@@ -890,6 +890,7 @@
"MultiPoint": "LineString editor",
"Text": "Text editor"
},
+ "center": "Center",
"add": "Add new coordinates",
"addByClick": "Add new coordinates by clicking the plus button or on the map",
"valid": "Geometry is valid",
diff --git a/web/client/translations/data.es-ES b/web/client/translations/data.es-ES
index 0473c1725c..90f36a8c8e 100644
--- a/web/client/translations/data.es-ES
+++ b/web/client/translations/data.es-ES
@@ -890,6 +890,7 @@
"MultiPoint": "Editor LineString",
"Text": "Editor de texto"
},
+ "center": "Centro",
"add": "Agregar nuevas coordenadas",
"addByClick": "Agregue nuevas coordenadas haciendo clic en el botón más o en el mapa",
"valid": "La geometría es válida",
diff --git a/web/client/translations/data.fr-FR b/web/client/translations/data.fr-FR
index 6a59eb56a3..9ccb91cd83 100644
--- a/web/client/translations/data.fr-FR
+++ b/web/client/translations/data.fr-FR
@@ -891,6 +891,7 @@
"MultiPoint": "Éditeur de ligne",
"Text": "Éditeur de texte"
},
+ "center": "Centre",
"add": "Ajouter de nouvelles coordonnées",
"addByClick": "Ajouter de nouvelles coordonnées en cliquant sur le bouton plus ou sur la carte",
"valid": "La géométrie est valide",
diff --git a/web/client/translations/data.hr-HR b/web/client/translations/data.hr-HR
index 7e738ec6ca..592aef334c 100644
--- a/web/client/translations/data.hr-HR
+++ b/web/client/translations/data.hr-HR
@@ -919,6 +919,7 @@
"MultiPoint": "LineString editor",
"Text": "Text editor"
},
+ "center": "Center",
"add": "Add new coordinates",
"addByClick": "Add new coordinates by clicking the plus button or on the map",
"valid": "Geometry is valid",
diff --git a/web/client/translations/data.it-IT b/web/client/translations/data.it-IT
index e98bfc9320..5500b58fab 100644
--- a/web/client/translations/data.it-IT
+++ b/web/client/translations/data.it-IT
@@ -890,6 +890,7 @@
"MultiPoint": "Editor della linea",
"Text": "Editor del testo"
},
+ "center": "Centro",
"add": "Aggiungi una nuova coordinata",
"addByClick": "Aggiungi nuove coordinate cliccando sul pulsante + o sulla mappa",
"valid": "La geometria è valida",
diff --git a/web/client/translations/data.nl-NL b/web/client/translations/data.nl-NL
index 5deffd305f..e938da71bf 100644
--- a/web/client/translations/data.nl-NL
+++ b/web/client/translations/data.nl-NL
@@ -858,6 +858,7 @@
"MultiPoint": "LineString editor",
"Text": "Text editor"
},
+ "center": "Center",
"add": "Add new coordinates",
"addByClick": "Add new coordinates by clicking the plus button or on the map",
"valid": "Geometry is valid",
diff --git a/web/client/translations/data.pt-PT b/web/client/translations/data.pt-PT
index 6dae0fa092..18efc121bc 100644
--- a/web/client/translations/data.pt-PT
+++ b/web/client/translations/data.pt-PT
@@ -920,6 +920,7 @@
"MultiPoint": "LineString editor",
"Text": "Text editor"
},
+ "center": "Center",
"add": "Add new coordinates",
"addByClick": "Add new coordinates by clicking the plus button or on the map",
"valid": "Geometry is valid",
diff --git a/web/client/translations/data.zh-ZH b/web/client/translations/data.zh-ZH
index fd1f891877..9af44bf00e 100644
--- a/web/client/translations/data.zh-ZH
+++ b/web/client/translations/data.zh-ZH
@@ -869,6 +869,7 @@
"MultiPoint": "LineString editor",
"Text": "Text editor"
},
+ "center": "Center",
"add": "Add new coordinates",
"addByClick": "Add new coordinates by clicking the plus button or on the map",
"valid": "Geometry is valid",
diff --git a/web/client/utils/AnnotationsUtils.js b/web/client/utils/AnnotationsUtils.js
index ffc311baf1..0c1473ad7e 100644
--- a/web/client/utils/AnnotationsUtils.js
+++ b/web/client/utils/AnnotationsUtils.js
@@ -464,6 +464,12 @@ const AnnotationsUtils = {
formatCoordinates: (coords = [[]]) => {
return coords.map(c => ({lat: c && c[1], lon: c && c[0]}));
},
+ getBaseCoord: (type) => {
+ switch (type) {
+ case "Polygon": case "LineString": case "MultiPoint": return [];
+ default: return [[{lat: "", lon: ""}]];
+ }
+ },
getComponents: ({type, coordinates}) => {
switch (type) {
case "Polygon": {
@@ -532,12 +538,6 @@ const AnnotationsUtils = {
}
return AnnotationsUtils.validateCoordinates({components, remove, type});
},
- getBaseCoord: (type) => {
- switch (type) {
- case "Polygon": case "LineString": case "MultiPoint": return [];
- default: return [[]];
- }
- },
updateAllStyles: (ftColl = {}, newStyle = {}) => {
if (ftColl.features && ftColl.features.length) {
return {
diff --git a/web/client/utils/DrawSupportUtils.jsx b/web/client/utils/DrawSupportUtils.jsx
index afeed28aca..7b5acb183d 100644
--- a/web/client/utils/DrawSupportUtils.jsx
+++ b/web/client/utils/DrawSupportUtils.jsx
@@ -56,7 +56,8 @@ const transformPolygonToCircle = (feature, mapCrs) => {
if (!feature.getGeometry() || feature.getGeometry().getType() !== "Polygon" || feature.getProperties().center && feature.getProperties().center.length === 0) {
return feature;
}
- if (feature.getProperties() && feature.getProperties().isCircle) {
+ if (feature.getProperties() && feature.getProperties().isCircle && feature.getProperties().center && feature.getProperties().center[0] && feature.getProperties().center[1]) {
+ // center must be a valid point
const extent = feature.getGeometry().getExtent();
let center;
if (feature.getProperties().center) {
diff --git a/web/client/utils/MeasureUtils.js b/web/client/utils/MeasureUtils.js
index 7ec072c37d..8fa5a53833 100644
--- a/web/client/utils/MeasureUtils.js
+++ b/web/client/utils/MeasureUtils.js
@@ -141,16 +141,44 @@ function convertUom(value, source = "m", dest = "m") {
return value;
}
-const isValidGeometry = ({coordinates, type}) => {
+
+const validateCoord = c => (!isNaN(parseFloat(c[0])) && !isNaN(parseFloat(c[1])));
+
+/**
+ * validate a geometry feature,
+ * if invalid return an empty one
+*/
+const validateFeatureCoordinates = ({coordinates, type} = {}) => {
+ let filteredCoords = coordinates;
+ if (type === "LineString") {
+ filteredCoords = coordinates.filter(validateCoord);
+ if (filteredCoords.length < 2) {
+ // if invalid return empty LineString
+ return [];
+ }
+ } else if (type === "Polygon") {
+ filteredCoords = head(coordinates).filter(validateCoord);
+ if (filteredCoords.length < 3) {
+ // if invalid return empty Polygon
+ return [[]];
+ }
+ // close polygon
+ filteredCoords = [filteredCoords.concat([head(filteredCoords)])];
+ }
+ return filteredCoords;
+};
+
+const isValidGeometry = ({coordinates, type} = {}) => {
if (!type || !coordinates || coordinates && isArray(coordinates) && coordinates.length === 0) {
return false;
}
- let coords = type === "Polygon" ? head(coordinates) : coordinates;
- let filteredCoords = coords.filter(c => !isNaN(parseFloat(c[0])) && !isNaN(parseFloat(c[1])));
- return filteredCoords.length > 0 && filteredCoords.length === coords.length;
+ let validatedCoords = validateFeatureCoordinates({coordinates, type});
+ validatedCoords = type === "Polygon" ? head(validatedCoords) : validatedCoords;
+ return validatedCoords.length > 0;
};
module.exports = {
+ validateFeatureCoordinates,
isValidGeometry,
convertUom,
getFormattedBearingValue,
diff --git a/web/client/utils/__tests__/AnnotationsUtils-test.js b/web/client/utils/__tests__/AnnotationsUtils-test.js
index 3c58719aeb..8fc679bb70 100644
--- a/web/client/utils/__tests__/AnnotationsUtils-test.js
+++ b/web/client/utils/__tests__/AnnotationsUtils-test.js
@@ -478,11 +478,12 @@ describe('Test the AnnotationsUtils', () => {
expect(coordToArray({lon: 2, lat: 1})[0]).toBe(2);
expect(coordToArray({lon: 2, lat: 1})[1]).toBe(1);
});
- it('test getBaseCoord defaults', () => {
+ it('test getBaseCoord', () => {
expect(getBaseCoord().length).toBe(1);
- expect(getBaseCoord()[0].length).toBe(0);
+ expect(getBaseCoord()[0].length).toBe(1);
expect(getBaseCoord("Polygon").length).toBe(0);
expect(getBaseCoord("LineString").length).toBe(0);
+ expect(getBaseCoord("MultiPoint").length).toBe(0);
});
it('test validateText defaults', () => {
let components = [{lat: 4, lon: 4}];
diff --git a/web/client/utils/__tests__/MeasureUtils-test.js b/web/client/utils/__tests__/MeasureUtils-test.js
index 06cfb125db..acc5fbe21b 100644
--- a/web/client/utils/__tests__/MeasureUtils-test.js
+++ b/web/client/utils/__tests__/MeasureUtils-test.js
@@ -12,6 +12,14 @@ const {
convertUom,
isValidGeometry
} = require('../MeasureUtils');
+const {
+ lineFeature,
+ lineFeatureInvalid,
+ lineFeatureInvalid2,
+ polyFeatureClosed,
+ polyFeatureNotClosedInvalid,
+ polyFeatureNotClosedInvalid2
+} = require('../../test-resources/drawsupport/features');
describe('MeasureUtils', () => {
@@ -88,20 +96,28 @@ describe('MeasureUtils', () => {
val = getFormattedBearingValue(281.111);
expect(val).toBe("N 78° 53' 20'' W");
});
- it('isValidGeometry with a valid geom', () => {
- const geometry = {
- type: "LineString",
- coordinates: [[1, 1], [2, 2]]
- };
- const isValid = isValidGeometry(geometry);
+ it('testing isValidGeometry() with all valid coords (line geom)', () => {
+ const isValid = isValidGeometry(lineFeature.geometry);
+ expect(isValid).toBe(true);
+ });
+ it('testing isValidGeometry() with some invalid coords (line geom) 2 point valid', () => {
+ const isValid = isValidGeometry(lineFeatureInvalid.geometry);
+ expect(isValid).toBe(true);
+ });
+ it('testing isValidGeometry() with some invalid coords (line geom) 1 point valid', () => {
+ const isValid = isValidGeometry(lineFeatureInvalid2.geometry);
+ expect(isValid).toBe(false);
+ });
+ it('testing isValidGeometry() with all valid coords (polygon geom)', () => {
+ const isValid = isValidGeometry(polyFeatureClosed.geometry);
+ expect(isValid).toBe(true);
+ });
+ it('testing isValidGeometry() with some invalid coords (polygon geom) 3 point valid', () => {
+ const isValid = isValidGeometry(polyFeatureNotClosedInvalid.geometry);
expect(isValid).toBe(true);
});
- it('isValidGeometry with an invalid geom', () => {
- const geometry = {
- type: "LineString",
- coordinates: [[1, 1], [2, 2], ["", 2]]
- };
- const isValid = isValidGeometry(geometry);
+ it('testing isValidGeometry() with some invalid coords (polygon geom) only 2 point valid', () => {
+ const isValid = isValidGeometry(polyFeatureNotClosedInvalid2.geometry);
expect(isValid).toBe(false);
});
diff --git a/web/client/utils/openlayers/DrawUtils.js b/web/client/utils/openlayers/DrawUtils.js
new file mode 100644
index 0000000000..187fae6130
--- /dev/null
+++ b/web/client/utils/openlayers/DrawUtils.js
@@ -0,0 +1,29 @@
+/**
+ * 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.
+*/
+
+let ol = require('openlayers');
+module.exports = {
+ createOLGeometry: ({type, coordinates, radius, center} = {}) => {
+ let geometry;
+ switch (type) {
+ case "Point": { geometry = new ol.geom.Point(coordinates ? coordinates : []); break; }
+ case "LineString": { geometry = new ol.geom.LineString(coordinates ? coordinates : []); break; }
+ case "MultiPoint": { geometry = new ol.geom.MultiPoint(coordinates ? coordinates : []); break; }
+ case "MultiLineString": { geometry = new ol.geom.MultiLineString(coordinates ? coordinates : []); break; }
+ case "MultiPolygon": { geometry = new ol.geom.MultiPolygon(coordinates ? coordinates : []); break; }
+ // defaults is Polygon / Circle
+ default: { geometry = radius && center ?
+ ol.geom.Polygon.fromCircle(new ol.geom.Circle([center.x, center.y], radius), 100) : new ol.geom.Polygon(coordinates ? coordinates : []);
+ }
+ }
+ return geometry;
+ },
+ isPolygon: (feature = {}) => {
+ return feature && feature.geometry && feature.geometry.type === "Polygon";
+ }
+};
diff --git a/web/client/utils/openlayers/__tests__/DrawUtils-test.js b/web/client/utils/openlayers/__tests__/DrawUtils-test.js
new file mode 100644
index 0000000000..7a210e42f5
--- /dev/null
+++ b/web/client/utils/openlayers/__tests__/DrawUtils-test.js
@@ -0,0 +1,122 @@
+/**
+ * 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 {createOLGeometry, isPolygon} = require('../DrawUtils');
+const expect = require('expect');
+
+
+describe('DrawUtils openlayers', () => {
+
+ it('test createOLGeometry defaults', () => {
+ const geom = createOLGeometry();
+ expect(geom).toExist();
+ expect(geom.getType()).toBe("Polygon");
+ });
+ it('test createOLGeometry LineString', () => {
+ // empty geom
+ const type = "LineString";
+ const coordinates = [[1, 1], [0, 0]];
+
+ let geom = createOLGeometry({type});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(0);
+
+ geom = createOLGeometry({type, coordinates});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(coordinates.length);
+ expect(geom.getCoordinates()).toEqual(coordinates);
+ });
+ it('test createOLGeometry Point', () => {
+ // empty geom
+ const type = "Point";
+ const coordinates = [1, 1];
+
+ let geom = createOLGeometry({type});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(0);
+
+ geom = createOLGeometry({type, coordinates});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(coordinates.length);
+ expect(geom.getCoordinates()).toEqual(coordinates);
+ });
+ it('test createOLGeometry MultiPoint', () => {
+ // empty geom
+ const type = "MultiPoint";
+ const coordinates = [[1, 1], [0, 0]];
+
+ let geom = createOLGeometry({type});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(0);
+
+ geom = createOLGeometry({type, coordinates});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(coordinates.length);
+ expect(geom.getCoordinates()).toEqual(coordinates);
+ });
+ it('test createOLGeometry MultiLineString', () => {
+ // empty geom
+ const type = "MultiLineString";
+ const coordinates = [ [[1, 1], [0, 0]], [[21, 21], [20, 20]]];
+
+ let geom = createOLGeometry({type});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(0);
+
+ geom = createOLGeometry({type, coordinates});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(coordinates.length);
+ expect(geom.getCoordinates()).toEqual(coordinates);
+ });
+ it('test createOLGeometry MultiPolygon', () => {
+ // empty geom
+ const type = "MultiPolygon";
+ const coordinates = [[ [[1, 1], [0, 0]], [[21, 21], [20, 20]]]];
+
+ let geom = createOLGeometry({type});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(0);
+
+ geom = createOLGeometry({type, coordinates});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(coordinates.length);
+ expect(geom.getCoordinates()).toEqual(coordinates);
+ });
+ it('test createOLGeometry Circle', () => {
+ // empty geom
+ const type = "Polygon";
+ const radius = 100;
+ const center = {x: 1, y: 1};
+
+ let geom = createOLGeometry({type});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(0);
+
+ geom = createOLGeometry({type, radius, center});
+ expect(geom).toExist();
+ expect(geom.getType()).toBe(type);
+ expect(geom.getCoordinates().length).toBe(1);
+ expect(geom.getCoordinates()[0].length).toBe(101);
+ });
+
+ it('test isPolygon', () => {
+ expect(isPolygon()).toBeFalsy();
+ });
+
+});