/** 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");
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");
+ }
}
*/
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 } from 'ol/proj.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 MapPart from './MapPart.js';
import { SentinelCloudless } from './OpenLayerTileSources.js';
export default class OpenLayersMapPart extends MapPart {
/** The OpenLayers Map. */
#map;
+
+ /** Externally added callback functions. */
callbacks = {};
- // Constructor
- constructor() {
- super();
+ /** 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 SentinelCloudless(),
+ // }),
new TileLayer({
source: new OSM(),
opacity: 0.4,
transition: 0,
}),
],
- target: 'map',
+ target: this.getMapName(),
});
}
geometry: new Point(fromLonLat([lng, lat]))
})]
});
- this.#map.addLayer(new VectorLayer({ source: vectorSource }));
+ this.#map.addLayer(new VectorLayer({
+ source: vectorSource,
+ style: style,
+ }));
}
- addUrlLayer(url, format) {
+ addUrlLayer(url, format, style) {
let vectorSource;
if (format === 'GEOJSON') {
vectorSource = new VectorSource({ url: url, format: new GeoJSON() })
}
this.#map.addLayer(new VectorLayer({
source: vectorSource,
+ style: style,
}));
}
}
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;
}
});
}
+
+ //
+ // HTML
+ //
+ getMapDivCssClass() {
+ return 'map';
+ }
+
+ //
+ // STATIC FOR EXTENSION
+ //
+ static newStyle(args){
+ return new Style(args);
+ }
+
+ static newIcon(args){
+ return new Icon(args);
+ }
+
+
}
<head>
<meta charset="UTF-8">
<style>
- .map {
- width: 100%;
- height: 100vh;
- }
-
.ol-popup {
position: absolute;
background-color: white;
</head>
<body>
- <div id="map" class="map"></div>
-
<!-- Popup -->
<div id="popup" class="ol-popup">
<div id="popup-content"></div>
void addPoint(double lng, double lat, String style);
- void addUrlLayer(String url, GeoFormat format);
+ void addUrlLayer(String url, GeoFormat format, String style);
void setZoom(int zoom);
/** Event when a feature has been selected. */
record FeatureSelectedEvent(String path) {
};
+
/** Event when a feature popup is requested. */
record FeaturePopupEvent(String path) {
};
import static org.argeo.app.geo.CqlUtils.CQL_FILTER;
import java.io.IOException;
+import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
+import javax.xml.namespace.QName;
+
import org.argeo.api.acr.Content;
import org.argeo.api.acr.ContentSession;
import org.argeo.api.acr.NamespaceUtils;
import org.argeo.api.acr.ldap.LdapAttr;
import org.argeo.api.acr.spi.ProvidedRepository;
+import org.argeo.app.api.EntityName;
import org.argeo.app.api.EntityType;
import org.argeo.app.api.WGS84PosName;
import org.argeo.app.geo.CqlUtils;
+import org.argeo.app.geo.GpxUtils;
import org.argeo.cms.http.HttpHeader;
import org.argeo.cms.http.server.HttpServerUtils;
import org.geotools.data.DataUtilities;
import org.geotools.filter.text.cql2.CQL;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
-import org.locationtech.jts.geom.Point;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
ContentSession session = HttpServerUtils.getContentSession(contentRepository, exchange);
// Content content = session.get(path);
- exchange.getResponseHeaders().set(HttpHeader.CONTENT_TYPE.getHeaderName(), "application/json; charset=utf-8");
+ exchange.getResponseHeaders().set(HttpHeader.CONTENT_TYPE.getHeaderName(), "application/json");
Map<String, List<String>> parameters = HttpServerUtils.parseParameters(exchange);
String cql = parameters.containsKey(CQL_FILTER) ? parameters.get(CQL_FILTER).get(0) : null;
search.getWhere().isContentClass(EntityType.local);
});
+ exchange.sendResponseHeaders(200, 0);
+
+ // BODY PROCESSING
GeoJSONWriter geoJSONWriter = new GeoJSONWriter(exchange.getResponseBody());
geoJSONWriter.setPrettyPrinting(true);
// "features": [
// """);
+ boolean gpx = false;
SimpleFeatureType TYPE;
try {
- TYPE = DataUtilities.createType("Content", "the_geom:Point:srid=4326,path:String,name:String");
+ if (gpx)
+ TYPE = DataUtilities.createType("Content", "the_geom:Polygon:srid=4326,path:String,type:String");
+ else
+ TYPE = DataUtilities.createType("Content", "the_geom:Point:srid=4326,path:String,type:String");
} catch (SchemaException e) {
throw new RuntimeException(e);
}
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
res.forEach((c) -> {
- if (!c.hasContentClass(EntityType.geopoint))
- return;
-
- double latitude = c.get(WGS84PosName.lat, Double.class).get();
- double longitude = c.get(WGS84PosName.lng, Double.class).get();
+ Geometry the_geom;
+ if (gpx) {// experimental
+ Content area = c.getContent("gpx/area.gpx").orElse(null);
+ if (area == null)
+ return;
+ try (InputStream in = area.open(InputStream.class)) {
+ SimpleFeature feature = GpxUtils.parseGpxToPolygon(in);
+ the_geom = (Geometry) feature.getDefaultGeometry();
+ } catch (IOException e) {
+ throw new UncheckedIOException("Cannot parse " + c, e);
+ }
+ } else {
+ if (!c.hasContentClass(EntityType.geopoint))
+ return;
+
+ double latitude = c.get(WGS84PosName.lat, Double.class).get();
+ double longitude = c.get(WGS84PosName.lng, Double.class).get();
+
+ Coordinate coordinate = new Coordinate(longitude, latitude);
+ the_geom = geometryFactory.createPoint(coordinate);
- Coordinate coordinate = new Coordinate(longitude, latitude);
- Point point = geometryFactory.createPoint(coordinate);
+ }
- featureBuilder.add(point);
+ featureBuilder.add(the_geom);
String pth = c.getPath();
featureBuilder.add(pth);
- featureBuilder.add(NamespaceUtils.toPrefixedName(c.getName()));
+ if (c.hasContentClass(EntityType.local)) {
+ String type = c.attr(EntityName.type);
+ featureBuilder.add(type);
+ } else {
+ List<QName> contentClasses = c.getContentClasses();
+ if (!contentClasses.isEmpty()) {
+ featureBuilder.add(NamespaceUtils.toPrefixedName(contentClasses.get(0)));
+ }
+ }
String uuid = c.attr(LdapAttr.entryUUID);
@Override
public Control createUiPart(Composite parent, Content context) {
- SwtJSMapPart map = new SwtJSMapPart(parent, 0);
+ SwtJSMapPart map = new SwtJSMapPart("defaultOverviewMap", parent, 0);
map.setCenter(13.404954, 52.520008); // Berlin
// map.setCenter(-74.00597, 40.71427); // NYC
// map.addPoint(-74.00597, 40.71427, null);
map.setZoom(6);
// map.addUrlLayer("https://openlayers.org/en/v4.6.5/examples/data/geojson/countries.geojson",
// Format.GEOJSON);
- return map;
+ return map.getControl();
}
}
import org.argeo.api.cms.CmsLog;
import org.argeo.app.geo.ux.JsImplementation;
import org.argeo.app.geo.ux.MapPart;
-import org.argeo.cms.swt.CmsSwtUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.BrowserFunction;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
/**
* An SWT implementation of {@link MapPart} based on JavaScript execute in a
* {@link Browser} control.
*/
-public class SwtJSMapPart extends Composite implements MapPart {
+public class SwtJSMapPart implements MapPart {
static final long serialVersionUID = 2713128477504858552L;
private final static CmsLog log = CmsLog.getLog(SwtJSMapPart.class);
private final CompletableFuture<Boolean> pageLoaded = new CompletableFuture<>();
private String jsImplementation = JsImplementation.OPENLAYERS_MAP_PART.getJsClass();
- private String mapVar = "argeoMap";
+ private final String mapName;// = "argeoMap";
- public SwtJSMapPart(Composite parent, int style) {
- super(parent, style);
- parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
- setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- setLayout(CmsSwtUtils.noSpaceGridLayout());
-
- browser = new Browser(this, SWT.BORDER);
+ public SwtJSMapPart(String mapName, Composite parent, int style) {
+ this.mapName = mapName;
+ browser = new Browser(parent, 0);
browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
browser.setUrl("/pkg/org.argeo.app.geo.js/index.html");
public void completed(ProgressEvent event) {
try {
// create map
- browser.execute(getJsMapVar() + " = new " + jsImplementation + "();");
+ browser.execute(getJsMapVar() + " = new " + jsImplementation + "('" + mapName + "');");
+ loadExtensions();
pageLoaded.complete(true);
} catch (Exception e) {
log.error("Cannot create map in browser", e);
});
}
+ public Control getControl() {
+ return browser;
+ }
+
/*
* MapPart.js METHODS
*/
}
@Override
- public void addUrlLayer(String url, GeoFormat format) {
- callMapMethod("addUrlLayer('%s', '%s')", url, format.name());
+ public void addUrlLayer(String url, GeoFormat format, String style) {
+ callMapMethod("addUrlLayer('%s', '%s', %s)", url, format.name(), style);
}
@Override
}
private String getJsMapVar() {
- return GLOBAL_THIS_ + mapVar;
+ return GLOBAL_THIS_ + mapName;
}
/**
protected CompletionStage<Object> evaluate(String js, Object... args) {
CompletableFuture<Object> res = pageLoaded.thenApply((ready) -> {
if (!ready)
- throw new IllegalStateException("Map " + mapVar + " is not initialised.");
+ throw new IllegalStateException("Map " + mapName + " is not initialised.");
Object result = browser.evaluate(String.format(Locale.ROOT, js, args));
return result;
});
return res.minimalCompletionStage();
}
+ protected void loadExtension(String url) {
+// String js = """
+// var script = document.createElement("script");
+// script.src = '%s';
+// document.head.appendChild(script);
+// """;
+// browser.evaluate(String.format(Locale.ROOT, js, url));
+ browser.evaluate(String.format(Locale.ROOT, "import('%s')", url));
+ }
+
+ /** To be overridden with calls to {@link #loadExtension(String)}. */
+ protected void loadExtensions() {
+
+ }
+
/*
* CALLBACKS
*/
protected void addCallback(String suffix, Function<Object[], Object> toDo) {
pageLoaded.thenAccept((ready) -> {
// browser functions must be directly on window (RAP specific)
- new BrowserFunction(browser, mapVar + "__on" + suffix) {
+ new BrowserFunction(browser, mapName + "__on" + suffix) {
@Override
public Object function(Object[] arguments) {
}
};
- browser.execute(getJsMapVar() + ".callbacks['on" + suffix + "']=window." + mapVar + "__on" + suffix + ";");
- callMethod(mapVar, "enable" + suffix + "()");
+ browser.execute(getJsMapVar() + ".callbacks['on" + suffix + "']=window." + mapName + "__on" + suffix + ";");
+ callMethod(mapName, "enable" + suffix + "()");
});
}
}