Improve open layers
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 18 Oct 2023 08:14:22 +0000 (10:14 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 18 Oct 2023 08:14:22 +0000 (10:14 +0200)
js/src/geo/OpenLayersMapPart.js
org.argeo.app.core/src/org/argeo/app/ux/js/AbstractJsObject.java
org.argeo.app.core/src/org/argeo/app/ux/js/JsClient.java
org.argeo.app.geo/src/org/argeo/app/geo/acr/GeoEntityUtils.java
org.argeo.app.geo/src/org/argeo/app/geo/http/WfsHttpHandler.java
org.argeo.app.geo/src/org/argeo/app/geo/ux/OpenLayersMapPart.java
org.argeo.app.geo/src/org/argeo/app/ol/Layer.java
org.argeo.app.geo/src/org/argeo/app/ol/Source.java

index 160930d6b7447563b309de34030dcf808d24b00a..6fedd7a2a382f9f6d8b77de9cbfae761a96b72cb 100644 (file)
@@ -34,6 +34,8 @@ export default class OpenLayersMapPart extends MapPart {
 
        #overviewMap;
 
+       select;
+
        /** Styled layer descriptor */
        #sld;
 
@@ -50,6 +52,7 @@ export default class OpenLayersMapPart extends MapPart {
                                }),
                        ],
                });
+               this.select = new Select();
                this.#map = new Map({
                        controls: defaultControls({
                                attribution: false,
@@ -70,6 +73,7 @@ export default class OpenLayersMapPart extends MapPart {
                        //                                              }),
                        target: this.getMapName(),
                });
+               this.#map.addInteraction(this.select);
                //this.#map.getView().set('projection', 'EPSG:4326', true);
        }
 
@@ -160,7 +164,7 @@ export default class OpenLayersMapPart extends MapPart {
                                return true;
                        });
                        if (feature !== null)
-                               mapPart.callbacks['onFeatureSingleClick'](feature.get('path'));
+                               mapPart.callbacks['onFeatureSingleClick'](feature.get('cr:path'));
                });
        }
 
@@ -172,7 +176,7 @@ export default class OpenLayersMapPart extends MapPart {
                select.on('select', function(e) {
                        if (e.selected.length > 0) {
                                let feature = e.selected[0];
-                               mapPart.callbacks['onFeatureSelected'](feature.get('path'));
+                               mapPart.callbacks['onFeatureSelected'](feature.get('cr:path'));
                        }
                });
        }
@@ -216,7 +220,7 @@ export default class OpenLayersMapPart extends MapPart {
                                return;
                        }
                        const coordinate = e.coordinate;
-                       const path = selected.get('path');
+                       const path = selected.get('cr:path');
                        if (path === null)
                                return true;
                        const res = mapPart.callbacks['onFeaturePopup'](path);
@@ -236,6 +240,26 @@ export default class OpenLayersMapPart extends MapPart {
                return 'map';
        }
 
+       selectFeatures(layerName, featureIds) {
+               // we cannot use 'this' in the function provided to OpenLayers
+               let mapPart = this;
+               this.select.getFeatures().clear();
+               const layer = this.getLayerByName(layerName);
+               const source = layer.getSource();
+               for (const featureId of featureIds) {
+                       let feature = source.getFeatureById(featureId);
+                       if (feature === null) {
+                               source.on('featuresloadend', function(e) {
+                                       feature = source.getFeatureById(featureId);
+                                       if (feature !== null)
+                                               mapPart.select.getFeatures().push(feature);
+                               });
+                       } else {
+                               this.select.getFeatures().push(feature);
+                       }
+               }
+       }
+
        //
        // STATIC FOR EXTENSION
        //
index 8645a77762f6706d8840692d5d095aa1301c7b08..3e13b68711bc68ee08d46d74d2dd8c6cce6ec14b 100644 (file)
@@ -65,7 +65,7 @@ public abstract class AbstractJsObject {
                return reference;
        }
 
-       String getJsReference() {
+       protected String getJsReference() {
                return jsClient.getJsVarName(reference);
        }
 
index 060f1200856c94bb666d8d0c02562b7ee9764210..2503cf05e482a06eb0bfb14a8feaf0ce21986cbf 100644 (file)
@@ -44,7 +44,7 @@ public interface JsClient {
        String createJsFunction(String name, Function<Object[], Object> toDo);
 
        /** Get a global variable name. */
-       public String getJsVarName(String name);
+       String getJsVarName(String name);
 
        /**
         * Completion stage when the client is ready (typically the page has loaded in
@@ -65,7 +65,7 @@ public interface JsClient {
        }
 
        default boolean isInstanceOf(String reference, String jsClass) {
-               return (Boolean) evaluate(getJsVarName(reference) + " instanceof " + jsClass);
+               return (Boolean) evaluate("return "+getJsVarName(reference) + " instanceof " + jsClass);
        }
 
        /*
index 43f0a022e772fcaa754e369bf469a6e97baa1c2d..62b432e7f42e59155d3f0a5f383b9057b087ef7d 100644 (file)
@@ -42,7 +42,7 @@ public class GeoEntityUtils {
        }
 
        public static void putGeometry(Content c, QName name, Geometry geometry) {
-               QName jsonFileName = new ContentName(name.getNamespaceURI(), name.getLocalPart() + _GEOM_JSON);
+               QName jsonFileName = getJsonFileName(name);
                Content geom = c.soleChild(jsonFileName).orElseGet(
                                () -> c.add(jsonFileName, Collections.singletonMap(DName.getcontenttype.qName(), "application/json")));
                try (OutputStream out = geom.open(OutputStream.class)) {
@@ -57,12 +57,21 @@ public class GeoEntityUtils {
                updateBoundingBox(c);
        }
 
+       public static boolean hasGeometry(Content c, QNamed name) {
+               return hasGeometry(c, name.qName());
+       }
+
+       public static boolean hasGeometry(Content c, QName name) {
+               QName jsonFileName = getJsonFileName(name);
+               return c.hasChild(jsonFileName);
+       }
+
        public static <T extends Geometry> T getGeometry(Content c, QNamed name, Class<T> clss) {
                return getGeometry(c, name.qName(), clss);
        }
 
        public static <T extends Geometry> T getGeometry(Content c, QName name, Class<T> clss) {
-               QName jsonFileName = new ContentName(name.getNamespaceURI(), name.getLocalPart() + _GEOM_JSON);
+               QName jsonFileName = getJsonFileName(name);
                Content geom = c.soleChild(jsonFileName).orElse(null);
                if (geom == null)
                        return null;
@@ -76,6 +85,11 @@ public class GeoEntityUtils {
                }
        }
 
+       private static QName getJsonFileName(QName name) {
+               QName jsonFileName = new ContentName(name.getNamespaceURI(), name.getLocalPart() + _GEOM_JSON);
+               return jsonFileName;
+       }
+
        public static Point toPoint(Content c) {
                if (c.hasContentClass(EntityType.geopoint)) {
                        Double lat = c.get(WGS84PosName.lat, Double.class).orElseThrow();
index 150977394d4c5bb00093a5020a8646c8294c8a84..c9a1e85c8c5867708b773a2b3d1345b6cad92090 100644 (file)
@@ -112,7 +112,8 @@ public class WfsHttpHandler implements HttpHandler {
                        outputFormat = "application/json";
                }
                String bboxStr = getKvpParameter(parameters, BBOX);
-               log.debug(bboxStr);
+               if (log.isTraceEnabled())
+                       log.trace(bboxStr);
                final Envelope bbox;
                if (bboxStr != null) {
                        String srs;
index a856bccd188fd1b9ed8d4fe5893aee5a6cf6e53f..512a473c080f5bc906397757a0478209211cf138 100644 (file)
@@ -1,7 +1,12 @@
 package org.argeo.app.geo.ux;
 
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
+import org.argeo.app.geo.ux.MapPart.FeaturePopupEvent;
+import org.argeo.app.geo.ux.MapPart.FeatureSelectedEvent;
+import org.argeo.app.geo.ux.MapPart.FeatureSingleClickEvent;
 import org.argeo.app.ol.AbstractOlObject;
 import org.argeo.app.ol.Layer;
 import org.argeo.app.ol.OlMap;
@@ -63,4 +68,39 @@ public class OpenLayersMapPart extends AbstractGeoJsObject {
                return mapPartName;
        }
 
+       public void selectFeatures(String layerName, Object... ids) {
+               executeMethod(getMethodName(), layerName, (Object[]) ids);
+       }
+
+       /*
+        * CALLBACKS
+        */
+       public void onFeatureSelected(Consumer<FeatureSelectedEvent> toDo) {
+               addCallback("FeatureSelected", (arr) -> {
+                       toDo.accept(new FeatureSelectedEvent((String) arr[0]));
+                       return null;
+               });
+       }
+
+       public void onFeatureSingleClick(Consumer<FeatureSingleClickEvent> toDo) {
+               addCallback("FeatureSingleClick", (arr) -> {
+                       toDo.accept(new FeatureSingleClickEvent((String) arr[0]));
+                       return null;
+               });
+       }
+
+       public void onFeaturePopup(Function<FeaturePopupEvent, String> toDo) {
+               addCallback("FeaturePopup", (arr) -> {
+                       return toDo.apply(new FeaturePopupEvent((String) arr[0]));
+               });
+       }
+
+       protected void addCallback(String suffix, Function<Object[], Object> toDo) {
+               getJsClient().getReadyStage().thenAccept((ready) -> {
+                       String functionName = getJsClient().createJsFunction(getMapPartName() + "__on" + suffix, toDo);
+                       getJsClient().execute(getJsReference() + ".callbacks['on" + suffix + "']=" + functionName + ";");
+                       executeMethod("enable" + suffix);
+               });
+       }
+
 }
index f6ccd1bab4abb13fc319376ddd0fabc35edfaafb..feb0700175d7ab67cd9ab1044c11d65570dbcf93 100644 (file)
@@ -30,6 +30,11 @@ public class Layer extends AbstractOlObject {
                        executeMethod(getMethodName(), source);
        }
 
+       public Source getSource() {
+               String reference = getReference() + ".getSource()";
+               return new Source(getJsClient(), reference);
+       }
+
        public void setMinResolution(double minResolution) {
                if (isNew())
                        getNewOptions().put("minResolution", minResolution);
index 50e25da08e6c88389954be2594168ae3fe441d33..541353eadd92928565beb2e520d6bcd1048ebc32 100644 (file)
@@ -5,4 +5,8 @@ public class Source extends AbstractOlObject {
        public Source(Object... args) {
                super(args);
        }
+
+       public void refresh() {
+               executeMethod(getMethodName());
+       }
 }