/* * 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.controller; import org.geomajas.geometry.Coordinate; import org.geomajas.geometry.service.MathService; import org.geomajas.gwt.client.map.RenderSpace; import org.geomajas.gwt2.client.map.MapPresenter; import org.geomajas.gwt2.client.map.View; import org.geomajas.gwt2.client.map.ViewPort; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Touch; import com.google.gwt.event.dom.client.TouchEvent; /** * 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 */ public class TouchNavigationController extends NavigationController implements PointerController { protected boolean zooming; protected Coordinate startCenter; protected double startDist; public void onMapTouchCancel(TouchEvent<?> event) { onMapTouchEnd(event); } public void onMapTouchStart(TouchEvent<?> event) { if (event.getTouches().length() == 2) { Coordinate p1 = getWorldLocation(event.getTouches().get(0), RenderSpace.WORLD); Coordinate p2 = getWorldLocation(event.getTouches().get(1), RenderSpace.WORLD); startCenter = getCenter(p1, p2); startDist = MathService.distance(p1, p2); stopPanning(null); this.zooming = true; } else { onDown(event); } event.preventDefault(); event.stopPropagation(); } public void onMapTouchMove(TouchEvent<?> event) { if (event.getTouches().length() == 2 && zooming) { Coordinate p1 = getWorldLocation(event.getTouches().get(0), RenderSpace.WORLD); Coordinate p2 = getWorldLocation(event.getTouches().get(1), RenderSpace.WORLD); double scale = MathService.distance(p1, p2) / startDist; Coordinate newCenter = getCenter(p1, p2); double dx = startCenter.getX() - newCenter.getX(); double dy = startCenter.getY() - newCenter.getY(); double resolution = mapPresenter.getViewPort().getResolution() / scale; Coordinate position = calculatePosition(scale, startCenter); View view = new View(new Coordinate(position.getX() + dx, position.getY() + dy), resolution); view.setInteractive(true); mapPresenter.getViewPort().applyView(view); } else { onDrag(event); } event.preventDefault(); event.stopPropagation(); } public void onMapTouchEnd(TouchEvent<?> event) { if (zooming) { if (event.getTouches().length() == 0) { zooming = false; } mapPresenter.getViewPort().stopInteraction(); } else { onUp(event); } event.preventDefault(); event.stopPropagation(); } private Coordinate getWorldLocation(Touch touch, RenderSpace world) { Element element = mapPresenter.asWidget().getElement(); Coordinate c = new Coordinate(touch.getRelativeX(element), touch.getRelativeY(element)); return mapPresenter.getViewPort().getTransformationService() .transform(c, RenderSpace.SCREEN, RenderSpace.WORLD); } private Coordinate getCenter(Coordinate p1, Coordinate p2) { return new Coordinate(0.5 * (p1.getX() + p2.getX()), 0.5 * (p1.getY() + p2.getY())); } /** * Calculate the target position should there be a rescale point. The idea is that after zooming in or out, the * mouse cursor would still lie at the same position in world space. */ protected Coordinate calculatePosition(double scale, Coordinate rescalePoint) { ViewPort viewPort = mapPresenter.getViewPort(); Coordinate position = viewPort.getPosition(); double dX = (rescalePoint.getX() - position.getX()) * (1 - 1 / scale); double dY = (rescalePoint.getY() - position.getY()) * (1 - 1 / scale); return new Coordinate(position.getX() + dX, position.getY() + dY); } // ------------------------------------------------------------------------ // Methods: // ------------------------------------------------------------------------ @Override public void onActivate(final MapPresenter mapPresenter) { this.mapPresenter = mapPresenter; this.eventParser = mapPresenter.getMapEventParser(); } }