package org.sigmah.client.ui.widget.map;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gwtopenmaps.openlayers.client.Bounds;
import org.gwtopenmaps.openlayers.client.LonLat;
import org.gwtopenmaps.openlayers.client.MapOptions;
import org.gwtopenmaps.openlayers.client.MapWidget;
import org.gwtopenmaps.openlayers.client.Pixel;
import org.gwtopenmaps.openlayers.client.Style;
import org.gwtopenmaps.openlayers.client.control.DragFeature;
import org.gwtopenmaps.openlayers.client.control.DragFeatureOptions;
import org.gwtopenmaps.openlayers.client.control.LayerSwitcher;
import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
import org.gwtopenmaps.openlayers.client.geometry.Point;
import org.gwtopenmaps.openlayers.client.layer.OSM;
import org.gwtopenmaps.openlayers.client.layer.OSMOptions;
import org.gwtopenmaps.openlayers.client.layer.Vector;
import org.gwtopenmaps.openlayers.client.layer.XYZ;
import org.sigmah.client.i18n.I18N;
import org.sigmah.shared.dto.BoundingBoxDTO;
/**
* OpenStreetMap implementation of WorldMap.
*
* @author Raphaƫl Calabro (rcalabro@ideia.fr)
*/
public class OpenStreetMapWorldMap extends AbstractWorldMap<VectorFeature> {
private static final String TRANSFORM_SOURCE = "EPSG:4326";
private MapWidget mapWidget;
private Vector vectorLayer;
private DragFeature dragFeature;
private boolean draggable;
private final List<VectorFeature> displayedFeatures = new ArrayList<VectorFeature>();
private final Map<String, List<PinDragEndHandler>> dragEndHandlers = new HashMap<String, List<PinDragEndHandler>>();
private static int featureIdSequence;
@Override
protected void init() {
mapWidget = new MapWidget("100%", "100%", new MapOptions());
// Humanitarian layer
final OSMOptions hotOption = new OSMOptions();
hotOption.setIsBaseLayer(true);
hotOption.crossOriginFix();
hotOption.setSphericalMercator(true);
XYZ HOTLayer = new XYZ(I18N.CONSTANTS.humanitarianOSMLayer(), "http://a.tile.openstreetmap.fr/hot/${z}/${x}/${y}.png", hotOption);
// Basic layer
OSM osmMapnik = new OSM();
osmMapnik.setName(I18N.CONSTANTS.basicOSMLayer());
osmMapnik.setIsBaseLayer(true);
// Pin layer
vectorLayer = new Vector(I18N.CONSTANTS.projectSitesLayer());
// Drag & drop listeners
dragFeature = createDraggableFeature(vectorLayer);
// Center & zoom
LonLat lonLat = new LonLat(0, 0);
lonLat.transform(TRANSFORM_SOURCE, mapWidget.getMap().getProjection());
mapWidget.getMap().addLayer(HOTLayer);
mapWidget.getMap().addLayer(osmMapnik);
mapWidget.getMap().addLayer(vectorLayer);
mapWidget.getMap().addControl(new LayerSwitcher());
mapWidget.getMap().setCenter(lonLat, 1);
mapWidget.getMap().updateSize();
getRoot().add(mapWidget);
setInitialized(true);
}
@Override
public String getName() {
return "OpenStreetMap";
}
@Override
protected void displayBounds(BoundingBoxDTO bounds) {
final LonLat lower = new LonLat(bounds.getX1(), bounds.getY1());
lower.transform(TRANSFORM_SOURCE, mapWidget.getMap().getProjection());
final LonLat upper = new LonLat(bounds.getX2(), bounds.getY2());
upper.transform(TRANSFORM_SOURCE, mapWidget.getMap().getProjection());
final Bounds b = new Bounds(lower.lon(), lower.lat(), upper.lon(), upper.lat());
mapWidget.getMap().setCenter(b.getCenterLonLat(),
mapWidget.getMap().getZoomForExtent(b, false));
mapWidget.getMap().updateSize();
}
@Override
protected void displayCenterAndZoom(double latitude, double longitude, int zoom) {
final LonLat lonLat = new LonLat(longitude, latitude);
lonLat.transform(TRANSFORM_SOURCE, mapWidget.getMap().getProjection());
mapWidget.getMap().setCenter(lonLat, zoom);
}
@Override
protected void displayPins(List<VectorFeature> vectorFeatures) {
for(final VectorFeature displayedFeature : displayedFeatures) {
vectorLayer.removeFeature(displayedFeature);
dragEndHandlers.remove(displayedFeature.getFeatureId());
}
displayedFeatures.clear();
for(final VectorFeature vectorFeature : vectorFeatures) {
vectorLayer.addFeature(vectorFeature);
displayedFeatures.add(vectorFeature);
}
}
@Override
protected VectorFeature createNativePin(Pin pin) {
final Style style = new Style();
if(pin.getTitle() != null) {
style.setLabel(pin.getTitle());
}
if(pin.getImageURL() != null) {
style.setExternalGraphic(pin.getImageURL());
style.setGraphicSize(pin.getImageWidth(), pin.getImageHeight());
style.setGraphicOffset(
// Horizontal center
-pin.getImageWidth() / 2,
// Bottom
-pin.getImageHeight());
} else {
style.setExternalGraphic("http://www.google.com/mapfiles/marker.png");
style.setGraphicSize(20, 34);
style.setGraphicOffset(-10, -34);
}
style.setFillOpacity(1.0);
if(pin.isDraggable() && !draggable) {
draggable = true;
mapWidget.getMap().addControl(dragFeature);
dragFeature.activate();
}
final LonLat lonLat = new LonLat(pin.getLongitude(), pin.getLatitude());
lonLat.transform(TRANSFORM_SOURCE, mapWidget.getMap().getProjection());
final Point point = new Point(lonLat.lon(), lonLat.lat());
final VectorFeature vectorFeature = new VectorFeature(point, style);
vectorFeature.setFeatureId("P" + (++featureIdSequence));
return vectorFeature;
}
@Override
protected void movePin(VectorFeature pin, double latitude, double longitude) {
final LonLat lonLat = new LonLat(longitude, latitude);
lonLat.transform(TRANSFORM_SOURCE, mapWidget.getMap().getProjection());
pin.move(lonLat);
}
@Override
protected void addPinDragEndHandler(VectorFeature vectorFeature, PinDragEndHandler dragEndHandler) {
List<PinDragEndHandler> handlers = dragEndHandlers.get(vectorFeature);
if(handlers == null) {
handlers = new ArrayList<PinDragEndHandler>();
dragEndHandlers.put(vectorFeature.getFeatureId(), handlers);
}
handlers.add(dragEndHandler);
}
@Override
public void panTo(double latitude, double longitude) {
final LonLat lonLat = new LonLat(longitude, latitude);
lonLat.transform(TRANSFORM_SOURCE, mapWidget.getMap().getProjection());
mapWidget.getMap().setCenter(lonLat);
}
private DragFeature createDraggableFeature(Vector vector) {
final DragFeatureOptions dragFeatureOptions = new DragFeatureOptions();
final DragFeature.DragFeatureListener emptyListener = new DragFeature.DragFeatureListener() {
@Override
public void onDragEvent(VectorFeature vectorFeature, Pixel pixel) {
}
};
final DragFeature.DragFeatureListener dragListener = new DragFeature.DragFeatureListener() {
@Override
public void onDragEvent(VectorFeature vectorFeature, Pixel pixel) {
final LonLat lonLat = mapWidget.getMap().getLonLatFromPixel(pixel);
lonLat.transform(mapWidget.getMap().getProjection(), TRANSFORM_SOURCE);
final List<PinDragEndHandler> handlers = dragEndHandlers.get(vectorFeature.getFeatureId());
if(handlers != null) {
for(final PinDragEndHandler handler : handlers) {
handler.onDragEnd(lonLat.lat(), lonLat.lon());
}
}
}
};
dragFeatureOptions.onStart(emptyListener);
dragFeatureOptions.onDrag(emptyListener);
dragFeatureOptions.onComplete(dragListener);
return new DragFeature(vector, dragFeatureOptions);
}
}