/* * 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.gwt.client.widget; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.History; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import org.geomajas.annotation.Api; import org.geomajas.geometry.Coordinate; import org.geomajas.gwt.client.map.MapView; import org.geomajas.gwt.client.map.event.MapViewChangedEvent; import org.geomajas.gwt.client.map.event.MapViewChangedHandler; /** * <p> * Includes x, y, r in the URL so that it can be used to bookmark the current map position and zoom level. * The map will navigate to x, y, r in case it is included in the bookmarked URL. * </p> * * @author Dosi Bingov * * @since 1.15.0 */ @Api public final class DynamicUrlController implements MapViewChangedHandler { private static DynamicUrlController instance; private boolean zoomedTo; private MapWidget mapWidget; private DynamicUrlParser urlParser; // ------------------------------------------------------------------------ // Constructors: // ------------------------------------------------------------------------ /** * Create a new DynamicUrlController instance. Private because register method is responsible for the creation. * * @since 1.15.0 */ private DynamicUrlController() { urlParser = new DynamicUrlParser(); } // ------------------------------------------------------------------------ // Private methods: // ------------------------------------------------------------------------ private void extractHash() { String hash = Window.Location.getHash(); GWT.log("DynamicUrlController hash => " + hash); if (null != hash && !hash.isEmpty()) { urlParser.parseHash(hash.substring(1)); } } /** * Sets the map. * * @param mapWidget */ private void setMap(MapWidget mapWidget) { this.mapWidget = mapWidget; initHandlers(); } /** * Initialise all handlers used in {@link DynamicUrlController}. */ private void initHandlers() { mapWidget.getMapModel().getMapView().addMapViewChangedHandler(this); mapWidget.getMapModel().runWhenInitialized(new Runnable() { public void run() { zoomTo(); } }); } /** * Changes hash part of the URL. * * @param newHash x, y, r hash string */ private void changeHash(String newHash) { History.newItem(newHash); } /** * Zooms to x, y, r coordinates on the map taken from the {@link DynamicUrlParser}. */ private void zoomTo() { if (urlParser.isValid() && !zoomedTo) { final Timer timer = new Timer() { @Override public void run() { mapWidget.getMapModel().getMapView().setCurrentScale(urlParser.getR(), MapView.ZoomOption.EXACT); mapWidget.getMapModel().getMapView().setCenterPosition(new Coordinate(urlParser.getX(), urlParser.getY())); this.cancel(); zoomedTo = true; } }; //run one time after 0.1s to be sure that the map has been resized. timer.schedule(100); } } @Override public void onMapViewChanged(MapViewChangedEvent event) { double resolution = mapWidget.getMapModel().getMapView().getViewState().getScale(); double x = mapWidget.getMapModel().getMapView().getViewState().getX(); double y = mapWidget.getMapModel().getMapView().getViewState().getY(); DynamicUrlParser parser = new DynamicUrlParser(x, y, resolution); changeHash(parser.getHash()); } // ------------------------------------------------------------------------ // Private classes: // ------------------------------------------------------------------------ /** * Help class that will parse hash part of the URL. * * x, y, r parser. */ private class DynamicUrlParser { private boolean isValid; private double y; private double x; private double r; public DynamicUrlParser() { } public DynamicUrlParser(double x, double y, double r) { this.x = x; this.y = y; this.r = r; } public DynamicUrlParser(String hash) { parseHash(hash); } public void setXYZ(Coordinate xy, double z) { x = xy.getX(); y = xy.getY(); this.r = z; } private void parseHash(String hash) { String[] xyr = hash.split(","); isValid = true; try { for (String s : xyr) { if (s.indexOf('x') != -1) { x = Double.parseDouble(s.substring(1)); } else if (s.indexOf('y') != -1) { y = Double.parseDouble(s.substring(1)); } else if (s.indexOf('r') != -1) { r = Double.parseDouble(s.substring(1)); } else { GWT.log("invalid geomajas xyr hash Exception !"); isValid = false; } } } catch (NumberFormatException ex) { GWT.log("invalid geomajas xyr hash Exception !", ex); isValid = false; } } public double getY() { return y; } public double getX() { return x; } public double getR() { return r; } public String getHash() { return "x" + getX() + ",y" + getY() + ",r" + r; } public boolean isValid() { return isValid; } } /** * Creates instance of {@link DynamicUrlController} that will listen to map changes and apply current x,y,r in the * hash part of the URL. * * This method should be called after {@link MapWidget} is created. * * @param mapWidget main map widget of the application. */ @Api public static void register(MapWidget mapWidget) { if (null == instance) { instance = new DynamicUrlController(); } instance.extractHash(); instance.setMap(mapWidget); } }