All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.geomajas.gwt2.client.map.MapPresenterImpl Maven / Gradle / Ivy
/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.gwt2.client.map;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.geomajas.geometry.Matrix;
import org.geomajas.gwt.client.controller.MapEventParser;
import org.geomajas.gwt.client.event.HasAllPointerTouchHandlers;
import org.geomajas.gwt.client.event.PointerEvents;
import org.geomajas.gwt.client.map.RenderSpace;
import org.geomajas.gwt.client.util.Dom;
import org.geomajas.gwt2.client.controller.MapController;
import org.geomajas.gwt2.client.controller.MapEventParserImpl;
import org.geomajas.gwt2.client.controller.NavigationController;
import org.geomajas.gwt2.client.controller.TouchNavigationController;
import org.geomajas.gwt2.client.event.LayerAddedEvent;
import org.geomajas.gwt2.client.event.LayerRemovedEvent;
import org.geomajas.gwt2.client.event.MapCompositionHandler;
import org.geomajas.gwt2.client.event.MapInitializationEvent;
import org.geomajas.gwt2.client.event.MapResizedEvent;
import org.geomajas.gwt2.client.event.ViewPortChangedEvent;
import org.geomajas.gwt2.client.event.ViewPortChangedHandler;
import org.geomajas.gwt2.client.gfx.CanvasContainer;
import org.geomajas.gwt2.client.gfx.TransformableWidgetContainer;
import org.geomajas.gwt2.client.gfx.VectorContainer;
import org.geomajas.gwt2.client.map.layer.LayersModel;
import org.geomajas.gwt2.client.map.layer.LayersModelImpl;
import org.geomajas.gwt2.client.map.render.LayersModelRenderer;
import org.geomajas.gwt2.client.map.render.RenderingInfo;
import org.geomajas.gwt2.client.map.render.dom.DomLayersModelRenderer;
import org.geomajas.gwt2.client.map.render.dom.container.HtmlContainer;
import org.geomajas.gwt2.client.widget.DefaultMapWidget;
import org.geomajas.gwt2.client.widget.control.pan.PanControl;
import org.geomajas.gwt2.client.widget.control.scalebar.Scalebar;
import org.geomajas.gwt2.client.widget.control.watermark.Watermark;
import org.geomajas.gwt2.client.widget.control.zoom.ZoomControl;
import org.geomajas.gwt2.client.widget.control.zoom.ZoomStepControl;
import org.geomajas.gwt2.client.widget.control.zoomtorect.ZoomToRectangleControl;
import org.geomajas.gwt2.client.widget.map.MapWidgetImpl;
import org.vaadin.gwtgraphics.client.Transformable;
import com.google.gwt.event.dom.client.HasAllGestureHandlers;
import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
import com.google.gwt.event.dom.client.HasMouseDownHandlers;
import com.google.gwt.event.dom.client.HasMouseMoveHandlers;
import com.google.gwt.event.dom.client.HasMouseOutHandlers;
import com.google.gwt.event.dom.client.HasMouseOverHandlers;
import com.google.gwt.event.dom.client.HasMouseUpHandlers;
import com.google.gwt.event.dom.client.HasMouseWheelHandlers;
import com.google.gwt.event.dom.client.HasTouchCancelHandlers;
import com.google.gwt.event.dom.client.HasTouchEndHandlers;
import com.google.gwt.event.dom.client.HasTouchMoveHandlers;
import com.google.gwt.event.dom.client.HasTouchStartHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.EventBus;
/**
* Default implementation of the map presenter interface. In other words this is the default GWT map object.
*
* @author Pieter De Graef
*/
public final class MapPresenterImpl implements MapPresenter {
private static Logger logger = Logger.getLogger("MapPresenterImpl");
/**
* Map view definition.
*
* @author Pieter De Graef
*/
public interface MapWidget extends HasMouseDownHandlers, HasMouseUpHandlers, HasMouseOutHandlers,
HasMouseOverHandlers, HasMouseMoveHandlers, HasMouseWheelHandlers, HasDoubleClickHandlers, IsWidget,
RequiresResize, HasTouchStartHandlers, HasTouchEndHandlers, HasTouchCancelHandlers, HasTouchMoveHandlers,
HasAllGestureHandlers, HasAllPointerTouchHandlers {
/**
* Returns the HTML container of the map. This is a normal HTML container that contains the images of rasterized
* tiles (both vector and raster layers).
*
* @return the container
*/
HtmlContainer getMapHtmlContainer();
/**
* Returns the list of user-defined containers (vector + canvas) for world-space objects.
*
* @return the container
*/
List getWorldTransformables();
/**
* Returns a new user-defined container for screen space objects.
*
* @return the container
*/
VectorContainer getNewScreenContainer();
/**
* Returns a new user-defined container for world space objects.
*
* @return the container
*/
VectorContainer getNewWorldContainer();
/**
* Returns a new user-defined container for world space widgets.
*
* @return the container
*/
TransformableWidgetContainer getNewWorldWidgetContainer();
/**
* Removes a user-defined container.
*
* @param container container
* @return true if removed, false if unknown
*/
boolean removeVectorContainer(VectorContainer container);
/**
* Removes a user-defined container.
*
* @param container container
* @return true if removed, false if unknown
*/
boolean removeWorldWidgetContainer(TransformableWidgetContainer container);
/**
* Brings the user-defined container to the front (relative to its world-space or screen-space peers!).
*
* @param container container
* @return true if successful
*/
boolean bringToFront(VectorContainer container);
/**
* Returns a new user-defined container of map gadgets.
*
* @return the container
*/
HasWidgets getWidgetContainer();
/**
* Get the total width of the view.
*
* @return width in pixels
*/
int getWidth();
/**
* Get the total height of the view.
*
* @return height in pixels
*/
int getHeight();
/**
* Set the total size of the view.
*
* @param width width
* @param height height
*/
void setPixelSize(int width, int height);
CanvasContainer getNewWorldCanvas();
}
private final MapEventBus eventBus;
private final MapEventParser mapEventParser;
private final LayersModel layersModel;
private final ViewPortImpl viewPort;
private final MapWidget display;
private final ContainerManager containerManager;
private final Map> listeners;
private MapConfiguration configuration;
private List handlers;
private MapController mapController;
private MapController fallbackController;
private LayersModelRenderer renderer;
private boolean isTouchSupported;
// ------------------------------------------------------------------------
// Constructor:
// ------------------------------------------------------------------------
public MapPresenterImpl(final EventBus eventBus) {
this.handlers = new ArrayList();
this.listeners = new HashMap>();
this.eventBus = new MapEventBusImpl(this, eventBus);
this.display = new MapWidgetImpl();
this.viewPort = new ViewPortImpl(this.eventBus);
this.layersModel = new LayersModelImpl(this.viewPort, this.eventBus);
this.mapEventParser = new MapEventParserImpl(this);
this.renderer = new DomLayersModelRenderer(layersModel, viewPort, this.eventBus);
this.containerManager = new ContainerManagerImpl(display, viewPort);
this.isTouchSupported = Dom.isTouchSupported() || PointerEvents.isSupported();
this.eventBus.addViewPortChangedHandler(new ViewPortChangedHandler() {
@Override
public void onViewPortChanged(ViewPortChangedEvent event) {
renderer.render(new RenderingInfo(display.getMapHtmlContainer(), event.getTo(), event.getTrajectory()));
}
});
this.eventBus.addMapCompositionHandler(new MapCompositionHandler() {
@Override
public void onLayerRemoved(LayerRemovedEvent event) {
}
@Override
public void onLayerAdded(LayerAddedEvent event) {
if (layersModel.getLayerCount() == 1) {
renderer.setAnimated(event.getLayer(), true);
}
}
});
this.eventBus.addViewPortChangedHandler(new WorldTransformableRenderer());
if (isTouchSupported) {
if (PointerEvents.isSupported()) {
logger.info("touch supported");
try {
logger.info("setting touch action");
display.asWidget().getElement().getStyle().setProperty("touchAction", "none");
} catch (Exception e) {
logger.info("oooops " + e.getMessage());
}
}
logger.fine("touch");
fallbackController = new TouchNavigationController();
} else {
logger.fine("no touch");
fallbackController = new NavigationController();
}
setMapController(fallbackController);
setSize(100, 100);
}
/**
* Generic controller that is used on touch devices. Note that gestures and multi touch are not supported by some
* mobile browsers.
*
* @author Jan De Moerloose
* @since 2.0.0
*/
// ------------------------------------------------------------------------
// MapPresenter implementation:
// ------------------------------------------------------------------------
public void initialize(MapConfiguration configuration, DefaultMapWidget... mapWidgets) {
initialize(configuration, true, mapWidgets);
}
public void initialize(MapConfiguration configuration, boolean fireEvent, DefaultMapWidget... mapWidgets) {
this.configuration = configuration;
// Apply this configuration on the LayersModelRenderer:
if (renderer instanceof DomLayersModelRenderer) {
((DomLayersModelRenderer) renderer).setMapConfiguration(configuration);
}
// Configure the ViewPort. This will immediately zoom to the initial bounds:
// viewPort.setMapSize(display.getWidth(), display.getHeight());
viewPort.initialize(configuration);
// Immediately zoom to the initial bounds as configured:
viewPort.applyBounds(configuration.getHintValue(MapConfiguration.INITIAL_BOUNDS), ZoomOption.LEVEL_CLOSEST);
renderer.render(new RenderingInfo(display.getMapHtmlContainer(), viewPort.getView(), null));
// Adding the default map control widgets:
if (getWidgetPane() != null) {
getWidgetPane().add(new Watermark()); // We always add the watermark...
for (DefaultMapWidget widget : mapWidgets) {
switch (widget) {
case SCALEBAR:
getWidgetPane().add(new Scalebar(MapPresenterImpl.this));
break;
case PAN_CONTROL:
getWidgetPane().add(new PanControl(MapPresenterImpl.this));
break;
case ZOOM_CONTROL:
getWidgetPane().add(new ZoomControl(MapPresenterImpl.this));
break;
case ZOOM_STEP_CONTROL:
getWidgetPane().add(new ZoomStepControl(MapPresenterImpl.this));
break;
case ZOOM_TO_RECTANGLE_CONTROL:
getWidgetPane().add(new ZoomToRectangleControl(MapPresenterImpl.this));
break;
}
}
}
// Fire initialization event
if (fireEvent) {
eventBus.fireEvent(new MapInitializationEvent(this));
}
}
@Override
public Widget asWidget() {
return display.asWidget();
}
public void setRenderer(LayersModelRenderer renderer) {
this.renderer = renderer;
}
public LayersModelRenderer getLayersModelRenderer() {
return renderer;
}
@Override
public MapConfiguration getConfiguration() {
if (configuration == null) {
configuration = new MapConfigurationImpl();
}
return configuration;
}
@Override
public void setSize(int width, int height) {
display.setPixelSize(width, height);
viewPort.setMapSize(width, height);
eventBus.fireEvent(new MapResizedEvent(width, height));
}
@Override
public LayersModel getLayersModel() {
return layersModel;
}
@Override
public ViewPort getViewPort() {
return viewPort;
}
@Override
public MapEventBus getEventBus() {
return eventBus;
}
@Override
public void setMapController(MapController mapController) {
for (HandlerRegistration registration : handlers) {
registration.removeHandler();
}
if (this.mapController != null) {
this.mapController.onDeactivate(this);
this.mapController = null;
}
handlers = new ArrayList();
if (null == mapController) {
mapController = fallbackController;
}
if (mapController != null) {
if (isTouchSupported) {
if (PointerEvents.isSupported()) {
handlers.add(display.addPointerTouchStartHandler(mapController));
handlers.add(display.addPointerTouchMoveHandler(mapController));
handlers.add(display.addPointerTouchEndHandler(mapController));
handlers.add(display.addPointerTouchCancelHandler(mapController));
handlers.add(display.addMouseWheelHandler(mapController));
} else {
handlers.add(display.addTouchStartHandler(mapController));
handlers.add(display.addTouchMoveHandler(mapController));
handlers.add(display.addTouchEndHandler(mapController));
handlers.add(display.addTouchCancelHandler(mapController));
handlers.add(display.addGestureStartHandler(mapController));
handlers.add(display.addGestureChangeHandler(mapController));
handlers.add(display.addGestureEndHandler(mapController));
handlers.add(display.addMouseWheelHandler(mapController));
}
}
// always listen to mouse events, controllers are responsible to avoid double-handling !!!
handlers.add(display.addMouseDownHandler(mapController));
handlers.add(display.addMouseMoveHandler(mapController));
handlers.add(display.addMouseOutHandler(mapController));
handlers.add(display.addMouseOverHandler(mapController));
handlers.add(display.addMouseUpHandler(mapController));
handlers.add(display.addMouseWheelHandler(mapController));
handlers.add(display.addDoubleClickHandler(mapController));
this.mapController = mapController;
mapController.onActivate(this);
}
}
@Override
public MapController getMapController() {
return mapController;
}
@Override
public boolean addMapListener(MapController mapListener) {
if (mapListener != null && !listeners.containsKey(mapListener)) {
List registrations = new ArrayList();
if (isTouchSupported) {
if (PointerEvents.isSupported()) {
registrations.add(display.addPointerTouchStartHandler(mapController));
registrations.add(display.addPointerTouchMoveHandler(mapController));
registrations.add(display.addPointerTouchEndHandler(mapController));
registrations.add(display.addPointerTouchCancelHandler(mapController));
registrations.add(display.addMouseWheelHandler(mapController));
} else {
registrations.add(display.addTouchStartHandler(mapController));
registrations.add(display.addTouchMoveHandler(mapController));
registrations.add(display.addTouchEndHandler(mapController));
registrations.add(display.addTouchCancelHandler(mapController));
registrations.add(display.addGestureStartHandler(mapController));
registrations.add(display.addGestureChangeHandler(mapController));
registrations.add(display.addGestureEndHandler(mapController));
registrations.add(display.addMouseWheelHandler(mapController));
}
}
// always listen to mouse events, listeners are responsible to avoid double-handling !!!
registrations.add(display.addMouseDownHandler(mapListener));
registrations.add(display.addMouseMoveHandler(mapListener));
registrations.add(display.addMouseOutHandler(mapListener));
registrations.add(display.addMouseOverHandler(mapListener));
registrations.add(display.addMouseUpHandler(mapListener));
registrations.add(display.addMouseWheelHandler(mapListener));
mapListener.onActivate(this);
listeners.put(mapListener, registrations);
return true;
}
return false;
}
@Override
public boolean removeMapListener(MapController mapListener) {
if (mapListener != null && listeners.containsKey(mapListener)) {
List registrations = listeners.get(mapListener);
for (HandlerRegistration registration : registrations) {
registration.removeHandler();
}
listeners.remove(mapListener);
mapListener.onDeactivate(this);
return true;
}
return false;
}
@Override
public Collection getMapListeners() {
return listeners.keySet();
}
@Override
public void setCursor(String cursor) {
DOM.setStyleAttribute(display.asWidget().getElement(), "cursor", cursor);
}
@Override
public MapEventParser getMapEventParser() {
return mapEventParser;
}
@Override
public HasWidgets getWidgetPane() {
return display.getWidgetContainer();
}
@Override
public ContainerManager getContainerManager() {
return containerManager;
}
// ------------------------------------------------------------------------
// Private classes:
// ------------------------------------------------------------------------
/**
* Handler that redraws all world space objects whenever the view on the map changes.
*
* @author Pieter De Graef
*/
private class WorldTransformableRenderer implements ViewPortChangedHandler {
@Override
public void onViewPortChanged(ViewPortChangedEvent event) {
Matrix matrix = viewPort.getTransformationService().getTransformationMatrix(RenderSpace.WORLD,
RenderSpace.SCREEN);
for (Transformable worldTransformable : display.getWorldTransformables()) {
worldTransformable.setTranslation(matrix.getDx(), matrix.getDy());
worldTransformable.setScale(matrix.getXx(), matrix.getYy());
}
}
}
}