Prepare multi JavaScript modules
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 14 Sep 2023 07:15:47 +0000 (09:15 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 14 Sep 2023 07:15:47 +0000 (09:15 +0200)
24 files changed:
js/.externalToolBuilders/npm run build.launch
js/Makefile
js/org.argeo.app.geo.js/.gitignore [deleted file]
js/org.argeo.app.geo.js/.project [deleted file]
js/org.argeo.app.geo.js/bnd.bnd [deleted file]
js/org.argeo.app.geo.js/build.properties [deleted file]
js/org.argeo.app.js/.gitignore [new file with mode: 0644]
js/org.argeo.app.js/.project [new file with mode: 0644]
js/org.argeo.app.js/bnd.bnd [new file with mode: 0644]
js/org.argeo.app.js/build.properties [new file with mode: 0644]
js/src/geo/MapPart.js [new file with mode: 0644]
js/src/geo/OpenLayerTileSources.js [new file with mode: 0644]
js/src/geo/OpenLayersMapPart.js [new file with mode: 0644]
js/src/geo/export-package.js [new file with mode: 0644]
js/src/geo/index.html [new file with mode: 0644]
js/src/geo/index.js [new file with mode: 0644]
js/src/org.argeo.app.geo.js/MapPart.js [deleted file]
js/src/org.argeo.app.geo.js/OpenLayerTileSources.js [deleted file]
js/src/org.argeo.app.geo.js/OpenLayersMapPart.js [deleted file]
js/src/org.argeo.app.geo.js/export-package.js [deleted file]
js/src/org.argeo.app.geo.js/index.html [deleted file]
js/src/org.argeo.app.geo.js/index.js [deleted file]
js/webpack.common.js
swt/org.argeo.app.geo.swt/src/org/argeo/app/geo/swt/SwtJSMapPart.java

index 75fcedbb4da6c9bbab332eba8d3cc98fc87020ff..c706fc1d9f85f9425d1cb091b5233dfe5b85223a 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
-    <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${container}"/>
+    <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${project}"/>
     <booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="true"/>
-    <stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/argeo-suite-js/src&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
+    <stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/argeo-suite-js/package-lock.json&quot; type=&quot;1&quot;/&gt;&#10;&lt;item path=&quot;/argeo-suite-js/package.json&quot; type=&quot;1&quot;/&gt;&#10;&lt;item path=&quot;/argeo-suite-js/src&quot; type=&quot;2&quot;/&gt;&#10;&lt;item path=&quot;/argeo-suite-js/webpack.common.js&quot; type=&quot;1&quot;/&gt;&#10;&lt;item path=&quot;/argeo-suite-js/webpack.dev.js&quot; type=&quot;1&quot;/&gt;&#10;&lt;item path=&quot;/argeo-suite-js/webpack.prod.js&quot; type=&quot;1&quot;/&gt;&#10;&lt;/resources&gt;}"/>
     <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/npm"/>
     <stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
     <stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="run build"/>
index 1e8cd432f1537c114cbccf9a462018f45c89b960..4b4255922daa525e1c74f280e4664256186a4be9 100644 (file)
@@ -3,7 +3,7 @@ include ../sdk.mk
 A2_CATEGORY = org.argeo.suite
 
 BUNDLES = \
-org.argeo.app.geo.js \
+org.argeo.app.js \
 
 all: webpack osgi
 
@@ -17,10 +17,10 @@ clean:
        $(foreach bundle, $(BUNDLES), rm -rf $(bundle)/org) 
 
 npm-install:
-       cd org.argeo.app.geo.js && npm install
+       npm install
        
 jsdoc:
-       org.argeo.app.geo.js/node_modules/.bin/jsdoc -r org.argeo.app.geo.js/src/org.argeo.app.geo.js \
-               -d $(SDK_BUILD_BASE)/jsdoc/org.argeo.app.geo.js
+       node_modules/.bin/jsdoc -r src \
+               -d $(SDK_BUILD_BASE)/jsdoc/argeo-suite-js
 
 include  $(SDK_SRC_BASE)/sdk/argeo-build/osgi.mk
diff --git a/js/org.argeo.app.geo.js/.gitignore b/js/org.argeo.app.geo.js/.gitignore
deleted file mode 100644 (file)
index cf1db2e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/org/
diff --git a/js/org.argeo.app.geo.js/.project b/js/org.argeo.app.geo.js/.project
deleted file mode 100644 (file)
index b4b7877..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.app.geo.js</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-       </natures>
-</projectDescription>
diff --git a/js/org.argeo.app.geo.js/bnd.bnd b/js/org.argeo.app.geo.js/bnd.bnd
deleted file mode 100644 (file)
index 818a44c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Export-Package: org.argeo.app.geo.js
-
-
-Provide-Capability:\
-cms.publish;pkg=org.argeo.app.geo.js;file="*.png,*.js,*.map,*.css,*.html"
diff --git a/js/org.argeo.app.geo.js/build.properties b/js/org.argeo.app.geo.js/build.properties
deleted file mode 100644 (file)
index 9b31242..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-bin.includes = META-INF/,\
-               org/
diff --git a/js/org.argeo.app.js/.gitignore b/js/org.argeo.app.js/.gitignore
new file mode 100644 (file)
index 0000000..cf1db2e
--- /dev/null
@@ -0,0 +1 @@
+/org/
diff --git a/js/org.argeo.app.js/.project b/js/org.argeo.app.js/.project
new file mode 100644 (file)
index 0000000..a2edfff
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.app.js</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+       </natures>
+</projectDescription>
diff --git a/js/org.argeo.app.js/bnd.bnd b/js/org.argeo.app.js/bnd.bnd
new file mode 100644 (file)
index 0000000..cac0263
--- /dev/null
@@ -0,0 +1,6 @@
+Export-Package: \
+org.argeo.app.js,\
+
+
+Provide-Capability:\
+cms.publish;pkg=org.argeo.app.js;file="*.png,*.js,*.map,*.css,*.html",\
diff --git a/js/org.argeo.app.js/build.properties b/js/org.argeo.app.js/build.properties
new file mode 100644 (file)
index 0000000..9b31242
--- /dev/null
@@ -0,0 +1,2 @@
+bin.includes = META-INF/,\
+               org/
diff --git a/js/src/geo/MapPart.js b/js/src/geo/MapPart.js
new file mode 100644 (file)
index 0000000..5711233
--- /dev/null
@@ -0,0 +1,72 @@
+/** API to be used by Java.
+ *  @module MapPart
+ */
+
+/** Abstract base class for displaying a map. */
+export default class MapPart {
+
+       /** The name of the map, will also be the name of the variable */
+       #mapName;
+
+       constructor(mapName) {
+               this.#mapName = mapName;
+               this.createMapDiv(this.#mapName);
+       }
+
+       //
+       // ABSTRACT METHODS
+       //
+
+       /** Zoom the map to the given value. */
+       setZoom(zoom) {
+               throw new Error("Abstract method");
+       }
+
+       /** Set the center of the map to the given coordinates. */
+       setCenter(lng, lat) {
+               throw new Error("Abstract method");
+       }
+
+       /** Add a single point. */
+       addPoint(lng, lat, style) {
+               throw new Error("Abstract method");
+       }
+
+       addUrlLayer(url, format) {
+               throw new Error("Abstract method");
+       }
+
+       //
+       // EXTENSIONS
+       //
+       loadMapModule(url) {
+               var script = document.createElement("script");
+               script.src = url;
+               document.head.appendChild(script);
+               //              import(url)
+               //                      .then(module => { })
+               //                      .catch((error) => 'An error occurred while loading the component');
+       }
+
+       //
+       // ACCESSORS
+       //
+       getMapName() {
+               return this.#mapName;
+       }
+
+       //
+       // HTML
+       //
+       createMapDiv(id) {
+               var mapDiv = document.createElement('div');
+               mapDiv.id = id;
+               mapDiv.className = this.getMapDivCssClass();
+               mapDiv.style.cssText = 'width: 100%; height: 100vh;';
+               document.body.appendChild(mapDiv);
+       }
+
+       getMapDivCssClass() {
+               throw new Error("Abstract method");
+       }
+}
diff --git a/js/src/geo/OpenLayerTileSources.js b/js/src/geo/OpenLayerTileSources.js
new file mode 100644 (file)
index 0000000..3425384
--- /dev/null
@@ -0,0 +1,54 @@
+
+import WMTS from 'ol/source/WMTS.js';
+import WMTSTileGrid from 'ol/tilegrid/WMTS';
+import { getTopLeft } from 'ol/extent';
+import { getWidth } from 'ol/extent';
+import { get as getProjection } from 'ol/proj';
+
+export class SentinelCloudless extends WMTS {
+       static source_s2CL2019;
+       static EPSG4326 = getProjection('EPSG:4326');
+
+       static resolutions;
+       static matrixIds;
+
+       static {
+               let min_zoom = 6;
+               let max_zoom = 17;
+               let zoomOffset = 1;
+
+               // from https://s2maps.eu/
+               let size = getWidth(this.EPSG4326.getExtent()) / 512;
+               this.resolutions = new Array(max_zoom + zoomOffset);
+               this.matrixIds = new Array(max_zoom + zoomOffset);
+               for (let z = min_zoom; z <= max_zoom; ++z) {
+                       // generate resolutions and matrixIds arrays for this WMTS
+                       this.resolutions[z] = size / Math.pow(2, z);
+                       this.matrixIds[z] = z;
+               }
+       }
+       
+       constructor() {
+               super({
+                       urls: [
+                               "//a.s2maps-tiles.eu/wmts/",
+                               "//b.s2maps-tiles.eu/wmts/",
+                               "//c.s2maps-tiles.eu/wmts/",
+                               "//d.s2maps-tiles.eu/wmts/",
+                               "//e.s2maps-tiles.eu/wmts/"
+                       ],
+                       layer: 's2cloudless-2021',
+                       matrixSet: 'WGS84',
+                       format: 'image/jpeg',
+                       projection: SentinelCloudless.EPSG4326,
+                       tileGrid: new WMTSTileGrid({
+                               origin: getTopLeft(SentinelCloudless.EPSG4326.getExtent()),
+                               resolutions: SentinelCloudless.resolutions,
+                               matrixIds: SentinelCloudless.matrixIds,
+                       }),
+                       style: 'default',
+                       transition: 0,
+                       wrapX: true
+               });
+       }
+}
\ No newline at end of file
diff --git a/js/src/geo/OpenLayersMapPart.js b/js/src/geo/OpenLayersMapPart.js
new file mode 100644 (file)
index 0000000..e1d8642
--- /dev/null
@@ -0,0 +1,223 @@
+/** OpenLayers-based implementation. 
+ * @module OpenLayersMapPart
+ */
+
+import Map from 'ol/Map.js';
+import View from 'ol/View.js';
+import OSM from 'ol/source/OSM.js';
+import TileLayer from 'ol/layer/Tile.js';
+import { fromLonLat, getPointResolution } from 'ol/proj.js';
+import VectorSource from 'ol/source/Vector.js';
+import Feature from 'ol/Feature.js';
+import { Point } from 'ol/geom.js';
+import VectorLayer from 'ol/layer/Vector.js';
+import GeoJSON from 'ol/format/GeoJSON.js';
+import GPX from 'ol/format/GPX.js';
+import Select from 'ol/interaction/Select.js';
+import Overlay from 'ol/Overlay.js';
+import { Style, Icon } from 'ol/style.js';
+
+import * as SLDReader from '@nieuwlandgeo/sldreader';
+
+import MapPart from './MapPart.js';
+import { SentinelCloudless } from './OpenLayerTileSources.js';
+
+/** OpenLayers implementation of MapPart. */
+export default class OpenLayersMapPart extends MapPart {
+       /** The OpenLayers Map. */
+       #map;
+
+       /** Externally added callback functions. */
+       callbacks = {};
+
+       /** Constructor taking the mapName as an argument. */
+       constructor(mapName) {
+               super(mapName);
+               this.#map = new Map({
+                       layers: [
+                               //                              new TileLayer({
+                               //                                      source: new SentinelCloudless(),
+                               //                              }),
+                               new TileLayer({
+                                       source: new OSM(),
+                                       opacity: 0.4,
+                                       transition: 0,
+                               }),
+                       ],
+                       target: this.getMapName(),
+               });
+       }
+
+       /* GEOGRAPHICAL METHODS */
+
+       setZoom(zoom) {
+               this.#map.getView().setZoom(zoom);
+       }
+
+       setCenter(lng, lat) {
+               this.#map.getView().setCenter(fromLonLat([lng, lat]));
+       }
+
+       addPoint(lng, lat, style) {
+               let vectorSource = new VectorSource({
+                       features: [new Feature({
+                               geometry: new Point(fromLonLat([lng, lat]))
+                       })]
+               });
+               this.#map.addLayer(new VectorLayer({
+                       source: vectorSource,
+                       style: style,
+               }));
+       }
+
+       addUrlLayer(url, format, style, sld) {
+               let featureFormat;
+               if (format === 'GEOJSON') {
+                       featureFormat = new GeoJSON();
+               }
+               else if (format === 'GPX') {
+                       featureFormat = new GPX();
+               } else {
+                       throw new Error("Unsupported format " + format);
+               }
+               const vectorSource = new VectorSource({
+                       url: url,
+                       format: featureFormat,
+               });
+               const vectorLayer = new VectorLayer({
+                       source: vectorSource,
+               });
+               if (sld) {
+                       this.#applySLD(vectorLayer, style);
+               } else if (style !== null) {
+                       vectorLayer.setStyle(style);
+               }
+               this.#map.addLayer(vectorLayer);
+       }
+
+
+       /* CALLBACKS */
+       enableFeatureSingleClick() {
+               // we cannot use 'this' in the function provided to OpenLayers
+               let mapPart = this;
+               this.#map.on('singleclick', function(e) {
+                       let feature = null;
+                       // we chose the first one
+                       e.map.forEachFeatureAtPixel(e.pixel, function(f) {
+                               feature = f;
+                               return true;
+                       });
+                       if (feature !== null)
+                               mapPart.callbacks['onFeatureSingleClick'](feature.get('path'));
+               });
+       }
+
+       enableFeatureSelected() {
+               // we cannot use 'this' in the function provided to OpenLayers
+               let mapPart = this;
+               var select = new Select();
+               this.#map.addInteraction(select);
+               select.on('select', function(e) {
+                       if (e.selected.length > 0) {
+                               let feature = e.selected[0];
+                               mapPart.callbacks['onFeatureSelected'](feature.get('path'));
+                       }
+               });
+       }
+
+       enableFeaturePopup() {
+               // we cannot use 'this' in the function provided to OpenLayers
+               let mapPart = this;
+               /**
+                * Elements that make up the popup.
+                */
+               const container = document.getElementById('popup');
+               const content = document.getElementById('popup-content');
+               const closer = document.getElementById('popup-closer');
+
+               /**
+                * Create an overlay to anchor the popup to the map.
+                */
+               const overlay = new Overlay({
+                       element: container,
+                       autoPan: false,
+                       autoPanAnimation: {
+                               duration: 250,
+                       },
+               });
+               this.#map.addOverlay(overlay);
+
+               let selected = null;
+               this.#map.on('pointermove', function(e) {
+                       if (selected !== null) {
+                               selected.setStyle(undefined);
+                               selected = null;
+                       }
+
+                       e.map.forEachFeatureAtPixel(e.pixel, function(f) {
+                               selected = f;
+                               return true;
+                       });
+
+                       if (selected == null) {
+                               overlay.setPosition(undefined);
+                               return;
+                       }
+                       const coordinate = e.coordinate;
+                       const path = selected.get('path');
+                       if (path === null)
+                               return true;
+                       const res = mapPart.callbacks['onFeaturePopup'](path);
+                       if (res != null) {
+                               content.innerHTML = res;
+                               overlay.setPosition(coordinate);
+                       } else {
+                               overlay.setPosition(undefined);
+                       }
+               });
+       }
+
+       //
+       // HTML
+       //
+       getMapDivCssClass() {
+               return 'map';
+       }
+
+       //
+       // STATIC FOR EXTENSION
+       //
+       static newStyle(args) {
+               return new Style(args);
+       }
+
+       static newIcon(args) {
+               return new Icon(args);
+       }
+
+       //
+       // SLD STYLING
+       //
+       #applySLD(vectorLayer, text) {
+               const sldObject = SLDReader.Reader(text);
+               const sldLayer = SLDReader.getLayer(sldObject);
+               const style = SLDReader.getStyle(sldLayer);
+               const featureTypeStyle = style.featuretypestyles[0];
+
+               const viewProjection = this.#map.getView().getProjection();
+               const olStyleFunction = SLDReader.createOlStyleFunction(featureTypeStyle, {
+                       // Use the convertResolution option to calculate a more accurate resolution.
+                       convertResolution: viewResolution => {
+                               const viewCenter = this.#map.getView().getCenter();
+                               return getPointResolution(viewProjection, viewResolution, viewCenter);
+                       },
+                       // If you use point icons with an ExternalGraphic, you have to use imageLoadCallback
+                       // to update the vector layer when an image finishes loading.
+                       // If you do not do this, the image will only be visible after next layer pan/zoom.
+                       imageLoadedCallback: () => {
+                               vectorLayer.changed();
+                       },
+               });
+               vectorLayer.setStyle(olStyleFunction);
+       }
+}
\ No newline at end of file
diff --git a/js/src/geo/export-package.js b/js/src/geo/export-package.js
new file mode 100644 (file)
index 0000000..c322c28
--- /dev/null
@@ -0,0 +1,14 @@
+import OpenLayersMapPart from './OpenLayersMapPart.js';
+
+// PSEUDO PACKAGE
+if (typeof globalThis.argeo === 'undefined')
+       globalThis.argeo = {};
+if (typeof globalThis.argeo.app === 'undefined')
+       globalThis.argeo.app = {};
+if (typeof globalThis.argeo.app.geo === 'undefined')
+       globalThis.argeo.app.geo = {};
+
+// PUBLIC CLASSES
+globalThis.argeo.app.geo.OpenLayersMapPart = OpenLayersMapPart;
+
+"use strict";
diff --git a/js/src/geo/index.html b/js/src/geo/index.html
new file mode 100644 (file)
index 0000000..bafe7fe
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+       <meta charset="UTF-8">
+       <style>
+               .ol-popup {
+                       position: absolute;
+                       background-color: white;
+                       box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
+                       padding: 5px;
+                       border-radius: 10px;
+                       border: 1px solid #cccccc;
+                       bottom: 12px;
+                       left: -50px;
+                       min-width: 130px;
+               }
+
+               .ol-popup:after,
+               .ol-popup:before {
+                       top: 100%;
+                       border: solid transparent;
+                       content: " ";
+                       height: 0;
+                       width: 0;
+                       position: absolute;
+                       pointer-events: none;
+               }
+
+               .ol-popup:after {
+                       border-top-color: white;
+                       border-width: 10px;
+                       left: 48px;
+                       margin-left: -10px;
+               }
+
+               .ol-popup:before {
+                       border-top-color: #cccccc;
+                       border-width: 11px;
+                       left: 48px;
+                       margin-left: -11px;
+               }
+
+               .ol-popup-closer {
+                       text-decoration: none;
+                       position: absolute;
+                       top: 2px;
+                       right: 8px;
+               }
+
+               .ol-popup-closer:after {
+                       content: "✖";
+               }
+
+               #popup-content {
+                       font: 16px sans-serif;
+               }
+       </style>
+</head>
+
+<body>
+       <!-- Popup -->
+       <div id="popup" class="ol-popup">
+               <div id="popup-content"></div>
+       </div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/js/src/geo/index.js b/js/src/geo/index.js
new file mode 100644 (file)
index 0000000..f389db0
--- /dev/null
@@ -0,0 +1,4 @@
+import './export-package.js';
+
+// webpack specific
+import 'ol/ol.css';
diff --git a/js/src/org.argeo.app.geo.js/MapPart.js b/js/src/org.argeo.app.geo.js/MapPart.js
deleted file mode 100644 (file)
index 5711233..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/** API to be used by Java.
- *  @module MapPart
- */
-
-/** Abstract base class for displaying a map. */
-export default class MapPart {
-
-       /** The name of the map, will also be the name of the variable */
-       #mapName;
-
-       constructor(mapName) {
-               this.#mapName = mapName;
-               this.createMapDiv(this.#mapName);
-       }
-
-       //
-       // ABSTRACT METHODS
-       //
-
-       /** Zoom the map to the given value. */
-       setZoom(zoom) {
-               throw new Error("Abstract method");
-       }
-
-       /** Set the center of the map to the given coordinates. */
-       setCenter(lng, lat) {
-               throw new Error("Abstract method");
-       }
-
-       /** Add a single point. */
-       addPoint(lng, lat, style) {
-               throw new Error("Abstract method");
-       }
-
-       addUrlLayer(url, format) {
-               throw new Error("Abstract method");
-       }
-
-       //
-       // EXTENSIONS
-       //
-       loadMapModule(url) {
-               var script = document.createElement("script");
-               script.src = url;
-               document.head.appendChild(script);
-               //              import(url)
-               //                      .then(module => { })
-               //                      .catch((error) => 'An error occurred while loading the component');
-       }
-
-       //
-       // ACCESSORS
-       //
-       getMapName() {
-               return this.#mapName;
-       }
-
-       //
-       // HTML
-       //
-       createMapDiv(id) {
-               var mapDiv = document.createElement('div');
-               mapDiv.id = id;
-               mapDiv.className = this.getMapDivCssClass();
-               mapDiv.style.cssText = 'width: 100%; height: 100vh;';
-               document.body.appendChild(mapDiv);
-       }
-
-       getMapDivCssClass() {
-               throw new Error("Abstract method");
-       }
-}
diff --git a/js/src/org.argeo.app.geo.js/OpenLayerTileSources.js b/js/src/org.argeo.app.geo.js/OpenLayerTileSources.js
deleted file mode 100644 (file)
index 3425384..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-
-import WMTS from 'ol/source/WMTS.js';
-import WMTSTileGrid from 'ol/tilegrid/WMTS';
-import { getTopLeft } from 'ol/extent';
-import { getWidth } from 'ol/extent';
-import { get as getProjection } from 'ol/proj';
-
-export class SentinelCloudless extends WMTS {
-       static source_s2CL2019;
-       static EPSG4326 = getProjection('EPSG:4326');
-
-       static resolutions;
-       static matrixIds;
-
-       static {
-               let min_zoom = 6;
-               let max_zoom = 17;
-               let zoomOffset = 1;
-
-               // from https://s2maps.eu/
-               let size = getWidth(this.EPSG4326.getExtent()) / 512;
-               this.resolutions = new Array(max_zoom + zoomOffset);
-               this.matrixIds = new Array(max_zoom + zoomOffset);
-               for (let z = min_zoom; z <= max_zoom; ++z) {
-                       // generate resolutions and matrixIds arrays for this WMTS
-                       this.resolutions[z] = size / Math.pow(2, z);
-                       this.matrixIds[z] = z;
-               }
-       }
-       
-       constructor() {
-               super({
-                       urls: [
-                               "//a.s2maps-tiles.eu/wmts/",
-                               "//b.s2maps-tiles.eu/wmts/",
-                               "//c.s2maps-tiles.eu/wmts/",
-                               "//d.s2maps-tiles.eu/wmts/",
-                               "//e.s2maps-tiles.eu/wmts/"
-                       ],
-                       layer: 's2cloudless-2021',
-                       matrixSet: 'WGS84',
-                       format: 'image/jpeg',
-                       projection: SentinelCloudless.EPSG4326,
-                       tileGrid: new WMTSTileGrid({
-                               origin: getTopLeft(SentinelCloudless.EPSG4326.getExtent()),
-                               resolutions: SentinelCloudless.resolutions,
-                               matrixIds: SentinelCloudless.matrixIds,
-                       }),
-                       style: 'default',
-                       transition: 0,
-                       wrapX: true
-               });
-       }
-}
\ No newline at end of file
diff --git a/js/src/org.argeo.app.geo.js/OpenLayersMapPart.js b/js/src/org.argeo.app.geo.js/OpenLayersMapPart.js
deleted file mode 100644 (file)
index f671b02..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/** OpenLayers-based implementation. 
- * @module OpenLayersMapPart
- */
-
-import Map from 'ol/Map.js';
-import View from 'ol/View.js';
-import OSM from 'ol/source/OSM.js';
-import TileLayer from 'ol/layer/Tile.js';
-import { fromLonLat, getPointResolution } from 'ol/proj.js';
-import VectorSource from 'ol/source/Vector.js';
-import Feature from 'ol/Feature.js';
-import { Point } from 'ol/geom.js';
-import VectorLayer from 'ol/layer/Vector.js';
-import GeoJSON from 'ol/format/GeoJSON.js';
-import GPX from 'ol/format/GPX.js';
-import Select from 'ol/interaction/Select.js';
-import Overlay from 'ol/Overlay.js';
-import { Style, Icon } from 'ol/style.js';
-
-import * as SLDReader from '@nieuwlandgeo/sldreader';
-
-import MapPart from './MapPart.js';
-import { SentinelCloudless } from './OpenLayerTileSources.js';
-
-/** OpenLayers implementation of MapPart. */
-export default class OpenLayersMapPart extends MapPart {
-       /** The OpenLayers Map. */
-       #map;
-
-       /** Externally added callback functions. */
-       callbacks = {};
-
-       /** Constructor taking the mapName as an argument. */
-       constructor(mapName) {
-               super(mapName);
-               this.#map = new Map({
-                       layers: [
-                               //                              new TileLayer({
-                               //                                      source: new SentinelCloudless(),
-                               //                              }),
-                               new TileLayer({
-                                       source: new OSM(),
-                                       opacity: 0.4,
-                                       transition: 0,
-                               }),
-                       ],
-                       target: this.getMapName(),
-               });
-       }
-
-       /* GEOGRAPHICAL METHODS */
-
-       setZoom(zoom) {
-               this.#map.getView().setZoom(zoom);
-       }
-
-       setCenter(lng, lat) {
-               this.#map.getView().setCenter(fromLonLat([lng, lat]));
-       }
-
-       addPoint(lng, lat, style) {
-               let vectorSource = new VectorSource({
-                       features: [new Feature({
-                               geometry: new Point(fromLonLat([lng, lat]))
-                       })]
-               });
-               this.#map.addLayer(new VectorLayer({
-                       source: vectorSource,
-                       style: style,
-               }));
-       }
-
-       addUrlLayer(url, format, style, sld) {
-               let featureFormat;
-               if (format === 'GEOJSON') {
-                       featureFormat = new GeoJSON();
-               }
-               else if (format === 'GPX') {
-                       featureFormat = new GPX();
-               } else {
-                       throw new Error("Unsupported format " + format);
-               }
-               const vectorSource = new VectorSource({
-                       url: url,
-                       format: featureFormat,
-               });
-               const vectorLayer = new VectorLayer({
-                       source: vectorSource,
-               });
-               if (sld) {
-                       this.#applySLD(vectorLayer, style);
-               } else if (style !== null) {
-                       vectorLayer.setStyle(style);
-               }
-               this.#map.addLayer(vectorLayer);
-       }
-
-
-       /* CALLBACKS */
-       enableFeatureSingleClick() {
-               // we cannot use 'this' in the function provided to OpenLayers
-               let mapPart = this;
-               this.#map.on('singleclick', function(e) {
-                       let feature = null;
-                       // we chose the first one
-                       e.map.forEachFeatureAtPixel(e.pixel, function(f) {
-                               feature = f;
-                               return true;
-                       });
-                       if (feature !== null)
-                               mapPart.callbacks['onFeatureSingleClick'](feature.get('path'));
-               });
-       }
-
-       enableFeatureSelected() {
-               // we cannot use 'this' in the function provided to OpenLayers
-               let mapPart = this;
-               var select = new Select();
-               this.#map.addInteraction(select);
-               select.on('select', function(e) {
-                       if (e.selected.length > 0) {
-                               let feature = e.selected[0];
-                               mapPart.callbacks['onFeatureSelected'](feature.get('path'));
-                       }
-               });
-       }
-
-       enableFeaturePopup() {
-               // we cannot use 'this' in the function provided to OpenLayers
-               let mapPart = this;
-               /**
-                * Elements that make up the popup.
-                */
-               const container = document.getElementById('popup');
-               const content = document.getElementById('popup-content');
-               const closer = document.getElementById('popup-closer');
-
-               /**
-                * Create an overlay to anchor the popup to the map.
-                */
-               const overlay = new Overlay({
-                       element: container,
-                       autoPan: false,
-                       autoPanAnimation: {
-                               duration: 250,
-                       },
-               });
-               this.#map.addOverlay(overlay);
-
-               let selected = null;
-               this.#map.on('pointermove', function(e) {
-                       if (selected !== null) {
-                               selected.setStyle(undefined);
-                               selected = null;
-                       }
-
-                       e.map.forEachFeatureAtPixel(e.pixel, function(f) {
-                               selected = f;
-                               return true;
-                       });
-
-                       if (selected == null) {
-                               overlay.setPosition(undefined);
-                               return;
-                       }
-                       const coordinate = e.coordinate;
-                       const path = selected.get('path');
-                       if (path === null)
-                               return true;
-                       const res = mapPart.callbacks['onFeaturePopup'](path);
-                       if (res != null) {
-                               content.innerHTML = res;
-                               overlay.setPosition(coordinate);
-                       } else {
-                               overlay.setPosition(undefined);
-                       }
-               });
-       }
-
-       //
-       // HTML
-       //
-       getMapDivCssClass() {
-               return 'map';
-       }
-
-       //
-       // STATIC FOR EXTENSION
-       //
-       static newStyle(args) {
-               return new Style(args);
-       }
-
-       static newIcon(args) {
-               return new Icon(args);
-       }
-
-       //
-       // SLD STYLING
-       //
-       #applySLD(vectorLayer, text) {
-               const sldObject = SLDReader.Reader(text);
-               const sldLayer = SLDReader.getLayer(sldObject);
-               const style = SLDReader.getStyle(sldLayer);
-               const featureTypeStyle = style.featuretypestyles[0];
-
-               const viewProjection = this.#map.getView().getProjection();
-               const olStyleFunction = SLDReader.createOlStyleFunction(featureTypeStyle, {
-                       // Use the convertResolution option to calculate a more accurate resolution.
-                       convertResolution: viewResolution => {
-                               const viewCenter = this.#map.getView().getCenter();
-                               return getPointResolution(viewProjection, viewResolution, viewCenter);
-                       },
-                       // If you use point icons with an ExternalGraphic, you have to use imageLoadCallback
-                       // to update the vector layer when an image finishes loading.
-                       // If you do not do this, the image will only be visible after next layer pan/zoom.
-                       imageLoadedCallback: () => {
-                               vectorLayer.changed();
-                       },
-               });
-               vectorLayer.setStyle(olStyleFunction);
-       }
-}
diff --git a/js/src/org.argeo.app.geo.js/export-package.js b/js/src/org.argeo.app.geo.js/export-package.js
deleted file mode 100644 (file)
index c322c28..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-import OpenLayersMapPart from './OpenLayersMapPart.js';
-
-// PSEUDO PACKAGE
-if (typeof globalThis.argeo === 'undefined')
-       globalThis.argeo = {};
-if (typeof globalThis.argeo.app === 'undefined')
-       globalThis.argeo.app = {};
-if (typeof globalThis.argeo.app.geo === 'undefined')
-       globalThis.argeo.app.geo = {};
-
-// PUBLIC CLASSES
-globalThis.argeo.app.geo.OpenLayersMapPart = OpenLayersMapPart;
-
-"use strict";
diff --git a/js/src/org.argeo.app.geo.js/index.html b/js/src/org.argeo.app.geo.js/index.html
deleted file mode 100644 (file)
index bafe7fe..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
-       <meta charset="UTF-8">
-       <style>
-               .ol-popup {
-                       position: absolute;
-                       background-color: white;
-                       box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
-                       padding: 5px;
-                       border-radius: 10px;
-                       border: 1px solid #cccccc;
-                       bottom: 12px;
-                       left: -50px;
-                       min-width: 130px;
-               }
-
-               .ol-popup:after,
-               .ol-popup:before {
-                       top: 100%;
-                       border: solid transparent;
-                       content: " ";
-                       height: 0;
-                       width: 0;
-                       position: absolute;
-                       pointer-events: none;
-               }
-
-               .ol-popup:after {
-                       border-top-color: white;
-                       border-width: 10px;
-                       left: 48px;
-                       margin-left: -10px;
-               }
-
-               .ol-popup:before {
-                       border-top-color: #cccccc;
-                       border-width: 11px;
-                       left: 48px;
-                       margin-left: -11px;
-               }
-
-               .ol-popup-closer {
-                       text-decoration: none;
-                       position: absolute;
-                       top: 2px;
-                       right: 8px;
-               }
-
-               .ol-popup-closer:after {
-                       content: "✖";
-               }
-
-               #popup-content {
-                       font: 16px sans-serif;
-               }
-       </style>
-</head>
-
-<body>
-       <!-- Popup -->
-       <div id="popup" class="ol-popup">
-               <div id="popup-content"></div>
-       </div>
-</body>
-
-</html>
\ No newline at end of file
diff --git a/js/src/org.argeo.app.geo.js/index.js b/js/src/org.argeo.app.geo.js/index.js
deleted file mode 100644 (file)
index f389db0..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-import './export-package.js';
-
-// webpack specific
-import 'ol/ol.css';
index 88b22bceca39c6db19108027897d7ca080a31ceb..1f2f2a2b80d40c23590b34ff8305715fdde052fe 100644 (file)
@@ -5,13 +5,14 @@ const path = require('path');
 
 module.exports = {
        entry: {
-               "org.argeo.app.geo.js": { 
-                       import: './src/org.argeo.app.geo.js/index.js',
+               "geo": { 
+                       import: './src/geo/index.js',
                }
        },
        output: {
                filename: '[name].[contenthash].js',
-               path: path.resolve(__dirname, 'org.argeo.app.geo.js/org/argeo/app/geo/js'),
+               path: path.resolve(__dirname, 'org.argeo.app.js/org/argeo/app/js'),
+                       publicPath:'/pkg/org.argeo.app.js',
                clean: true,
        },
        optimization: {
@@ -43,9 +44,11 @@ module.exports = {
                new MiniCssExtractPlugin(),
                // deal with HTML generation
                new HtmlWebpackPlugin({
-                       title: 'Open Layers',
-                       template: 'src/org.argeo.app.geo.js/index.html',
+                       title: 'Argeo Suite Geo JS',
+                       template: 'src/geo/index.html',
                        scriptLoading: 'module',
+                       filename: 'geo.html',
+                       chunks: ['geo'],
                }),
 
        ],
index ece95085a9b0b002bcbad9f0b832a5a2baab445e..ad1a9faa9989afff42dbc158dc1f8b68184aa400 100644 (file)
@@ -19,7 +19,7 @@ public class SwtJSMapPart extends SwtBrowserJsPart implements MapPart {
        private final String mapName;// = "argeoMap";
 
        public SwtJSMapPart(String mapName, Composite parent, int style) {
-               super(parent, style, "/pkg/org.argeo.app.geo.js/index.html");
+               super(parent, style, "/pkg/org.argeo.app.js/geo.html");
                this.mapName = mapName;
        }