概述
由于项目需要用到地图,虽然isis的插件库里有个现成的地图实现,不过用的google地图,虽然google地图可以不用注册Appkey,但完全打不开。所以打算改成国产地图。
效果
先看下运行效果。
列表中的效果:
整体效果:
详细效果:
实现思路
高德地图的API跟Google地图类似,编程模型也相同,甚至很多类的命名都一样的。所以,从Google迁到高德还是比较容易的。
高德跟Google一样,用一个DIV来渲染地图。根据Vicket的编程方式,这个Div使用一个组件来表示,这个组件包含了相应的属性和呈现出来的模板及脚本。
先看下Google的模板,很简单在Panel里放了一个Div:
<html xmlns:wicket>
<body>
<wicket:panel>
<div wicket:id="map" style="100%; height:100%"></div>
</wicket:panel>
</body>
</html>
Google的客户端对应的初始化脚本:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* * Wicket GMap3 * * @author Tilman M�ller * @author Joachim F. Rohde */ // Wicket Namespace if (typeof(Wicket) === 'undefined') { window.Wicket = {}; } else if (typeof(Wicket) !== "object") { throw new Error("Wicket already exists but is not an object"); } function WicketClientGeocoder() { try { this.coder = new google.maps.Geocoder(); } catch (e) { if( !Wicket.maps['_failSilently'] ) { throw e; } } this.getLatLng = function(callBack, addressId){ var address = Wicket.$(addressId).value; this.coder.geocode({ 'address': address }, function(results, status){ if (status === google.maps.GeocoderStatus.OK) { callBack = callBack + '&address=' + results[0].formatted_address; callBack = callBack + '&coordinates=' + results[0].geometry.location; } callBack = callBack + '&status=' + status; Wicket.Ajax.ajax({ 'u':callBack }); }); } } Wicket.maps = {} function WicketMap(id, failSilently) { Wicket.maps[id] = this; if(failSilently) { Wicket.maps['_failSilently'] = failSilently; } this.options = {}; try { this.map = new google.maps.Map(Wicket.$(id)); } catch (e) { if(!failSilently) { throw e; } } this.overlays = {}; this.onEvent = function(callBack, params) { params['center'] = this.map.getCenter(); params['bounds'] = this.map.getBounds(); params['zoom'] = this.map.getZoom(); params['currentMapType'] = this.getMapTypeString(this.map.getMapTypeId()); for ( var key in params) { callBack = callBack + '&' + key + '=' + params[key]; } Wicket.Ajax.ajax({ 'u':callBack }); } this.addListener = function(event, callBack) { var self = this; google.maps.event.addListener(this.map, event, function() { var params = {}; for ( var p = 0; p < arguments.length; p++) { if (arguments[p] != null) { if (arguments[p].latLng != null) { params['lat'] = arguments[0].latLng.lat(); params['lng'] = arguments[0].latLng.lng(); } } } self.onEvent(callBack, params); }); } this.addOverlayListener = function(overlayID, event) { var self = this; var overlay = this.overlays[overlayID]; google.maps.event.addListener(overlay, event, function() { var params = {}; for ( var p = 0; p < arguments.length; p++) { if (arguments[p] != null) { params['argument' + p] = arguments[p]; } } if (overlay.getPosition) { params['overlay.latLng'] = overlay.getPosition(); } else if (overlay.getCenter) { // Circle uses #getCenter() instead params['overlay.latLng'] = overlay.getCenter(); } if (overlay.getRadius) { // Circle params['overlay.radius'] = overlay.getRadius(); } if (overlay.getBounds) { params['overlay.bounds'] = overlay.getBounds(); } params['overlay.overlayId'] = overlay.overlayId; params['overlay.event'] = event; self.onEvent(self.overlayListenerCallbackUrl, params); }); } this.clearOverlayListeners = function(overlayID, event) { var overlay = this.overlays[overlayID]; google.maps.event.clearListeners(overlay, event); } this.setDraggingEnabled = function(enabled) { this.options.draggable = enabled; this.map.setOptions(this.options); } this.setDoubleClickZoomEnabled = function(enabled) { this.options.disableDoubleClickZoom = enabled; this.map.setOptions(this.options); } this.setScrollWheelZoomEnabled = function(enabled) { this.options.scrollwheel = enabled; this.map.setOptions(this.options); } this.setScaleControlEnabled = function(enabled) { this.options.scaleControl = enabled; this.map.setOptions(this.options); } this.setZoomControlEnabled = function(enabled) { this.options.zoomControl = enabled; this.map.setOptions(this.options); } this.setMapTypeControlEnabled = function(enabled) { this.options.mapTypeControl = enabled; this.map.setOptions(this.options); } this.setStreetViewControlEnabled = function(enabled) { this.options.streetViewControl = enabled; this.map.setOptions(this.options); } this.setPanControlEnabled = function(enabled) { this.options.panControl = enabled; this.map.setOptions(this.options); } this.fitBounds = function(bounds) { this.options.bounds = bounds; this.map.setOptions(this.options); this.map.fitBounds(bounds); } this.panToBounds = function(bounds) { this.options.bounds = bounds; this.map.setOptions(this.options); this.map.panToBounds(bounds); } this.setMinZoom = function(minZoom) { this.options.minZoom = minZoom; this.map.setOptions(this.options); } this.setMaxZoom = function(maxZoom) { this.options.maxZoom = maxZoom; this.map.setOptions(this.options); } this.getMapTypeString = function(mapType) { switch (mapType) { case google.maps.MapTypeId.ROADMAP: return 'ROADMAP'; break; case google.maps.MapTypeId.SATELLITE: return 'SATELLITE'; break; case google.maps.MapTypeId.HYBRID: return 'HYBRID'; break; case google.maps.MapTypeId.TERRAIN: return 'TERRAIN'; break; default: return 'unknown'; break; } } this.setMapType = function(mapType) { this.map.setMapTypeId(mapType); } this.setZoom = function(level) { this.map.setZoom(level); } this.setCenter = function(center) {
//设置地图中心 this.map.setCenter(center); } this.setCenterFailSafe = function(lat, lng, unbounded) { try { this.map.setCenter( new google.maps.LatLng(lat, lng, unbounded) ); } catch (e) { // do nothing } } this.panTo = function(center) { this.map.panTo(center); } this.panDirection = function(dx, dy) { this.map.panBy(dx, dy); } this.zoomOut = function() { this.map.setZoom(this.map.getZoom()-1) } this.zoomIn = function() { this.map.setZoom(this.map.getZoom()+1) } this.addOverlay = function(overlayId, overlay) { this.overlays[overlayId] = overlay; overlay.overlayId = overlayId; overlay.setMap(this.map); overlay.toString = function() { return overlayId; }; } this.removeOverlay = function(overlayId) { if (this.overlays[overlayId] != null) { this.overlays[overlayId].setMap(null); this.overlays[overlayId] = null; } } this.clearOverlays = function() { if (this.overlays) { for (i in this.overlays) { this.overlays[i].setMap(null); } } this.overlays = {}; } this.triggerEvent = function(event) { google.maps.event.trigger(this.map, event); } this.triggerResize = function() { this.triggerEvent('resize'); } } Wicket.Event.add(window, "load", function(event){ if(typeof(Wicket.geocoder) === 'undefined') Wicket.geocoder = new WicketClientGeocoder(); });
Java部分的实现,可以看出其属性与客户端的JS是一一对应的,这是Vicket的一种机制,将服务端的对象映射到客户端,这样在服务端设置属性就跟在客户端设置一样:
/* * * ============================================================================== * 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.wicketstuff.gmap; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.wicket.Component; import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.behavior.Behavior; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.OnDomReadyHeaderItem; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.request.IRequestParameters; import org.apache.wicket.request.Request; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.util.string.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wicketstuff.gmap.api.GEvent; import org.wicketstuff.gmap.api.GLatLng; import org.wicketstuff.gmap.api.GLatLngBounds; import org.wicketstuff.gmap.api.GMapType; import org.wicketstuff.gmap.api.GMarker; import org.wicketstuff.gmap.api.GMarkerCluster; import org.wicketstuff.gmap.api.GMarkerOptions; import org.wicketstuff.gmap.api.GOverlay; import org.wicketstuff.gmap.event.GEventListenerBehavior; /** * Wicket component to embed <a href="http://maps.google.com">Google Maps</a> into your pages. * <p> */ public class GMap extends Panel implements GOverlayContainer { /** log. */ private static final Logger log = LoggerFactory.getLogger(GMap.class); private static final long serialVersionUID = 1L; // Center is Palo Alto private GLatLng center = new GLatLng(37.4419, -122.1419); private boolean draggingEnabled = true; private boolean doubleClickZoomEnabled = false; private boolean scrollWheelZoomEnabled = false; private boolean streetViewControlEnabled = false; private boolean zoomControlEnabled = true; private boolean mapTypeControlEnabled = true; private boolean scaleControlEnabled = false; private boolean panControlEnabled = true; private GMapType mapType = GMapType.ROADMAP; private int zoom = 13; private int minZoom = 0; private int maxZoom = 0; private final Map<String, GOverlay> overlays = new HashMap<String, GOverlay>(); protected final WebMarkupContainer map; private GLatLngBounds bounds; private OverlayListener overlayListener = null; private List<GLatLng> markersToShow = new ArrayList<GLatLng>(); /** * If set to true map loading will not produce any JavaScript errors in case * google maps API cannot be found (e.g. no Internet connection) */ private boolean failSilently = false; private GMarkerCluster markerCluster; /** * Constructor. * * Default the header contributor of the component will added and the gmap * will be initiated directly on rendering of the map. * * @param id wicket id * @param apiKey your Google API key */ public GMap(final String id, String apiKey) { this(id, new GMapHeaderContributor("http", apiKey)); } /** * Constructor. * * Default the header contributor of the component will added and the gmap * will be initiated directly on rendering of the map. * * @param id wicket id * @param scheme the scheme ("http" or "https") which should be used * @param apiKey your Google API key */ public GMap(final String id, String apiKey, String scheme) { this(id, new GMapHeaderContributor(scheme, apiKey)); } /** * Construct. * * Default the header contributor of the component will added and the gmap * will be initiated directly on rendering of the map. * * @param id wicket id * @deprecated since 22th June 2016 Google Maps requires an API-key, * therefore you should use * {@link #GMap(java.lang.String, java.lang.String) } or {@link #GMap(java.lang.String, java.lang.String, java.lang.String) * } * instead of this constructor * @see * http://googlegeodevelopers.blogspot.de/2016/06/building-for-scale-updates-to-google.html */ public GMap(final String id) { this(id, new GMapHeaderContributor()); } /** * @deprecated Since the sensor-parameter is no longer required from Google * {@link #GMap(java.lang.String, java.lang.String) } or {@link #GMap(java.lang.String, java.lang.String, java.lang.String) * } * instead of this constructor */ public GMap(final String id, final boolean sensor) { this(id, new GMapHeaderContributor(sensor)); } /** * Construct. * * @param id * @param headerContrib */ public GMap(final String id, final GMapHeaderContributor headerContrib) { super(id); if (headerContrib != null) { add(headerContrib); } map = new WebMarkupContainer("map"); map.setOutputMarkupId(true); add(map); overlayListener = getOverlayListener(); add(overlayListener); } protected OverlayListener getOverlayListener() { return new OverlayListener(); } /** * @return the markup-id of the container */ public String getMapId() { return map.getMarkupId(); } @Override protected void onBeforeRender() { super.onBeforeRender(); if (getApplication().usesDevelopmentConfig() && !getApplication().getMarkupSettings().getStripWicketTags()) { log.warn("Application is in DEVELOPMENT mode && Wicket tags are not stripped," + "Some Chrome Versions will not render the GMap." + " Change to DEPLOYMENT mode || turn on Wicket tags stripping." + " See:" + " http://www.nabble.com/Gmap2-problem-with-Firefox-3.0-to18137475.html."); } } @Override public void renderHead(IHeaderResponse response) { response.render(OnDomReadyHeaderItem.forScript(getJSinit())); } /** * Add an overlay. * * @see GOverlayContainer#addOverlay(GOverlay) * @param overlay * overlay to add * @return This */ @Override public GMap addOverlay(final GOverlay overlay) { overlays.put(overlay.getId(), overlay); overlay.setParent(this); AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(overlay.getJS()); } return this; } /** * Remove an overlay. * * @see GOverlayContainer#removeOverlay(GOverlay) * @param overlay * overlay to remove * @return This */ @Override public GMap removeOverlay(final GOverlay overlay) { while (overlays.containsKey(overlay.getId())) { overlays.remove(overlay.getId()); } AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(overlay.getJSremove()); } overlay.setParent(null); return this; } /** * Clear all overlays. * * @see GOverlayContainer#removeAllOverlays() * @return This */ @Override public GMap removeAllOverlays() { for (final GOverlay overlay : overlays.values()) { overlay.setParent(null); } overlays.clear(); AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSinvoke("clearOverlays()")); } return this; } /** * @see GOverlayContainer#getOverlays() */ @Override public List<GOverlay> getOverlays() { return Collections.unmodifiableList(new ArrayList<GOverlay>(overlays.values())); } public GLatLngBounds getBounds() { return bounds; } public void setBounds(GLatLngBounds bounds) { this.bounds = bounds; } /** * Returns the script for triggering an event on map. * * @param event * @return */ public CharSequence getTriggerEventScript(String event) { return "Wicket.maps['"+getMapId()+ "'].triggerEvent('"+event+"')"; } /** * @return returns the script to make map re-paint after resize. */ public CharSequence getTriggerResizeScript() { return "Wicket.maps['"+getMapId()+ "'].triggerResize();"; } /** * Sets if dragging should be allowed or not. * @param enabled true if dragging should be allowed, false otherwise */ public void setDraggingEnabled(final boolean enabled) { if (this.draggingEnabled != enabled) { draggingEnabled = enabled; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetDraggingEnabled(enabled)); } } } /** * Is dragging allowed? Enabled by default. * * @return true if it's allowed, false if not */ public boolean isDraggingEnabled() { return draggingEnabled; } /** * Sets if zooming-by-doubleclicking should be allowed or not. * @param enabled true if zooming-by-doubleclicking should be allowed, false otherwise */ public void setDoubleClickZoomEnabled(final boolean enabled) { if (this.doubleClickZoomEnabled != enabled) { doubleClickZoomEnabled = enabled; AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetDoubleClickZoomEnabled(enabled)); } } } /** * Is the function zooming-by-doubleclick enabled? * Disabled by default. * * @return true if enabled, false if disabled */ public boolean isDoubleClickZoomEnabled() { return doubleClickZoomEnabled; } /** * Sets if zooming-by-mousewheel should be allowed or not. * @param enabled true if zooming-by-mousewheel should be allowed, false otherwise */ public void setScrollWheelZoomEnabled(final boolean enabled) { if (this.scrollWheelZoomEnabled != enabled) { scrollWheelZoomEnabled = enabled; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetScrollWheelZoomEnabled(enabled)); } } } /** * Is the function zooming-by-mousewheel enabled? * Disabled by default. * * @return true if enabled, false if disabled */ public boolean isScrollWheelZoomEnabled() { return scrollWheelZoomEnabled; } /** * Is the StreetView control enabled? * Disabled by default. * * @return true if enabled, false if disabled */ public boolean isStreetViewControlEnabled() { return streetViewControlEnabled; } /** * Sets if the StreeView control should be visible or not. * @param enabled true if StreetView should be allowed, false otherwise */ public void setStreetViewControlEnabled(boolean enabled) { if (this.streetViewControlEnabled != enabled) { streetViewControlEnabled = enabled; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetStreetViewControlEnabled(enabled)); } } } /** * Is the zoom control enabled? * Enabled by default. * * @return true if enabled, false if disabled */ public boolean isZoomControlEnabled() { return zoomControlEnabled; } /** * Sets if the zoom control should be visible or not. * @param enabled true if the zoom-control should be enabled, false otherwise */ public void setZoomControlEnabled(boolean enabled) { if (this.zoomControlEnabled != enabled) { this.zoomControlEnabled = enabled; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetZoomControlEnabled(enabled)); } } } /** * Is the map type control enabled? * Enabled by default. * * @return true if enabled, false if disabled */ public boolean isMapTypeControlEnabled() { return mapTypeControlEnabled; } /** * Sets if the map type control should be visible or not. * @param enabled true if you want the user to have the possibility to * change the map type, false otherwise */ public void setMapTypeControlEnabled(boolean enabled) { if (this.mapTypeControlEnabled != enabled) { this.mapTypeControlEnabled = enabled; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetMapTypeControlEnabled(enabled)); } } } /** * Is the scale control enabled? * Disabled by default. * * @return true if enabled, false if disabled */ public boolean isScaleControlEnabled() { return scaleControlEnabled; } /** * Sets if the scale control should be visible or not. * @param enabled true if the scale-control should be enabled, false otherwise */ public void setScaleControlEnabled(boolean enabled) { if (this.scaleControlEnabled != enabled) { this.scaleControlEnabled = enabled; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetScaleControlEnabled(enabled)); } } } /** * Is the pan control enabled? * Enabled by default. * * @return true if enabled, false if disabled */ public boolean isPanControlEnabled() { return panControlEnabled; } /** * Sets if the pan control should be visible or not. * @param enabled true if the pan-control should be enabled, false otherwise */ public void setPanControlEnabled(boolean enabled) { if (this.panControlEnabled != enabled) { this.panControlEnabled = enabled; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetPanControlEnabled(enabled)); } } } /** * @return the current map type. * @see GMapType */ public GMapType getMapType() { return mapType; } /** * Sets the map type which should be used. * @param mapType the map type * @see GMapType */ public void setMapType(final GMapType mapType) { if (this.mapType != mapType) { this.mapType = mapType; AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(mapType.getJSsetMapType(GMap.this)); } } } /** * @return the current zoom level */ public int getZoom() { return zoom; } /** * @return the minZoom level */ public int getMinZoom() { return minZoom; } /** * @return the maxZoom level */ public int getMaxZoom() { return maxZoom; } /** * Sets a new zoom level. * @param level the new zoom level */ public void setZoom(final int level) { if (this.zoom != level) { this.zoom = level; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetZoom(zoom)); } } } /** * Sets a new minZoom limit. * @param level the new minZoom level */ public void setMinZoom(final int level) { if (this.minZoom != level) { this.minZoom = level >= 0 ? level : 0; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetMinZoom(minZoom)); } } } /** * Sets a new maxZoom limit. * @param level the new maxZoom level */ public void setMaxZoom(final int level) { if (this.maxZoom != level) { this.maxZoom = level >= 0 ? level : 0; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetMaxZoom(maxZoom)); } } } /** * @return the current center point */ public GLatLng getCenter() { return center; } /** * Set the center. * * @param center * center to set */ public void setCenter(final GLatLng center) { if (!this.center.equals(center)) { this.center = center; AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSsetCenter(center)); } } } /** * Changes the center point of the map to the given point. If the point is already visible in the current map view, * change the center in a smooth animation. * * @param center * the new center of the map */ public void panTo(final GLatLng center) { if (!this.center.equals(center)) { this.center = center; AjaxRequestTarget target = getRequestCycle().find(AjaxRequestTarget.class); if (target != null && findPage() != null) { target.appendJavaScript(getJSpanTo(center)); } } } public void setMarkerCluster(GMarkerCluster markerCluster) { if(markerCluster == null) throw new IllegalArgumentException("GMarkerCluster argument should not be null."); this.markerCluster = markerCluster; if (getBehaviors(GMapMarkerClustererHeaderContributor.class).isEmpty()) { add(new GMapMarkerClustererHeaderContributor()); } } public boolean isMarkerClusterEnabled() { return markerCluster != null; } /** * Generates the JavaScript used to instantiate this GMap3 as an JavaScript class on the client side. * * @return The generated JavaScript */ public String getJSinit() { final StringBuilder js = new StringBuilder("new WicketMap('" + getMapId() + "', "+isFailSilently() +"); "); js.append(getJSinvoke("clearOverlays()")); js.append(overlayListener.getJSinit()); js.append(getJSsetCenter(getCenter())); js.append(getJSsetZoom(getZoom())); js.append(getJSsetMinZoom(getMinZoom())); js.append(getJSsetMaxZoom(getMaxZoom())); js.append(getJSfitBounds()); js.append(getJSsetDraggingEnabled(draggingEnabled)); js.append(getJSsetDoubleClickZoomEnabled(doubleClickZoomEnabled)); js.append(getJSsetScrollWheelZoomEnabled(scrollWheelZoomEnabled)); js.append(getJSsetStreetViewControlEnabled(streetViewControlEnabled)); js.append(getJSsetZoomControlEnabled(zoomControlEnabled)); js.append(getJSsetScaleControlEnabled(scaleControlEnabled)); js.append(getJSsetMapTypeControlEnabled(mapTypeControlEnabled)); js.append(getJSsetPanControlEnabled(panControlEnabled)); js.append(getJSFitMarkers()); js.append(mapType.getJSsetMapType(this)); // Add the overlays. for (final GOverlay overlay : overlays.values()) { js.append(overlay.getJS()); } for (final Object behavior : getBehaviors(GEventListenerBehavior.class)) { js.append(((GEventListenerBehavior) behavior).getJSaddListener()); } js.append(getJSMarkerCluster()); return js.toString(); } /** * Convenience method for generating a JavaScript call on this GMap with the given invocation. * * @param invocation * The JavaScript call to invoke on this GMap. * @return The generated JavaScript. */ public String getJSinvoke(final String invocation) { return getJsReference() + "." + invocation + "; "; } /** * Build a reference in JS-Scope. */ public String getJsReference() { return "Wicket.maps['" + getMapId() + "']"; } /** * @see #fitMarkers(List, boolean, double) */ public void fitMarkers(final List<GLatLng> markersToShow) { fitMarkers(markersToShow, false, 0.0); } /** * @see #fitMarkers(List, boolean, double) */ public void fitMarkers(final List<GLatLng> markersToShow, final boolean showMarkersForPoints) { fitMarkers(markersToShow, showMarkersForPoints, 0.0); } /** * <p> * Makes the map zoom out and centre around all the GLatLng points in markersToShow. * <p> * Big ups to Doug Leeper for the code. * * @see <a href= "http://www.nabble.com/Re%3A-initial-GMap2-bounds-question-p19886673.html" >Doug's Nabble post</a> * @param markersToShow * the points to centre around. * @param showMarkersForPoints * if true, will also add basic markers to the map for each point focused on. Just a simple convenience * method - you will probably want to turn this off so that you can show more information with each * marker when clicked etc. */ public void fitMarkers(final List<GLatLng> markersToShow, final boolean showMarkersForPoints, final double zoomAdjustment) { this.markersToShow = markersToShow; // show the markers if (showMarkersForPoints) { for (final GLatLng location : markersToShow) { this.addOverlay(new GMarker(new GMarkerOptions(this, location))); } } } private String getJSFitMarkers() { if (markersToShow.isEmpty()) { return ""; } final StringBuilder buf = new StringBuilder(); buf.append("var bounds = new google.maps.LatLngBounds(); "); // Ask google maps to keep extending the bounds to include each point for (final GLatLng point : markersToShow) { buf.append("bounds.extend( ").append(point.getJSconstructor()).append(" ); "); } buf.append(getJSinvoke("fitBounds(bounds)")); buf.append(getJSinvoke("panToBounds(bounds)")); return buf.toString(); } private String getJSsetDraggingEnabled(final boolean enabled) { return getJSinvoke("setDraggingEnabled(" + enabled + ")"); } private String getJSsetDoubleClickZoomEnabled(final boolean enabled) { return getJSinvoke("setDoubleClickZoomEnabled(" + enabled + ")"); } private String getJSsetScrollWheelZoomEnabled(final boolean enabled) { return getJSinvoke("setScrollWheelZoomEnabled(" + enabled + ")"); } private String getJSsetStreetViewControlEnabled(final boolean enabled) { return getJSinvoke("setStreetViewControlEnabled(" + enabled + ")"); } private String getJSsetZoomControlEnabled(final boolean enabled) { return getJSinvoke("setZoomControlEnabled(" + enabled + ")"); } private String getJSsetScaleControlEnabled(final boolean enabled) { return getJSinvoke("setScaleControlEnabled(" + enabled + ")"); } private String getJSsetMapTypeControlEnabled(final boolean enabled) { return getJSinvoke("setMapTypeControlEnabled(" + enabled + ")"); } private String getJSsetPanControlEnabled(final boolean enabled) { return getJSinvoke("setPanControlEnabled(" + enabled + ")"); } private String getJSsetZoom(final int zoom) { return getJSinvoke("setZoom(" + zoom + ")"); } private String getJSsetMinZoom(final int minZoom) { return getJSinvoke("setMinZoom(" + minZoom + ")"); } private String getJSsetMaxZoom(final int maxZoom) { return getJSinvoke("setMaxZoom(" + maxZoom + ")"); } /** * Build the JavaScript for fitBounds() with the bounds property * * @return JavaScript for the fitBounds-Function */ private String getJSfitBounds() { if (null == bounds || Strings.isEmpty(bounds.getJSconstructor())) { return ""; } // else return getJSinvoke("fitBounds(" + bounds.getJSconstructor() + ")"); } private String getJSsetCenter(final GLatLng center) { if (center != null) { if( !failSilently ) { return getJSinvoke("setCenter(" + center.getJSconstructor() + ")"); } else { return getJSinvoke("setCenterFailSafe(" + center.getArguments() + ")"); } } return ""; } private String getJSpanDirection(final int dx, final int dy) { return getJSinvoke("panDirection(" + dx + "," + dy + ")"); } private String getJSpanTo(final GLatLng center) { return getJSinvoke("panTo(" + center.getJSconstructor() + ")"); } private String getJSzoomOut() { return getJSinvoke("zoomOut()"); } private String getJSzoomIn() { return getJSinvoke("zoomIn()"); } private String getJSMarkerCluster() { if(markerCluster != null) { return markerCluster.getJSconstructor(); } return ""; } /** * Update state from a request to an AJAX target. * You need to call this method explictly if you want to have up-to-date values. */ public void update() { // Attention: don't use setters as this will result in an endless // AJAX request loop IRequestParameters requestParameters = getRequest().getRequestParameters(); bounds = GLatLngBounds.parse(requestParameters.getParameterValue("bounds").toString()); center = GLatLng.parse(requestParameters.getParameterValue("center").toString()); zoom = requestParameters.getParameterValue("zoom").toInt(zoom); String requestMapType = requestParameters.getParameterValue("currentMapType").toString(); mapType = requestMapType != null ? GMapType.valueOf(requestParameters.getParameterValue("currentMapType").toString()) : mapType; } public void setOverlays(final List<GOverlay> overlays) { removeAllOverlays(); for (final GOverlay overlay : overlays) { addOverlay(overlay); } } private static abstract class JSMethodBehavior extends Behavior { private static final long serialVersionUID = 1L; private final String attribute; public JSMethodBehavior(final String attribute) { this.attribute = attribute; } @Override public void onComponentTag(final Component component, final ComponentTag tag) { String invoke = getJSinvoke(); if (attribute.equalsIgnoreCase("href")) { invoke = "javascript:" + invoke; } tag.put(attribute, invoke); } protected abstract String getJSinvoke(); } public class ZoomOutBehavior extends JSMethodBehavior { private static final long serialVersionUID = 1L; public ZoomOutBehavior(final String event) { super(event); } @Override protected String getJSinvoke() { return getJSzoomOut(); } } public class ZoomInBehavior extends JSMethodBehavior { private static final long serialVersionUID = 1L; public ZoomInBehavior(final String event) { super(event); } @Override protected String getJSinvoke() { return getJSzoomIn(); } } public class PanDirectionBehavior extends JSMethodBehavior { private static final long serialVersionUID = 1L; private final int dx; private final int dy; public PanDirectionBehavior(final String event, final int dx, final int dy) { super(event); this.dx = dx; this.dy = dy; } @Override protected String getJSinvoke() { return getJSpanDirection(dx, dy); } } public class SetZoomBehavior extends JSMethodBehavior { private static final long serialVersionUID = 1L; private final int zoomBehavior; public SetZoomBehavior(final String event, final int zoom) { super(event); zoomBehavior = zoom; } @Override protected String getJSinvoke() { return getJSsetZoom(zoomBehavior); } } public class SetCenterBehavior extends JSMethodBehavior { private static final long serialVersionUID = 1L; private final GLatLng gLatLng; public SetCenterBehavior(final String event, final GLatLng gLatLng) { super(event); this.gLatLng = gLatLng; } @Override protected String getJSinvoke() { return getJSsetCenter(gLatLng); } } public class SetMapTypeBehavior extends JSMethodBehavior { private static final long serialVersionUID = 1L; private final GMapType mapTypeBehavior; public SetMapTypeBehavior(final String event, final GMapType mapType) { super(event); mapTypeBehavior = mapType; } @Override protected String getJSinvoke() { return mapTypeBehavior.getJSsetMapType(GMap.this); } } public class OverlayListener extends AbstractDefaultAjaxBehavior { private static final long serialVersionUID = 1L; @Override protected void respond(final AjaxRequestTarget target) { final Request request = RequestCycle.get().getRequest(); final String overlayId = request.getRequestParameters().getParameterValue("overlay.overlayId").toString().replace("overlay", ""); final String event = request.getRequestParameters().getParameterValue("overlay.event").toString(); final GOverlay overlay = overlays.get(overlayId); if (overlay != null) { overlay.onEvent(target, GEvent.valueOf(event)); } } public Object getJSinit() { return GMap.this.getJSinvoke("overlayListenerCallbackUrl = '" + this.getCallbackUrl() + "'"); } } public boolean isFailSilently() { return failSilently; } public void setFailSilently(boolean failSilently) { this.failSilently = failSilently; } }
看下怎么往地图上添加标记,可以看到我们不用直接在客户端写JS,服务端操作即可:
private GMap buildGui() { final EntityModel model = getModel(); final ObjectAdapter adapter = model.getObject(); Location l = (Location) adapter.getObject(); GLatLng latLng = new GLatLng(l.getLatitude(), l.getLongitude()); final boolean visible = latLng != null; final GMap map = new GMap(ID_MAP, apiKey); // map.setStreetViewControlEnabled(true); map.setScaleControlEnabled(false); map.setPanControlEnabled(false); map.setDoubleClickZoomEnabled(false); map.setZoom(17); if (visible) { // centre the map on the first object that has a location. map.setCenter(latLng); } addOrReplace(map); addMarker(map, adapter); return map; } private void addMarker(final GMap map, ObjectAdapter adapter) { ObjectAdapter dereferencedAdapter = dereference(adapter); final GMarker gMarker = createGMarker(map, adapter, dereferencedAdapter); if (gMarker != null) { map.addOverlay(gMarker); // addClickListener(gMarker, dereferencedAdapter); } List<GLatLng> glatLngsToShow = Lists.newArrayList(); map.fitMarkers(glatLngsToShow); }
下边开始尝试替换相应的内容:
GMapHeaderContributor类,改成高德的接口
public class GMapHeaderContributor extends Behavior { private static final long serialVersionUID = 1L; // URL for Google Maps' API endpoint. private static final String GMAP_API_URL = "%s://webapi.amap.com/maps?v=1.3&key=%s"; private static final String HTTP = "http"; // We have some custom Javascript. private static final ResourceReference WICKET_GMAP_JS = new JavaScriptResourceReference(GMap.class, "wicket-gmap.js"); //... }
wicket-gmap.js
//... //地图对象的实例化 function WicketClientGeocoder() { this.coder = new AMap.Geocoder(); this.getLatLng = function(callBack, addressId){ var address = Wicket.$(addressId).value; this.coder.geocode({ 'address': address }, function(results, status){ var params = {}; if (status == AMap.GeocoderStatus.OK) { params['address'] = results[0].formatted_address; params['coordinates'] = results[0].geometry.location; params['status'] = status; } for ( var key in params) { callBack = callBack + '&' + key + '=' + params[key]; } Wicket.Ajax.ajax({ 'u':callBack, 'ep': params }); }); } } //其它API有差异的地方也相应的改一下,此处略 //...
实现集合页UI适配工厂:
/* * Copyright 2013~2014 Dan Haywood * * 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 com.itisys.map.ui; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.net.UnknownHostException; import org.apache.isis.core.commons.config.IsisConfiguration; import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.specloader.SpecificationLoader; import org.apache.isis.core.runtime.system.context.IsisContext; import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel; import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory; import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract; import org.apache.isis.viewer.wicket.ui.ComponentType; import org.apache.wicket.Component; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import com.itisys.map.applib.AmapApplibConstants; import com.itisys.map.applib.Locatable; public class CollectionOfEntitiesAsLocatablesFactory extends ComponentFactoryAbstract implements CollectionContentsAsFactory { private static final long serialVersionUID = 1L; private static final String ID_MAP = "map"; private boolean determinedWhetherInternetReachable; private boolean internetReachable; public CollectionOfEntitiesAsLocatablesFactory() { super(ComponentType.COLLECTION_CONTENTS, ID_MAP); } @Override public ApplicationAdvice appliesTo(IModel<?> model) { final String apiKey = getConfiguration().getString(AmapApplibConstants.API_KEY); if(apiKey == null) { return ApplicationAdvice.DOES_NOT_APPLY; } if(!internetReachable()) { return ApplicationAdvice.DOES_NOT_APPLY; } if (!(model instanceof EntityCollectionModel)) { return ApplicationAdvice.DOES_NOT_APPLY; } EntityCollectionModel entityCollectionModel = (EntityCollectionModel) model; ObjectSpecification typeOfSpec = entityCollectionModel.getTypeOfSpecification(); ObjectSpecification locatableSpec = getSpecificationLoader().loadSpecification(Locatable.class); return appliesIf(typeOfSpec.isOfType(locatableSpec)); } private boolean internetReachable() { if(!determinedWhetherInternetReachable) { internetReachable = isInternetReachable(); determinedWhetherInternetReachable = true; } return internetReachable; } /** * Tries to retrieve some content, 1 second timeout. */ private static boolean isInternetReachable() { try { final URL url = new URL("http://www.amap.com"); final HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection(); urlConnect.setConnectTimeout(1000); urlConnect.getContent(); urlConnect.disconnect(); } catch (UnknownHostException e) { return false; } catch (IOException e) { return false; } return true; } public Component createComponent(String id, IModel<?> model) { final String apiKey = getConfiguration().getString(AmapApplibConstants.API_KEY); EntityCollectionModel collectionModel = (EntityCollectionModel) model; return new CollectionOfEntitiesAsLocatables(id, apiKey, collectionModel); } protected SpecificationLoader getSpecificationLoader() { return IsisContext.getSessionFactory().getSpecificationLoader(); } protected IsisConfiguration getConfiguration() { return IsisContext.getSessionFactory().getConfiguration(); } @Override public IModel<String> getTitleLabel() { return Model.of("Map"); } @Override public IModel<String> getCssClass() { return Model.of("fa fa-map-marker"); } }
实现实体属性UI适配:
/* * Copyright 2013~2014 Dan Haywood * * 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 com.itisys.map.ui; import org.apache.isis.core.commons.config.IsisConfiguration; import org.apache.isis.core.metamodel.specloader.SpecificationLoader; import org.apache.isis.core.runtime.system.context.IsisContext; import org.apache.isis.viewer.wicket.model.models.ScalarModel; import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScalarAbstract; import org.apache.wicket.Component; import com.itisys.map.applib.AmapApplibConstants; import com.itisys.map.applib.Location; public class EntityAsLocatablesFactory extends ComponentFactoryScalarAbstract { private static final long serialVersionUID = 1L; private static final String ID_MAP = "map"; public EntityAsLocatablesFactory() { super(EntityAsLocatables.class, Location.class); } protected SpecificationLoader getSpecificationLoader() { return IsisContext.getSessionFactory().getSpecificationLoader(); } protected IsisConfiguration getConfiguration() { return IsisContext.getSessionFactory().getConfiguration(); } @Override protected Component createComponent(String id, ScalarModel scalarModel) { final String apiKey = getConfiguration().getString(AmapApplibConstants.API_KEY); return new EntityAsLocatables(id,apiKey, scalarModel); } }