Java tutorial
/* * Copyright 2012 Vaadin Community. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.vaadin.addon.leaflet.client; import org.vaadin.addon.leaflet.shared.LeafletMapClientRpc; import org.vaadin.addon.leaflet.shared.LeafletMapServerRpc; import org.vaadin.addon.leaflet.shared.LeafletMapState; import java.util.ArrayList; import java.util.List; import org.peimari.gleaflet.client.ClickListener; import org.peimari.gleaflet.client.Event; import org.peimari.gleaflet.client.Layer; import org.peimari.gleaflet.client.LatLng; import org.peimari.gleaflet.client.LatLngBounds; import org.peimari.gleaflet.client.Map; import org.peimari.gleaflet.client.MapOptions; import org.peimari.gleaflet.client.MouseEvent; import org.peimari.gleaflet.client.MoveEndListener; import org.peimari.gleaflet.client.ContextMenuListener; import org.peimari.gleaflet.client.control.Layers; import org.peimari.gleaflet.client.resources.LeafletResourceInjector; import org.vaadin.addon.leaflet.LMap; import org.vaadin.addon.leaflet.shared.Bounds; import org.vaadin.addon.leaflet.shared.Point; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.json.client.JSONParser; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.ServerConnector; import com.vaadin.client.VConsole; import com.vaadin.client.communication.RpcProxy; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractHasComponentsConnector; import com.vaadin.client.ui.layout.ElementResizeEvent; import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.Connect; import org.peimari.gleaflet.client.Crs; /** * */ @Connect(LMap.class) public class LeafletMapConnector extends AbstractHasComponentsConnector implements ElementResizeListener { static { LeafletResourceInjector.ensureInjected(); } LeafletMapServerRpc rpc = RpcProxy.create(LeafletMapServerRpc.class, this); private Map map; private MapOptions options; private ArrayList<ServerConnector> updateChildren; private Layers layersControl; @Override public MapWidget getWidget() { return (MapWidget) super.getWidget(); } @Override public LeafletMapState getState() { return (LeafletMapState) super.getState(); } @Override protected Widget createWidget() { MapWidget mapWidget = new MapWidget(); return mapWidget; } @Override protected void init() { super.init(); /* * Working with state can be really painfull in some cases. E.g. if we * keep extent, center and stuff in state, we'll get false "changes" if * children are updated at the same time. In maps case we might get some * nasty rounding erros -> weird "effects". Thus we have to do all live * updates via RPC and store same stuff in state for initial renderings * and reattaches. It is sooo easy... */ registerRpc(LeafletMapClientRpc.class, new LeafletMapClientRpc() { @Override public void setCenter(Double lat, Double lon, Double zoom) { VConsole.log("To be center : " + lat + " " + lon + " "); if (zoom == null) { zoom = map.getZoom(); } LatLng center; if (lon == null) { center = map.getBounds().getCenter(); } else { center = LatLng.create(lat, lon); } map.setView(center, zoom); } @Override public void zoomToExtent(Bounds b) { LatLngBounds bounds = toLeafletBounds(b); map.fitBounds(bounds); } @Override public void setMaxBounds(Bounds bounds) { map.setMaxBounds(toLeafletBounds(bounds)); } }); getLayoutManager().addElementResizeListener(getWidget().getElement(), this); } @Override public void onUnregister() { super.onUnregister(); getLayoutManager().removeElementResizeListener(getWidget().getElement(), this); } @Override public void onStateChanged(final StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); if (map == null) { updateChildren = new ArrayList<ServerConnector>(getChildren()); if (getState().customMapOptionsJson != null) { options = JSONParser.parseStrict(getState().customMapOptionsJson).isObject().getJavaScriptObject() .cast(); } else { options = MapOptions.create(); } if (getState().maxBounds != null) { options.setMaxBounds(toLeafletBounds(getState().maxBounds)); } if (getState().center != null) { options.setCenter(getCenterFromState()); } else { options.setCenter(LatLng.create(0, 0)); } /* * See if CRS set. Maintain backwards compatability so that EPSG:3857 * used if nothing specified. */ if (getState().crsName != null) { options.setCrs(Crs.byName(getState().crsName)); } if (getState().attributionPrefix == null) { options.setAttributionControl(false); } if (getState().minZoom != null) { options.setMinZoom(getState().minZoom); } if (getState().maxZoom != null) { options.setMaxZoom(getState().maxZoom); } double zoom = 15; if (getState().zoomLevel != null) { zoom = getState().zoomLevel; } options.setZoom(zoom); map = Map.create(getWidget().getElement().getFirstChildElement(), options); if (getState().attributionPrefix != null) { map.getAttributionControl().setPrefix(getState().attributionPrefix); } if (getState().zoomToExtent != null) { Bounds b = getState().zoomToExtent; LatLng northEast = LatLng.create(b.getNorthEastLat(), b.getNorthEastLon()); LatLng southWest = LatLng.create(b.getSouthWestLat(), b.getSouthWestLon()); map.fitBounds(LatLngBounds.create(southWest, northEast)); } map.addClickListener(new ClickListener() { public void onClick(MouseEvent event) { if (hasEventListener("click")) { // Add mouse details MouseEventDetails details = MouseEventDetailsBuilder .buildMouseEventDetails(event.getNativeEvent(), getWidget().getElement()); rpc.onClick(new Point(event.getLatLng().getLatitude(), event.getLatLng().getLongitude()), details); } } }); map.addContextMenuListener(new ContextMenuListener() { @Override public void onContextMenu(MouseEvent event) { if (hasEventListener("contextmenu")) { // Add mouse details MouseEventDetails details = MouseEventDetailsBuilder .buildMouseEventDetails(event.getNativeEvent(), getWidget().getElement()); rpc.onContextMenu( new Point(event.getLatLng().getLatitude(), event.getLatLng().getLongitude()), details); } } }); MoveEndListener moveEndListener = new MoveEndListener() { @Override public void onMoveEnd(Event event) { Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { reportViewPortToServer(); } }); } }; map.addMoveEndListener(moveEndListener); if (getState().width != null && !getState().width.contains("%")) { // fixed size for the leaflet map, report size manually to the // server reportViewPortToServer(); } } else { // extent, zoom etc, must not be updated here, see client rpc... } updateChildrens(); } protected void reportViewPortToServer() { rpc.onMoveEnd(new Bounds(map.getBounds().toBBoxString()), new Point(map.getCenter().getLatitude(), map.getCenter().getLongitude()), map.getZoom()); if (getState().registeredEventListeners != null && getState().registeredEventListeners.contains("moveend")) { getConnection().sendPendingVariableChanges(); } } private void updateChildrens() { if (map == null) { return; } if (updateChildren != null) { for (ServerConnector serverConnector : updateChildren) { if (serverConnector instanceof AbstractLeafletLayerConnector<?>) { AbstractLeafletLayerConnector<?> c = (AbstractLeafletLayerConnector<?>) serverConnector; c.updateIfDirty(); } } updateChildren = null; } } private LatLng getCenterFromState() { LatLng center = LatLng.create(getState().center.getLat(), getState().center.getLon()); return center; } public Map getMap() { return map; } @Override public void updateCaption(ComponentConnector connector) { // TODO Auto-generated method stub } @Override public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) { List<ComponentConnector> oldChildren = connectorHierarchyChangeEvent.getOldChildren(); updateChildren = new ArrayList<ServerConnector>(); for (ServerConnector componentConnector : getChildren()) { if (!oldChildren.contains(componentConnector)) { updateChildren.add(componentConnector); } oldChildren.remove(componentConnector); } for (ComponentConnector componentConnector : oldChildren) { // Instance of check for Popup's that don't extend AbstractLeafletLayerConnector if (componentConnector instanceof AbstractLeafletLayerConnector) { AbstractLeafletLayerConnector<?> c = (AbstractLeafletLayerConnector<?>) componentConnector; Layer layer = c.getLayer(); try { map.removeLayer(layer); if (layersControl != null) { layersControl.removeLayer(layer); } } catch (Exception e) { VConsole.log("Removing failed, possibly due to timing issue..."); } } } updateChildrens(); } @Override public void onElementResize(ElementResizeEvent e) { // Without this it appears component is invalidly sized sometimes map.invalidateSize(); } public void setLayersControl(Layers l) { this.layersControl = l; } public static LatLngBounds toLeafletBounds(Bounds b) { LatLng northEast = LatLng.create(b.getNorthEastLat(), b.getNorthEastLon()); LatLng southWest = LatLng.create(b.getSouthWestLat(), b.getSouthWestLon()); LatLngBounds bounds = LatLngBounds.create(southWest, northEast); return bounds; } public Point getMapPixelPosition() { return new Point(getWidget().getAbsoluteTop(), getWidget().getAbsoluteLeft()); } }