diff --git a/src/app/api.js b/src/app/api.js
index 271f0df44..4896ec724 100644
--- a/src/app/api.js
+++ b/src/app/api.js
@@ -35,6 +35,25 @@ import GUI from 'services/gui';
//MIXINS
import Mixins from 'mixins';
+import { reverseGeometry } from 'utils/reverseGeometry';
+import { getExtentForViewAndSize } from 'utils/getExtentForViewAndSize';
+import { createPolygonLayerFromBBox } from 'utils/createPolygonLayerFromBBox';
+import { getLengthMessageText } from 'utils/getLengthMessageText';
+import { needUseSphereMethods } from 'utils/needUseSphereMethods';
+import { transformMeterLength } from 'utils/transformMeterLength';
+import { createMeasureTooltip } from 'utils/createMeasureTooltip';
+import { formatMeasure } from 'utils/formatMeasure';
+import { getCurrentMapUnit } from 'utils/getCurrentMapUnit';
+import { getAreaMessageText } from 'utils/getAreaMessageText';
+import { transformMeterArea } from 'utils/transformMeterArea';
+import { removeMeasureTooltip } from 'utils/removeMeasureTooltip';
+import { setMeasureTooltipStatic } from 'utils/setMeasureTooltipStatic';
+import { getMetersFromDegrees } from 'utils/getMetersFromDegrees';
+import { getDPI } from 'utils/getDPI';
+import { getResolutionFromScale } from 'utils/getResolutionFromScale';
+import { getScaleFromResolution } from 'utils/getScaleFromResolution';
+import { mergeOptions } from 'utils/mergeOptions';
+
const G3WObject = require('core/g3wobject');
const utils = require('utils');
const geoutils = require('utils/geo');
@@ -96,7 +115,6 @@ const PickCoordinatesInteraction = require('g3w-ol/interactions/pickcoordinatesi
const DeleteFeatureInteraction = require('g3w-ol/interactions/deletefeatureinteraction');
const AreaInteraction = require('g3w-ol/interactions/areainteraction');
const LengthInteraction = require('g3w-ol/interactions/lengthinteraction');
-const g3wolutils = require('utils/ol');
module.exports = {
@@ -250,7 +268,26 @@ module.exports = {
}
},
controls: {},
- utils: g3wolutils
+ utils: {
+ merge: mergeOptions,
+ getExtentForViewAndSize,
+ createPolygonLayerFromBBox,
+ reverseGeometry,
+ getScaleFromResolution,
+ getResolutionFromScale,
+ getDPI,
+ getMetersFromDegrees,
+ needUseSphereMethods,
+ getLengthMessageText,
+ getAreaMessageText,
+ formatMeasure,
+ createMeasureTooltip,
+ getCurrentMapUnit,
+ transformMeterLength,
+ transformMeterArea,
+ removeMeasureTooltip,
+ setMeasureTooltipStatic,
+ },
},
// G3W-SUITE debug info
diff --git a/src/app/constant.js b/src/app/constant.js
index 2eaa5a1a0..9a6801785 100644
--- a/src/app/constant.js
+++ b/src/app/constant.js
@@ -620,10 +620,28 @@ export const LOGO_GIS3W = 'images/logo_gis3w_156_85.png';
*/
export const SPATIAL_METHODS = ['intersects', 'within'];
+/**
+ * DPI96
+ *
+ * DOTS_PER_INCH = ol.has.DEVICE_PIXEL_RATIO * 96;
+ *
+ * @since 3.10.0
+ */
+export const DOTS_PER_INCH = 96;
+
+/**
+ * @since 3.10.0
+ */
+export const INCHES_PER_UNIT = {
+ m: 39.37,
+ degrees: 4374754
+};
+
export default {
APP_VERSION,
API_BASE_URLS,
DEFAULT_EDITING_CAPABILITIES,
+ DOTS_PER_INCH,
DOWNLOAD_FORMATS,
FILTER_OPERATORS,
FILTER_EXPRESSION_OPERATORS,
@@ -631,6 +649,7 @@ export default {
G3W_FID,
GEOMETRY_FIELDS,
GEOMETRY_TYPES,
+ INCHES_PER_UNIT,
LIST_OF_RELATIONS_TITLE,
LIST_OF_RELATIONS_ID,
LOCAL_ITEM_IDS,
diff --git a/src/app/core/layers/mixins/geo.js b/src/app/core/layers/mixins/geo.js
index 26ff652d5..580de75c4 100644
--- a/src/app/core/layers/mixins/geo.js
+++ b/src/app/core/layers/mixins/geo.js
@@ -5,11 +5,11 @@
* @since 3.9.0
*/
-import GUI from 'services/gui';
-import ApplicationService from 'services/application';
+import GUI from 'services/gui';
+import ApplicationService from 'services/application';
+import { getScaleFromResolution } from 'utils/getScaleFromResolution';
const Projections = require('g3w-ol/projection/projections');
-const { getScaleFromResolution } = require('utils/ol');
const { createFeatureFromFeatureObject } = require('utils/geo');
const { XHR, sanitizeUrl } = require('utils');
diff --git a/src/app/core/layers/providersfactory.js b/src/app/core/layers/providersfactory.js
index 31839742e..209474aec 100644
--- a/src/app/core/layers/providersfactory.js
+++ b/src/app/core/layers/providersfactory.js
@@ -2,6 +2,8 @@ import ApplicationState from 'store/application-state';
import RelationsService from 'services/relations';
import { QUERY_POINT_TOLERANCE } from 'constant';
import { QgsFilterToken } from 'core/layers/utils/QgsFilterToken';
+import { getDPI } from 'utils/getDPI';
+import { getExtentForViewAndSize } from 'utils/getExtentForViewAndSize';
import { get_legend_params } from 'utils/get_legend_params';
const G3WObject = require('core/g3wobject');
@@ -15,12 +17,11 @@ const { handleQueryResponse } = require('utils/geo');
const Parsers = require('utils/parsers');
const { t } = require('core/i18n/i18n.service');
const Feature = require('core/layers/features/feature');
-const geoutils = require('utils/ol');
const Filter = require('core/layers/filter/filter');
const GETFEATUREINFO_IMAGE_SIZE = [101, 101];
-const DPI = geoutils.getDPI();
+const DPI = getDPI();
const is_defined = d => undefined !== d;
@@ -505,7 +506,7 @@ const Providers = {
? layers.map(layer => layer.getWMSInfoLayerName()).join(',')
: this._layer.getWMSInfoLayerName();
- const extent = geoutils.getExtentForViewAndSize(coordinates, resolution, 0, size);
+ const extent = getExtentForViewAndSize(coordinates, resolution, 0, size);
const is_map_tolerance = ('map' === query_point_tolerance.unit);
diff --git a/src/app/g3w-ol/controls/areacontrol.js b/src/app/g3w-ol/controls/areacontrol.js
index 9f9d65963..7a20d39ae 100644
--- a/src/app/g3w-ol/controls/areacontrol.js
+++ b/src/app/g3w-ol/controls/areacontrol.js
@@ -1,4 +1,5 @@
-const utils = require('utils/ol');
+import { mergeOptions } from 'utils/mergeOptions';
+
const AreaIteraction = require('g3w-ol/interactions/areainteraction');
const MeasureControl = require('g3w-ol/controls/measurecontrol');
@@ -9,7 +10,7 @@ const AreaControl = function(options={}) {
clickmap: true, // set ClickMap
interactionClass: AreaIteraction
};
- options = utils.merge(options, _options);
+ options = mergeOptions(options, _options);
MeasureControl.call(this, options);
};
diff --git a/src/app/g3w-ol/controls/basequerypolygoncontrol.js b/src/app/g3w-ol/controls/basequerypolygoncontrol.js
index 364e6cb88..513073505 100644
--- a/src/app/g3w-ol/controls/basequerypolygoncontrol.js
+++ b/src/app/g3w-ol/controls/basequerypolygoncontrol.js
@@ -3,9 +3,9 @@
* @since v3.8
*/
import { SPATIAL_METHODS } from 'app/constant';
+import { mergeOptions } from 'utils/mergeOptions';
const InteractionControl = require('g3w-ol/controls/interactioncontrol');
-const { merge } = require('utils/ol');
const { Geometry } = require('utils/geo');
const VALIDGEOMETRIES = Geometry.getAllPolygonGeometryTypes();
@@ -32,7 +32,7 @@ const BaseQueryPolygonControl = function(options = {}) {
onhover: true
};
- options = merge(options, default_options);
+ options = mergeOptions(options, default_options);
options.geometryTypes = VALIDGEOMETRIES;
diff --git a/src/app/g3w-ol/controls/lengthcontrol.js b/src/app/g3w-ol/controls/lengthcontrol.js
index 3fb0c9f48..90d833eb9 100644
--- a/src/app/g3w-ol/controls/lengthcontrol.js
+++ b/src/app/g3w-ol/controls/lengthcontrol.js
@@ -1,6 +1,7 @@
-const utils = require('utils/ol');
+import { mergeOptions } from 'utils/mergeOptions';
+
const LenghtIteraction = require('g3w-ol/interactions/lengthinteraction');
-const MeasureControl = require('g3w-ol/controls/measurecontrol');
+const MeasureControl = require('g3w-ol/controls/measurecontrol');
const LengthControl = function(options={}) {
const _options = {
@@ -10,7 +11,7 @@ const LengthControl = function(options={}) {
interactionClass: LenghtIteraction
};
- options = utils.merge(options,_options);
+ options = mergeOptions(options,_options);
MeasureControl.call(this, options);
};
diff --git a/src/app/g3w-ol/controls/querycontrol.js b/src/app/g3w-ol/controls/querycontrol.js
index 654b620f3..26bf89451 100644
--- a/src/app/g3w-ol/controls/querycontrol.js
+++ b/src/app/g3w-ol/controls/querycontrol.js
@@ -1,9 +1,9 @@
-import GUI from 'services/gui';
-import ProjectsRegistry from 'store/projects';
+import GUI from 'services/gui';
+import ProjectsRegistry from 'store/projects';
import DataRouterService from 'services/data';
+import { mergeOptions } from 'utils/mergeOptions';
const { throttle } = require('utils');
-const utils = require('utils/ol');
const InteractionControl = require('g3w-ol/controls/interactioncontrol');
const PickCoordinatesInteraction = require('g3w-ol/interactions/pickcoordinatesinteraction');
@@ -17,7 +17,7 @@ const QueryControl = function(options = {}){
interactionClass: PickCoordinatesInteraction,
};
- options = utils.merge(options, _options);
+ options = mergeOptions(options, _options);
InteractionControl.call(this, options);
};
diff --git a/src/app/g3w-ol/controls/resetcontrol.js b/src/app/g3w-ol/controls/resetcontrol.js
index eeddcd207..b3769a9ba 100644
--- a/src/app/g3w-ol/controls/resetcontrol.js
+++ b/src/app/g3w-ol/controls/resetcontrol.js
@@ -1,4 +1,5 @@
-const utils = require('utils/ol');
+import { mergeOptions } from 'utils/mergeOptions';
+
const InteractionControl = require('g3w-ol/controls/interactioncontrol');
const ResetControl = function(options){
@@ -9,7 +10,7 @@ const ResetControl = function(options){
tipLabel: "Pan",
label: "\ue901"
};
- options = utils.merge(options,_options);
+ options = mergeOptions(options,_options);
InteractionControl.call(this,options);
};
diff --git a/src/app/g3w-ol/controls/scalecontrol.js b/src/app/g3w-ol/controls/scalecontrol.js
index 2495a72bb..b5ceda2ee 100644
--- a/src/app/g3w-ol/controls/scalecontrol.js
+++ b/src/app/g3w-ol/controls/scalecontrol.js
@@ -1,6 +1,8 @@
-const {t} = require('core/i18n/i18n.service');
-const { getResolutionFromScale, getScaleFromResolution } = require('utils/ol');
-import { PRINT_SCALES } from 'app/constant';
+import { PRINT_SCALES } from 'app/constant';
+import { getResolutionFromScale } from 'utils/getResolutionFromScale';
+import { getScaleFromResolution } from 'utils/getScaleFromResolution';
+
+const { t } = require('core/i18n/i18n.service');
const ScaleControl = function(options= {}) {
this.isMobile = options.isMobile || false;
diff --git a/src/app/g3w-ol/controls/streetviewcontrol.js b/src/app/g3w-ol/controls/streetviewcontrol.js
index b2e494181..731d54376 100644
--- a/src/app/g3w-ol/controls/streetviewcontrol.js
+++ b/src/app/g3w-ol/controls/streetviewcontrol.js
@@ -1,10 +1,10 @@
import ApplicationState from 'store/application-state';
-import GUI from 'services/gui';
+import GUI from 'services/gui';
+import { mergeOptions } from 'utils/mergeOptions';
-const { XHR } = require('utils');
-const utils = require('utils/ol');
-const StreetViewComponent = require('gui/streetview/vue/streetview');
-const InteractionControl = require('g3w-ol/controls/interactioncontrol');
+const { XHR } = require('utils');
+const StreetViewComponent = require('gui/streetview/vue/streetview');
+const InteractionControl = require('g3w-ol/controls/interactioncontrol');
const PickCoordinatesInteraction = require('g3w-ol/interactions/pickcoordinatesinteraction');
const GoogleStreetViewApiUrl = `https://maps.googleapis.com/maps/api/`;
@@ -73,7 +73,7 @@ const StreetViewControl = function(options={}) {
}
});
- options = utils.merge(options,_options);
+ options = mergeOptions(options, _options);
InteractionControl.call(this,options);
};
diff --git a/src/app/g3w-ol/interactions/measureinteraction.js b/src/app/g3w-ol/interactions/measureinteraction.js
index 0b561c588..7b0a655f5 100644
--- a/src/app/g3w-ol/interactions/measureinteraction.js
+++ b/src/app/g3w-ol/interactions/measureinteraction.js
@@ -1,10 +1,9 @@
-const { t } = require('core/i18n/i18n.service');
-const {
- createMeasureTooltip,
- setMeasureTooltipStatic,
- removeMeasureTooltip,
- needUseSphereMethods
-} = require('utils/ol');
+import { createMeasureTooltip } from 'utils/createMeasureTooltip';
+import { setMeasureTooltipStatic } from 'utils/setMeasureTooltipStatic';
+import { removeMeasureTooltip } from 'utils/removeMeasureTooltip';
+import { needUseSphereMethods } from 'utils/needUseSphereMethods';
+
+const { t } = require('core/i18n/i18n.service');
const MeasureIteraction = function(options={}) {
this._helpTooltip;
diff --git a/src/app/g3w-ol/layers/rasters.js b/src/app/g3w-ol/layers/rasters.js
index 65c79c35d..09954ebdc 100755
--- a/src/app/g3w-ol/layers/rasters.js
+++ b/src/app/g3w-ol/layers/rasters.js
@@ -1,4 +1,6 @@
-const DPI = require('utils/ol').getDPI();
+import { getDPI } from 'utils/getDPI';
+
+const DPI = getDPI();
const RasterLayers = {};
diff --git a/src/app/gui/map/mapservice.js b/src/app/gui/map/mapservice.js
index 645447051..5281c8a4e 100644
--- a/src/app/gui/map/mapservice.js
+++ b/src/app/gui/map/mapservice.js
@@ -1,12 +1,14 @@
-import { MAP_SETTINGS } from 'app/constant';
-import DataRouterService from 'services/data';
-import MapLayersStoresRegistry from 'store/map-layers';
-import ProjectsRegistry from 'store/projects';
-import ApplicationService from 'services/application';
-import ControlsRegistry from 'store/map-controls';
-import GUI from 'services/gui';
-import MapControlZoomHistory from "components/MapControlZoomHistory.vue";
-import MapControlGeocoding from 'components/MapControlGeocoding.vue';
+import { MAP_SETTINGS } from 'app/constant';
+import DataRouterService from 'services/data';
+import MapLayersStoresRegistry from 'store/map-layers';
+import ProjectsRegistry from 'store/projects';
+import ApplicationService from 'services/application';
+import ControlsRegistry from 'store/map-controls';
+import GUI from 'services/gui';
+import MapControlZoomHistory from "components/MapControlZoomHistory.vue";
+import MapControlGeocoding from 'components/MapControlGeocoding.vue';
+import { getScaleFromResolution } from 'utils/getScaleFromResolution';
+import { getResolutionFromScale } from 'utils/getResolutionFromScale';
const {
inherit,
@@ -26,10 +28,6 @@ const {
getGeoTIFFfromServer,
} = require('utils/geo');
const BaseLayers = require('g3w-ol/layers/bases');
-const {
- getScaleFromResolution,
- getResolutionFromScale
-} = require('utils/ol');
const VectorLayer = require('core/layers/vectorlayer');
const Control = require('g3w-ol/controls/control');
diff --git a/src/app/gui/print/printservice.js b/src/app/gui/print/printservice.js
index 89d95c1d8..65c2d58f3 100644
--- a/src/app/gui/print/printservice.js
+++ b/src/app/gui/print/printservice.js
@@ -1,12 +1,16 @@
-import ProjectsRegistry from 'store/projects';
-import ApplicationService from 'services/application';
-import ApplicationState from 'store/application-state';
+import ProjectsRegistry from 'store/projects';
+import ApplicationService from 'services/application';
+import ApplicationState from 'store/application-state';
import {
PRINT_SCALES as scale,
PRINT_RESOLUTIONS as dpis,
PRINT_FORMATS as formats
-} from 'app/constant';
-import GUI from 'services/gui';
+} from 'app/constant';
+import GUI from 'services/gui';
+import { getScaleFromResolution } from 'utils/getScaleFromResolution';
+import { getResolutionFromScale } from 'utils/getResolutionFromScale';
+import { getMetersFromDegrees } from 'utils/getMetersFromDegrees';
+
const {
base,
@@ -16,11 +20,6 @@ const {
} = require('utils');
const { t } = require('core/i18n/i18n.service');
const G3WObject = require('core/g3wobject');
-const {
- getScaleFromResolution,
- getResolutionFromScale,
- getMetersFromDegrees
-} = require('utils/ol');
const PrintPage = require('gui/print/vue/printpage');
/*
diff --git a/src/utils/createMeasureTooltip.js b/src/utils/createMeasureTooltip.js
new file mode 100644
index 000000000..3180886e1
--- /dev/null
+++ b/src/utils/createMeasureTooltip.js
@@ -0,0 +1,38 @@
+import { formatMeasure } from 'utils/formatMeasure';
+
+/**
+ * create and add measure tooltip
+ */
+export function createMeasureTooltip({ map, feature } = {}, options = {}) {
+ const element = document.createElement('div');
+ element.className = 'mtooltip mtooltip-measure';
+
+ const tooltip = new ol.Overlay({
+ element,
+ offset: [0, -15],
+ positioning: 'bottom-center'
+ });
+
+ map.addOverlay(tooltip);
+
+ return {
+ tooltip,
+ unbyKey: feature
+ .getGeometry()
+ .on('change', evt => {
+ let tooltipCoord;
+ const geometry = evt.target;
+ if (geometry instanceof ol.geom.Polygon) {
+ tooltipCoord = geometry.getInteriorPoint().getCoordinates();
+ } else if (geometry instanceof ol.geom.MultiPolygon) {
+ tooltipCoord = geometry.getInteriorPoints().getCoordinates()[0];
+ } else if (geometry instanceof ol.geom.LineString) {
+ tooltipCoord = geometry.getLastCoordinate();
+ } else if (geometry instanceof ol.geom.MultiLineString) {
+ tooltipCoord = geometry.getLastCoordinate();
+ }
+ element.innerHTML = formatMeasure({geometry, projection: map.getView().getProjection()}, options);
+ tooltip.setPosition(tooltipCoord);
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/utils/createPolygonLayerFromBBox.js b/src/utils/createPolygonLayerFromBBox.js
new file mode 100644
index 000000000..09bb034e7
--- /dev/null
+++ b/src/utils/createPolygonLayerFromBBox.js
@@ -0,0 +1,14 @@
+/**
+ * Create a polygon vector layer from bbox
+ *
+ * @param bbox
+ *
+ * @returns { ol.layer.Vector }
+ */
+export function createPolygonLayerFromBBox(bbox) {
+ return new ol.layer.Vector({
+ source: new ol.source.Vector({
+ features: [ new ol.Feature(new ol.geom.Polygon.fromExtent(bbox)) ]
+ })
+ });
+}
\ No newline at end of file
diff --git a/src/utils/formatMeasure.js b/src/utils/formatMeasure.js
new file mode 100644
index 000000000..c3f9057cb
--- /dev/null
+++ b/src/utils/formatMeasure.js
@@ -0,0 +1,29 @@
+import { getCurrentMapUnit } from 'utils/getCurrentMapUnit';
+import { getLengthMessageText } from 'utils/getLengthMessageText';
+import { getAreaMessageText } from 'utils/getAreaMessageText';
+
+export function formatMeasure({ geometry, projection } = {}, options = {}) {
+ /**
+ * @FIXME circular dependency (ie. empty object when importing at top level), ref: #130
+ */
+ const { Geometry, multiGeometryToSingleGeometries } = require('utils/geo');
+ //
+ const geometryType = geometry.getType();
+ const unit = getCurrentMapUnit();
+ if (Geometry.isLineGeometryType(geometryType)) {
+ return getLengthMessageText({
+ unit,
+ projection,
+ geometry
+ });
+ } else if (Geometry.isPolygonGeometryType(geometryType)){
+ let segments;
+ if (Geometry.isMultiGeometry(geometryType)) {
+ segments = [];
+ multiGeometryToSingleGeometries(geometry).forEach(geometry => {
+ geometry.getLinearRing().getCoordinates().forEach(coordinates => segments.push(coordinates))
+ })
+ } else segments = geometry.getLinearRing().getCoordinates();
+ return getAreaMessageText({unit, geometry, projection, segments});
+ }
+};
\ No newline at end of file
diff --git a/src/utils/getAreaMessageText.js b/src/utils/getAreaMessageText.js
new file mode 100644
index 000000000..559229758
--- /dev/null
+++ b/src/utils/getAreaMessageText.js
@@ -0,0 +1,36 @@
+import { needUseSphereMethods } from 'utils/needUseSphereMethods';
+import { getLengthMessageText } from 'utils/getLengthMessageText';
+import { transformMeterArea } from 'utils/transformMeterArea';
+
+export function getAreaMessageText({
+ unit,
+ geometry,
+ projection,
+ segments = []
+}) {
+ const useSphereMethods = needUseSphereMethods(projection);
+ const area = Math.round(useSphereMethods ? ol.sphere.getArea(geometry, {
+ projection: projection.getCode()
+ }): geometry.getArea());
+ let message;
+ let segments_info_meausure = '';
+ const segmentLength = segments.length;
+ if (segmentLength > 2) {
+ segments_info_meausure+=`${getLengthMessageText({
+ unit,
+ projection,
+ geometry: new ol.geom.LineString(segments)
+ })}
`;
+ }
+ switch (unit) {
+ case 'nautical':
+ message = `${transformMeterArea(area, unit)} nmi²`;
+ break;
+ case 'metric':
+ default:
+ message = area > 1000000 ? `${(Math.round(area / 1000000 * 100) / 100).toFixed(6)} km2` : `${(Math.round(area * 100) / 100).toFixed(3)} m2`;
+ }
+ if (segments_info_meausure)
+ message =`Area: ${message}