diff --git a/openlayers3-parent/openlayers3-examples/pom.xml b/openlayers3-parent/openlayers3-examples/pom.xml index a7b111dabe..c2baf806f4 100644 --- a/openlayers3-parent/openlayers3-examples/pom.xml +++ b/openlayers3-parent/openlayers3-examples/pom.xml @@ -45,6 +45,11 @@ wicketstuff-annotation ${project.version} + + de.agilecoders.wicket + wicket-bootstrap-extensions + 0.10.0 + diff --git a/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.html b/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.html index c2148c5a1a..73d17cc551 100644 --- a/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.html +++ b/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.html @@ -5,7 +5,16 @@

Below is a map of the world. This map centered on the location of Miles' office and provides a - helpful marker to ensure that you don't miss it.

+ helpful marker to ensure that you don't miss it. Use the layer drop-down to toggle between + the street layer and the satellite layer.

+ +
+
+
+ +
+
+
[MARKER]
diff --git a/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.java b/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.java index c3dfeb37f1..aae787e697 100644 --- a/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.java +++ b/openlayers3-parent/openlayers3-examples/src/main/java/org/wicketstuff/openlayers3/examples/MarkerPage.java @@ -2,7 +2,13 @@ import java.util.Arrays; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; +import org.apache.wicket.model.util.ListModel; import org.wicketstuff.annotation.mount.MountPath; import org.wicketstuff.openlayers3.DefaultOpenLayersMap; import org.wicketstuff.openlayers3.api.Map; @@ -12,30 +18,57 @@ import org.wicketstuff.openlayers3.api.layer.Tile; import org.wicketstuff.openlayers3.api.overlay.Overlay; import org.wicketstuff.openlayers3.api.source.tile.Osm; +import org.wicketstuff.openlayers3.api.source.tile.XYZ; import org.wicketstuff.openlayers3.api.util.Color; import org.wicketstuff.openlayers3.component.Marker; import org.wicketstuff.openlayers3.examples.base.BasePage; +import de.agilecoders.wicket.core.markup.html.bootstrap.form.BootstrapForm; +import de.agilecoders.wicket.core.markup.html.bootstrap.form.FormGroup; +import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.select.BootstrapSelect; + /** * Provides a page with a mpa that includes a marker. */ @MountPath("/marker") public class MarkerPage extends BasePage { - /** - * Marker over Miles' office. - */ - private Marker marker; + private static final String MA_ORTHO_URL = "http://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/USGS_Orthos_2013_2014/MapServer/tile/{z}/{y}/{x}"; - @Override - protected void onInitialize() { - super.onInitialize(); + private enum LayerOption { + STREET, + SATELLITE; + } - // create and add our marker - add(marker = new Marker("marker", Model.of(new Color("#4169E1")))); + private static class LayerSelectedModel extends LoadableDetachableModel { + + private IModel model; + private LayerOption layerOption; + + public LayerSelectedModel(IModel model, LayerOption layerOption) { + this.model = model; + this.layerOption = layerOption; + } + + @Override + protected Boolean load() { + return layerOption.equals(model.getObject()); + } + + } + + public MarkerPage() { + super(); + + // model of the selected layer + final IModel model = Model.of(LayerOption.STREET); + + // create and add our marker over Miles' office + Marker marker = new Marker("marker", Model.of(new Color("#4169E1"))); + add(marker); // create and add our marker - add(new DefaultOpenLayersMap("map", + final DefaultOpenLayersMap map = new DefaultOpenLayersMap("map", // create the model for our map Model.of(new Map( @@ -43,11 +76,21 @@ protected void onInitialize() { // list of layers Arrays.asList( - // a new tile layer with the map of the world + // a new tile layer with the street map of Noho new Tile("Streets", // a new web map service tile layer - new Osm())), + new Osm(), + // visible when the layer selector is street + new LayerSelectedModel(model, LayerOption.STREET)), + + // a new tile layer with the satellite map of Noho + new Tile("Ortho", + + // MA ortho-imagery layer + new XYZ().setUrl(MA_ORTHO_URL), + // visible when the layer selector is satellite + new LayerSelectedModel(model, LayerOption.SATELLITE))), // list of overlays Arrays.asList( @@ -69,6 +112,27 @@ protected void onInitialize() { new LongLat(-72.638382, 42.313181, "EPSG:4326").transform(View.DEFAULT_PROJECTION), // zoom level for the view - 16))))); + 16)))); + add(map); + + // form for changing the layer + Form form = new BootstrapForm<>("form", model); + add(form); + + // layer selector -- refresh the map's layers on change + form.add(new FormGroup("layer") + .add(new BootstrapSelect<>("layerSelector", model, + new ListModel<>(Arrays.asList(LayerOption.values()))) + .setLabel(Model.of("Layer")) + .add(new AjaxFormComponentUpdatingBehavior("change") { + + @Override + protected void onUpdate(AjaxRequestTarget target) { + map.updateLayers(target); + } + + }))); + } + } diff --git a/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/OpenLayersMap.java b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/OpenLayersMap.java index 632a84d6f4..c33326acfa 100644 --- a/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/OpenLayersMap.java +++ b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/OpenLayersMap.java @@ -31,28 +31,25 @@ public abstract class OpenLayersMap extends GenericPanel { /** * Map of layers to the data loaded handler that notifies their listeners. */ - private java.util.Map layerDataLoadedMap = - new HashMap(); + private java.util.Map layerDataLoadedMap = new HashMap(); /** * Map of layers to the data loaded handler that notifies their listeners. */ - private java.util.Map layerLoadedMap = - new HashMap(); + private java.util.Map layerLoadedMap = new HashMap(); /** * Creates a new instance * * @param id - * Wicket element ID + * Wicket element ID * @param model - * Backing modep for this map + * Backing modep for this map */ public OpenLayersMap(final String id, final IModel model) { super(id, model); } - @Override protected void onConfigure() { super.onConfigure(); @@ -68,36 +65,37 @@ protected void onConfigure() { final Vector vectorLayer = (Vector) layer; - if(vectorLayer.getFeatureDataLoadedListeners() != null + if (vectorLayer.getFeatureDataLoadedListeners() != null && vectorLayer.getFeatureDataLoadedListeners().size() > 0) { // add a behavior to be notified when new data is loaded - VectorFeatureDataLoadedListener vectorFeatureDataLoadedListener = - new VectorFeatureDataLoadedListener(vectorLayer) { - - @Override - public void handleDataLoaded(AjaxRequestTarget target, JsonArray features) { - vectorLayer.notifyFeatureDataLoadedListeners(target, features); - } - }; + VectorFeatureDataLoadedListener vectorFeatureDataLoadedListener = new VectorFeatureDataLoadedListener( + vectorLayer) { + + @Override + public void handleDataLoaded(AjaxRequestTarget target, JsonArray features) { + vectorLayer.notifyFeatureDataLoadedListeners(target, features); + } + }; add(vectorFeatureDataLoadedListener); // map the layer to the data loaded handler layerDataLoadedMap.put(layer, vectorFeatureDataLoadedListener); } - if(vectorLayer.getFeaturesLoadedListeners() != null + if (vectorLayer.getFeaturesLoadedListeners() != null && vectorLayer.getFeaturesLoadedListeners().size() > 0) { - // add a behavior to be notified when new features are loaded - VectorFeaturesLoadedListener vectorFeatureLoadedListener = - new VectorFeaturesLoadedListener(vectorLayer) { + // add a behavior to be notified when new features are + // loaded + VectorFeaturesLoadedListener vectorFeatureLoadedListener = new VectorFeaturesLoadedListener( + vectorLayer) { - @Override - public void handleDataLoaded(AjaxRequestTarget target) { - vectorLayer.notifyFeaturesLoadedListeners(target); - } - }; + @Override + public void handleDataLoaded(AjaxRequestTarget target) { + vectorLayer.notifyFeaturesLoadedListeners(target); + } + }; add(vectorFeatureLoadedListener); // map the layer to the data loaded handler @@ -109,26 +107,28 @@ public void handleDataLoaded(AjaxRequestTarget target) { } /** - * Zooms the map to an extent that includes all of the features on the provided vector layer. + * Zooms the map to an extent that includes all of the features on the + * provided vector layer. * * @param target - * Ajax request target + * Ajax request target * @param vector - * Vector layer containing features + * Vector layer containing features */ public void zoomToFeatureExtent(AjaxRequestTarget target, Vector vector) { this.zoomToFeatureExtent(target, vector, 0); } /** - * Zooms the map to an extent that includes all of the features on the provided vector layer. + * Zooms the map to an extent that includes all of the features on the + * provided vector layer. * * @param target - * Ajax request target + * Ajax request target * @param vector - * Vector layer containing features + * Vector layer containing features * @param buffer - * Buffer around the calculated extent + * Buffer around the calculated extent */ public void zoomToFeatureExtent(AjaxRequestTarget target, Vector vector, Number buffer) { StringBuilder builder = new StringBuilder(); @@ -149,8 +149,10 @@ public void zoomToFeatureExtent(AjaxRequestTarget target, Vector vector, Number /** * Sets the center of the map's current view. * - * @param target Ajax request target - * @param point New center location for the map + * @param target + * Ajax request target + * @param point + * New center location for the map */ public void setViewCenter(AjaxRequestTarget target, Point point) { @@ -165,8 +167,10 @@ public void setViewCenter(AjaxRequestTarget target, Point point) { /** * Adds the provided interaction to the map. * - * @param target Ajax request target - * @param interaction Interaction to add + * @param target + * Ajax request target + * @param interaction + * Interaction to add */ public void addInteraction(AjaxRequestTarget target, Interaction interaction) { @@ -174,16 +178,18 @@ public void addInteraction(AjaxRequestTarget target, Interaction interaction) { getModelObject().getInteractions().add(interaction); // update the map - target.appendJavaScript(interaction.getJsId() + " = new " + interaction.getJsType() - + "(" + interaction.renderJs() + ");" - + JavascriptObject.JS_GLOBAL + "['map_" + getMarkupId() + "'].addInteraction(" + interaction.getJsId() + ");"); + target.appendJavaScript(interaction.getJsId() + " = new " + interaction.getJsType() + "(" + + interaction.renderJs() + ");" + JavascriptObject.JS_GLOBAL + "['map_" + getMarkupId() + + "'].addInteraction(" + interaction.getJsId() + ");"); } /** * Removes provided interaction from the map. * - * @param target Ajax request target - * @param interaction Interaction to add + * @param target + * Ajax request target + * @param interaction + * Interaction to add */ public void removeInteraction(AjaxRequestTarget target, Interaction interaction) { @@ -192,20 +198,22 @@ public void removeInteraction(AjaxRequestTarget target, Interaction interaction) // update the map target.appendJavaScript(JavascriptObject.JS_GLOBAL + "['map_" + getMarkupId() + "'].removeInteraction(" - + interaction.getJsId() + ");"); + + interaction.getJsId() + ");"); } - /** + /** * Sets the extent for the map and zooms to that extent. * - * @param target Ajax request target - * @param extent Extent to which the map will be zoomed + * @param target + * Ajax request target + * @param extent + * Extent to which the map will be zoomed */ - public void zoomToExtent(AjaxRequestTarget target, Extent extent) { - target.appendJavaScript(JavascriptObject.JS_GLOBAL + "['map_" + getMarkupId() + "'].getView().fit(" - + getModelObject().getView().getExtent().renderJsForView(getModelObject().getView()) + "," - + JavascriptObject.JS_GLOBAL + "['map_" + getMarkupId() + "']" + ".getSize());"); - } + public void zoomToExtent(AjaxRequestTarget target, Extent extent) { + target.appendJavaScript(JavascriptObject.JS_GLOBAL + "['map_" + getMarkupId() + "'].getView().fit(" + + getModelObject().getView().getExtent().renderJsForView(getModelObject().getView()) + "," + + JavascriptObject.JS_GLOBAL + "['map_" + getMarkupId() + "']" + ".getSize());"); + } @Override public abstract void renderHead(final IHeaderResponse response); @@ -219,9 +227,9 @@ public String renderBeforeConstructorJs() { StringBuilder builder = new StringBuilder(); - // make sure our global variable exists - builder.append("if(typeof " + JavascriptObject.JS_GLOBAL + " === 'undefined') { " - + JavascriptObject.JS_GLOBAL + " = []};\n\n"); + // make sure our global variable exists + builder.append("if(typeof " + JavascriptObject.JS_GLOBAL + " === 'undefined') { " + JavascriptObject.JS_GLOBAL + + " = []};\n\n"); Map map = getModelObject(); if (map != null) { @@ -235,9 +243,9 @@ public String renderBeforeConstructorJs() { VectorSource vectorSource = vectorLayer.getSource(); // render any persistent features - if(vectorSource.getFeatures() != null) { - for(Feature feature : vectorSource.getFeatures()) { - if(feature instanceof PersistentFeature) { + if (vectorSource.getFeatures() != null) { + for (Feature feature : vectorSource.getFeatures()) { + if (feature instanceof PersistentFeature) { builder.append(feature.getJsId() + " = new " + feature.getJsType() + "(" + feature.renderJs() + ");\n"); } @@ -245,12 +253,12 @@ public String renderBeforeConstructorJs() { } // ensure our loader has a reference to our source - if(vectorSource.getLoader() != null) { + if (vectorSource.getLoader() != null) { vectorSource.getLoader().setSource(vectorSource); } // render the source for the cluster source - if(vectorSource instanceof Cluster) { + if (vectorSource instanceof Cluster) { Cluster source = (Cluster) vectorSource; builder.append(renderServerVectorJs(source.getSource(), layer)); } @@ -259,8 +267,7 @@ public String renderBeforeConstructorJs() { builder.append(renderServerVectorJs(vectorSource, layer)); } - builder.append(layer.getJsId() + " = new " + layer.getJsType() + "(" + layer.renderJs() - + ");\n"); + builder.append(layer.getJsId() + " = new " + layer.getJsType() + "(" + layer.renderJs() + ");\n"); } } @@ -271,8 +278,8 @@ private String renderServerVectorJs(VectorSource vectorSource, Layer layer) { StringBuilder builder = new StringBuilder(); - builder.append(vectorSource.getJsId() + " = new " + vectorSource.getJsType() + "(" - + vectorSource.renderJs() + ");\n"); + builder.append( + vectorSource.getJsId() + " = new " + vectorSource.getJsType() + "(" + vectorSource.renderJs() + ");\n"); if (vectorSource.getLoader() instanceof DefaultGeoJsonLoader) { DefaultGeoJsonLoader loader = (DefaultGeoJsonLoader) vectorSource.getLoader(); @@ -295,7 +302,8 @@ private String renderServerVectorJs(VectorSource vectorSource, Layer layer) { } /** - * Renders the Javascript after the construction of our OL3 objects (but not the map). + * Renders the Javascript after the construction of our OL3 objects (but not + * the map). * * @return String with the rendered Javascript */ @@ -309,7 +317,7 @@ public String renderAfterConstructorJs() { for (Layer layer : map.getLayers()) { - if(layer instanceof Vector) { + if (layer instanceof Vector) { Vector vectorLayer = (Vector) layer; VectorSource vectorSource = vectorLayer.getSource(); @@ -336,9 +344,9 @@ public String renderAfterMapConstructorJs() { Map map = getModelObject(); - if(map.getView().getExtent() != null) { - builder.append(map.getJsId() + ".getView().fit(" + map.getView().getExtent().renderJsForView(map.getView()) + "," - + map.getJsId() + ".getSize());"); + if (map.getView().getExtent() != null) { + builder.append(map.getJsId() + ".getView().fit(" + map.getView().getExtent().renderJsForView(map.getView()) + + "," + map.getJsId() + ".getSize());"); } return builder.toString(); @@ -351,7 +359,7 @@ public String renderAfterMapConstructorJs() { */ public String renderJs() { - Map map = getModelObject(); + Map map = getModelObject(); StringBuilder builder = new StringBuilder(); builder.append(renderBeforeConstructorJs() + "\n\n"); @@ -362,4 +370,30 @@ public String renderJs() { builder.append(renderAfterMapConstructorJs()); return builder.toString(); } + + /** + * Refreshes via ajax all of the maps layers. + * + * @param target + */ + public void updateLayers(AjaxRequestTarget target) { + for (Layer layer : getModelObject().getLayers()) { + layer.onUpdate(target); + } + } + + /** + * Calls detach on all of the layers in the map. + * + * @see org.apache.wicket.MarkupContainer#onDetach() + */ + @Override + public void onDetach() { + super.onDetach(); + Map map = getModel().getObject(); + for (Layer layer : map.getLayers()) { + layer.detach(); + } + } + } diff --git a/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Layer.java b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Layer.java index ddf2c0fa0b..c6bc7bfece 100644 --- a/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Layer.java +++ b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Layer.java @@ -1,24 +1,73 @@ package org.wicketstuff.openlayers3.api.layer; +import java.io.Serializable; + import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.IModel; import org.wicketstuff.openlayers3.api.JavascriptObject; -import java.io.Serializable; - /** * Provides an object that models a layer. */ public abstract class Layer extends JavascriptObject implements Serializable { + private IModel visibleModel; + + /** + * Creates a new Layer. + */ + public Layer() { + super(); + } + + /** + * Creates a new Layer with the visibility determined by the + * {@code visibleModel} + * + * @param visibleModel + * a modle of whether the layer is visible + */ + public Layer(IModel visibleModel) { + this.visibleModel = visibleModel; + } + /** * Sets the visiblity of the layer. * * @param target - * Ajax request target + * Ajax request target * @param visible - * Flag with the visibility of the layer + * Flag with the visibility of the layer */ public void setVisible(AjaxRequestTarget target, boolean visible) { target.appendJavaScript(getJsId() + ".setVisible(" + visible + ")"); } + + /** + * Callback for updating the layer via ajax. + * + * @param target + */ + public void onUpdate(AjaxRequestTarget target) { + if (visibleModel != null) { + target.appendJavaScript(getJsId() + ".setVisible(" + visibleModel.getObject() + ")"); + } + } + + /** + * @return the model of the visibility of the layer + */ + protected IModel getVisibleModel() { + return visibleModel; + } + + /** + * Callback for detaching any resources (e.g., models). + */ + public void detach() { + if (visibleModel != null) { + visibleModel.detach(); + } + } + } diff --git a/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Tile.java b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Tile.java index 4ee6d05514..a8ae55e9ad 100644 --- a/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Tile.java +++ b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/layer/Tile.java @@ -1,5 +1,6 @@ package org.wicketstuff.openlayers3.api.layer; +import org.apache.wicket.model.IModel; import org.wicketstuff.openlayers3.api.source.tile.TileSource; /** @@ -42,6 +43,21 @@ public Tile(String title, TileSource source) { setSource(source); } + /** + * Creates a new instance. + * + * @param title + * The title for the layer + * @param source + * The source of data for this layer + */ + public Tile(String title, TileSource source, IModel visibleModel) { + super(visibleModel); + + this.title = title; + setSource(source); + } + /** * Returns the title for this layer. * @@ -119,6 +135,10 @@ public String renderJs() { builder.append("'title': '" + getTitle() + "',"); } + if (getVisibleModel() != null) { + builder.append("'visible': " + getVisibleModel().getObject() + ","); + } + builder.append("'source': new " + getSource().getJsType() + "("); builder.append(getSource().renderJs()); builder.append(")"); diff --git a/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/source/tile/XYZ.java b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/source/tile/XYZ.java new file mode 100644 index 0000000000..eb51a4bbdd --- /dev/null +++ b/openlayers3-parent/openlayers3/src/main/java/org/wicketstuff/openlayers3/api/source/tile/XYZ.java @@ -0,0 +1,41 @@ +package org.wicketstuff.openlayers3.api.source.tile; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Joiner; + +/** + * Provides an object that models an XYZ data source where the requested tiles are part of the URL. + * The placeholders {x}, {y} and {z} are used to indicate how the URL is to be constructed. + *

+ * Example: new XYZ().setUrl("http://tiles.arcgis.com/tiles/hGdibHYSPO59RG1h/arcgis/rest/services/USGS_Orthos_2013_2014/MapServer/tile/{z}/{y}/{x}") + *

+ * @see http://openlayers.org/en/latest/apidoc/ol.source.XYZ.html + */ +public class XYZ extends TileSource { + + private String url; + + public String getUrl() { + return url; + } + + public XYZ setUrl(String url) { + this.url = url; + return this; + } + + @Override + public String getJsType() { + return "ol.source.XYZ"; + } + + @Override + public String renderJs() { + List list = new ArrayList<>(); + list.add("'url': '" + getUrl() + "'"); + return "{" + Joiner.on(", ").join(list) + "}"; + } + +} diff --git a/openlayers3-parent/pom.xml b/openlayers3-parent/pom.xml index 3586175057..ee95f0971b 100644 --- a/openlayers3-parent/pom.xml +++ b/openlayers3-parent/pom.xml @@ -1,46 +1,47 @@ - + - 4.0.0 + 4.0.0 - - org.wicketstuff - wicketstuff-core - 7.4.0-SNAPSHOT - + + org.wicketstuff + wicketstuff-core + 7.4.0-SNAPSHOT + - openlayers3-parent - pom + openlayers3-parent + pom - Openlayers3 Integration - Parent - + Openlayers3 Integration - Parent + See the child project "openlayers3" for a more complete description. This is the parent for the actual project and the examples. - - openlayers3 - openlayers3-bootstrap - openlayers3-examples - + + openlayers3 + openlayers3-bootstrap + openlayers3-examples + - - - - ${project.groupId} - wicketstuff-openlayers3 - ${project.version} - - - de.agilecoders.wicket.webjars - wicket-webjars - 0.5.3 - - - org.webjars - openlayers - 3.10.1 - - - + + + + ${project.groupId} + wicketstuff-openlayers3 + ${project.version} + + + de.agilecoders.wicket.webjars + wicket-webjars + 0.5.3 + + + org.webjars + openlayers + 3.10.1 + + +