diff --git a/config/locales/de.yml b/config/locales/de.yml
index 9795c66..92ffb4c 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -72,6 +72,7 @@ de:
linestring: Linieneditor
polygon: Flächeneditor
clear_map: "Clear map"
+ remove_point: "Remove point"
geolocation_activated: Geolokalisierung aktiviert
geolocation_deactivated: Geolokalisierung deaktiviert
copied_location_to_clipboard: Standort in die Zwischenablage kopiert
@@ -81,6 +82,9 @@ de:
messages:
baselayer_missing: "Es ist kein Baselayer verfügbar!"
zoom_in_more: "Zoomen Sie hinein, um die Objekte zu sehen."
+ modify_start: "Hold down ALT
and click on a vertex to delete it."
+ modify_start_mac: "Hold down Option
and click on a vertex to delete it."
+ modify_start_touch: "Tap on a vertex to delete it."
gtt_map_rotate_label: Kartenrotation
gtt_map_rotate_info_html: Halten Sie Shift+Alt
gedrückt und ziehen
Sie die Karte, um sie zu drehen.
diff --git a/config/locales/en.yml b/config/locales/en.yml
index ae97bef..fe22c99 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -123,6 +123,7 @@ en:
linestring: "Line editor"
polygon: "Area editor"
clear_map: "Clear map"
+ remove_point: "Remove point"
copied_location_to_clipboard: "Copied location to clipboard"
modal:
load: "Load"
@@ -130,3 +131,6 @@ en:
messages:
baselayer_missing: "There is no baselayer available!"
zoom_in_more: "Zoom in to view objects."
+ modify_start: "Hold down ALT
and click on a vertex to delete it."
+ modify_start_mac: "Hold down Option
and click on a vertex to delete it."
+ modify_start_touch: "Tap on a vertex to delete it."
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index c1687aa..b6789da 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -118,6 +118,7 @@ ja:
linestring: ライン編集
polygon: エリア編集
clear_map: "地図をクリア"
+ remove_point: "Remove point"
copied_location_to_clipboard: 位置情報をクリップボードにコピーしました
modal:
load: 読み込み
@@ -125,3 +126,6 @@ ja:
messages:
baselayer_missing: "背景レイヤーが存在しません!"
zoom_in_more: "地物表示のためズームします。"
+ modify_start: "Hold down ALT
and click on a vertex to delete it."
+ modify_start_mac: "Hold down Option
and click on a vertex to delete it."
+ modify_start_touch: "Tap on a vertex to delete it."
diff --git a/src/components/gtt-client/helpers/platforms.ts b/src/components/gtt-client/helpers/platforms.ts
new file mode 100644
index 0000000..f0cdd12
--- /dev/null
+++ b/src/components/gtt-client/helpers/platforms.ts
@@ -0,0 +1,17 @@
+/**
+ * Utility function to detect touch devices
+ * @param isTouchDevice - boolean
+ * @returns boolean
+ */
+export const isTouchDevice = (): boolean => {
+ return ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
+}
+
+/**
+ * Utility function to detect macOS
+ * @param isMacOS - boolean
+ * @returns boolean
+ */
+export const isMacOS = (): boolean => {
+ return /Macintosh|MacIntel|MacPPC|Mac68K/.test(navigator.userAgent);
+}
diff --git a/src/components/gtt-client/openlayers/index.ts b/src/components/gtt-client/openlayers/index.ts
index e57f04a..c6fe69f 100644
--- a/src/components/gtt-client/openlayers/index.ts
+++ b/src/components/gtt-client/openlayers/index.ts
@@ -6,7 +6,8 @@ import { Style, Fill, Stroke, Circle } from 'ol/style';
import { createEmpty, extend, containsCoordinate } from 'ol/extent';
import { transform, fromLonLat } from 'ol/proj';
-import { Modify, Draw, Select } from 'ol/interaction'
+import { Draw, Select, Snap } from 'ol/interaction'
+import ModifyTouch from 'ol-ext/interaction/ModifyTouch';
import Bar from 'ol-ext/control/Bar';
import Button from 'ol-ext/control/Button';
import Toggle from 'ol-ext/control/Toggle';
@@ -16,12 +17,30 @@ import { position } from 'ol-ext/control/control';
import { GeoJSON } from 'ol/format';
import { getCookie, getMapSize, degreesToRadians, updateForm, formatLength, formatArea } from "../helpers";
+import { isTouchDevice, isMacOS } from "../helpers/platforms";
// Define the types for the Tooltip and the custom methods you added
interface ExtendedTooltip extends Tooltip {
prevHTML?: string;
}
+/**
+ * Helper class to manage the visibility of controls.
+ */
+class ControlManager {
+ static hide(controls: any[]) {
+ controls.forEach(control => {
+ control.element.style.display = 'none';
+ });
+ }
+
+ static show(controls: any[]) {
+ controls.forEach(control => {
+ control.element.style.display = '';
+ });
+ }
+}
+
/**
* Get the z-value for a given geometry.
* If the geometry is a Point, return the z-coordinate of the Point.
@@ -156,9 +175,17 @@ function createTooltip(): ExtendedTooltip {
*/
export function setControls(types: Array) {
// Make vector features editable
- const modify = new Modify({
+ const modify = new ModifyTouch({
+ title: this.i18n.control.remove_point,
features: this.vector.getSource().getFeaturesCollection()
- })
+ } as any)
+
+ modify.on('showpopup', evt => {
+ const geometryType = evt.feature.getGeometry().getType();
+ if (geometryType === 'Point') {
+ modify.removePoint(); // don't show the popup
+ }
+ });
modify.on('modifyend', evt => {
updateForm(this, evt.features.getArray(), true)
@@ -197,20 +224,43 @@ export function setControls(types: Array) {
})
draw.on('drawstart', evt => {
+ // Change the style of existing features to light gray and transparent and dashed line
+ this.vector.getSource().getFeatures().forEach((feature: any) => {
+ feature.setStyle(new Style({
+ fill: new Fill({
+ color: 'rgba(0, 0, 0, 0.1)'
+ }),
+ stroke: new Stroke({
+ color: 'rgba(0, 0, 0, 0.5)',
+ width: 2,
+ lineDash: [5, 5]
+ })
+ }));
+ });
+
if (this.contents.measure) {
tooltip.setFeature(evt.feature)
}
})
draw.on('change:active', evt => {
- tooltip.removeFeature()
- })
+ // If the Draw interaction is deactivated
+ if (!evt.target.getActive()) {
+ // Reset the style of existing features
+ this.vector.getSource().getFeatures().forEach((feature: any) => {
+ feature.setStyle(null); // Reset the style to the default style
+ });
+ }
+
+ tooltip.removeFeature();
+ });
draw.on('drawend', evt => {
tooltip.removeFeature()
this.vector.getSource().clear()
const feature = setZValueForGeometry(evt.feature, zValue);
updateForm(this, [feature], true)
+ ControlManager.show([editModeControl, clearMapCtrl]);
})
// Material design icon
@@ -230,11 +280,53 @@ export function setControls(types: Array) {
html: ``,
title: this.i18n.control[type.toLowerCase()],
interaction: draw,
- active: (type === geometryType)
+ active: false,
+ onToggle: (active: boolean) => {
+ modify.setActive(false);
+ if (active) {
+ draw.setActive(true);
+ } else {
+ draw.setActive(false);
+ }
+ }
})
editbar.addControl(control)
})
+ // Add the edit control
+ const editModeControl = new Toggle({
+ html: '',
+ title: this.i18n.control.edit_mode,
+ active: false,
+ onToggle: (active: boolean) => {
+ if (active) {
+ modify.setActive(true);
+ this.map.getInteractions().forEach((interaction: any) => {
+ if (interaction instanceof Draw) {
+ interaction.setActive(false);
+ }
+ });
+
+ if (this.vector.getSource().getFeatures().length > 0) {
+ const firstFeature = this.vector.getSource().getFeatures()[0];
+ if (firstFeature && firstFeature.getGeometry().getType() !== 'Point') {
+ // Code to execute if the first feature is not a Point
+ let message = this.i18n.messages.modify_start;
+ if (isTouchDevice()) {
+ message = this.i18n.messages.modify_start_touch;
+ } else if (isMacOS()) {
+ message = this.i18n.messages.modify_start_mac;
+ }
+ this.map.notification.show(message);
+ }
+ }
+ } else {
+ modify.setActive(false);
+ }
+ }
+ });
+ editbar.addControl(editModeControl);
+
// Add the clear map control
const clearMapCtrl = new Button({
html: '',
@@ -242,10 +334,29 @@ export function setControls(types: Array) {
handleClick: () => {
this.vector.getSource().clear();
updateForm(this, null);
+ (editbar.getControls()[0] as Toggle).setActive(true);
+ ControlManager.hide([editModeControl, clearMapCtrl]);
}
});
editbar.addControl(clearMapCtrl);
+ // if the vector layer is not empty, set the editModeControl to active
+ if (this.vector.getSource().getFeatures().length > 0) {
+ editModeControl.setActive(true);
+ ControlManager.show([editModeControl, clearMapCtrl]);
+ }
+ // otherwise set the first draw control to active
+ else {
+ (editbar.getControls()[0] as Toggle).setActive(true);
+ ControlManager.hide([editModeControl, clearMapCtrl]);
+ }
+
+ // Add the snap interaction
+ const snap = new Snap({
+ source: this.vector.getSource(),
+ });
+ this.map.addInteraction(snap);
+
// Uses jQuery UI for GeoJSON Upload modal window
const mapObj = this
const dialog = $("#dialog-geojson-upload").dialog({