0

這是爲了幫助那些試圖實現此目標的人,或者像我一直在尋找這種解決方案的人一樣。沒有成功找到現有的解決方案,我最終決定去做。在Google Maps API v3中使用單個刪除按鈕繪製圓/多邊形

如何將刪除按鈕或X標記添加到繪製的形狀(圓形/多邊形),以便可以使用此按鈕刪除單個形狀?

回答

2

這是Github Link查看圖書館,也是一個完整的工作示例。

在繪製圓圈時,刪除按鈕(X標記)將放置在圓周上45度(東北)。 對於多邊形,由於它們可能是不可預測的,我將刪除按鈕(X標記)放置在多邊形的第一個頂點旁邊。

您可以刪除單個圓/多邊形或清除所有繪製的圖形。

直接調用庫在HTML文件中使用下面的腳本,
<script src="https://gist.github.com/loyalvares/c4ba7420b1eb055b309ab48bdcd34219.js"></script>

這是JSFiddle Link相同的。

/* 
 
    * Method that is called when Google Maps API is loaded. 
 
    */ 
 
    function initMap() { 
 
    \t setInitialMapOptions(); 
 
    \t map = getMapObject(mapOptions); 
 
    \t drawingManager = getDrawingManagerObject(); 
 
    \t google.maps.event.addListener(drawingManager, 'overlaycomplete', onOverlayComplete); 
 
    \t initializeDeleteOverlayButtonLibrary(); 
 
    } 
 

 
    // Get Map Geo Center Denver, USA Coordinates 
 
    var center = {lat: 39.810866, lng: -104.990347}; 
 
    var map, drawingManager, mapOptions = {}; 
 
    var listenerFiltersApplied = false; 
 
    var overlays = {}; 
 
    var circleOptions = { 
 
      fillColor: "#e20000", 
 
      fillOpacity: 0, 
 
      strokeColor: "#e20000", 
 
      strokeWeight: 4, 
 
      strokeOpacity: 1, 
 
      clickable: false, 
 
      editable: true, 
 
      suppressUndo: true, 
 
      zIndex: 999 
 
     \t }; 
 
    var polygonOptions = { 
 
    \t \t editable: true, 
 
    \t \t fillColor: "#e20000", 
 
      fillOpacity: 0, 
 
    \t \t strokeColor: "#e20000", 
 
    \t \t strokeWeight: 4, 
 
    \t  strokeOpacity: 1, 
 
    \t  suppressUndo: true, 
 
    \t  zIndex: 999 
 
    \t }; 
 

 
    function setInitialMapOptions() { 
 
    \t mapOptions = { 
 
    \t \t \t zoom: 4, 
 
    \t \t \t center: center, 
 
    \t \t \t styles: [ 
 
    \t \t \t \t {"featureType":"road", elementType:"geometry", stylers: [{visibility:"off"}]}, \t //turns off roads geometry 
 
    \t \t \t \t {"featureType":"road", elementType:"labels", stylers: [{visibility:"off"}]}, \t //turns off roads labels 
 
    \t \t \t \t {"featureType":"poi", elementType:"labels", stylers: [{visibility:"off"}]}, //turns off points of interest lines 
 
    \t \t \t \t {"featureType":"poi", elementType:"geometry", stylers: [{visibility:"off"}]}, //turns off points of interest geometry 
 
    \t \t \t \t {"featureType":"transit", elementType:"labels", stylers: [{visibility:"off"}]}, //turns off transit lines labels 
 
    \t \t \t \t {"featureType":"transit", elementType:"geometry", stylers: [{visibility:"off"}]}, \t //turns off transit lines geometry 
 
    \t \t \t \t {"featureType":"administrative.land_parcel", elementType:"labels", stylers: [{visibility:"off"}]}, //turns off administrative land parcel labels 
 
    \t \t \t \t {"featureType":"administrative.land_parcel", elementType:"geometry", stylers: [{visibility:"off"}]}, //turns off administrative land parcel geometry 
 
    \t \t \t \t {"featureType":"water", elementType:"geometry", stylers: [{color: '#d1e1ff'}]}, //sets water color to a very light blue 
 
    \t \t \t \t {"featureType":"landscape", elementType:"geometry", stylers: [{color: '#fffffa'}]}, //sets landscape color to a light white color 
 
    \t \t \t \t ], 
 
    \t \t \t \t mapTypeControl: false, 
 
    \t \t \t \t panControl: true, 
 
    \t \t \t \t panControlOptions: { 
 
    \t \t \t \t \t position: google.maps.ControlPosition.RIGHT_CENTER 
 
    \t \t \t \t }, 
 
    \t \t \t \t streetViewControl: false, 
 
    \t \t \t \t scaleControl: false, 
 
    \t \t \t \t zoomControl: true, 
 
    \t \t \t \t zoomControlOptions: { 
 
    \t \t \t \t \t style: google.maps.ZoomControlStyle.SMALL, 
 
    \t \t \t \t \t position: google.maps.ControlPosition.RIGHT_BOTTOM 
 
    \t \t \t \t }, 
 
    \t \t \t \t minZoom: 2 
 
    \t }; 
 
    } 
 

 
    function getMapObject(mapOptions) { 
 
     var map = new google.maps.Map(document.getElementById('map'), mapOptions); 
 
     return map; 
 
    } 
 

 
    function getDrawingManagerObject(drawingManagerOptions) { 
 
    \t var drawingManager = new google.maps.drawing.DrawingManager({ 
 
      drawingMode: null, 
 
      drawingControl: true, 
 
      drawingControlOptions: { 
 
       position: google.maps.ControlPosition.TOP_CENTER, 
 
       drawingModes: [ 
 
      \t google.maps.drawing.OverlayType.CIRCLE, 
 
      \t google.maps.drawing.OverlayType.POLYGON 
 
     \t ] 
 
      }, 
 
      circleOptions: circleOptions, 
 
      polygonOptions: polygonOptions 
 
      }); 
 
      drawingManager.setMap(map); 
 
      return drawingManager; 
 
    } 
 

 
    /* -- Overlay Functions Begin Here -- */ 
 
    function onOverlayComplete(shape) { 
 
    \t addDeleteButtonToOverlay(shape); 
 
    \t addOverlayListeners(shape); 
 
    \t if(listenerFiltersApplied) { 
 
    \t \t listenerFiltersApplied = false; 
 
    \t } 
 
    } 
 

 
    function addOverlayListeners(shape) { 
 
    \t // Filters already applied. 
 
    \t if(listenerFiltersApplied) { 
 
    \t \t return; 
 
    \t } 
 
    \t if (shape.type == google.maps.drawing.OverlayType.POLYGON) { 
 
    \t \t setBoundsChangedListener(shape); 
 
    \t } \t 
 
    \t if (shape.type == google.maps.drawing.OverlayType.CIRCLE) { 
 
    \t \t setCenterChangedListener(shape); 
 
    \t \t setRadiusChangedListener(shape); 
 
    \t } 
 
    } 
 

 
    function setBoundsChangedListener(shape) { 
 
    \t // Add listeners for each path of the polygon. 
 
    \t shape.overlay.getPaths().forEach(function(path, index){ 
 
    \t \t // New point 
 
    \t \t google.maps.event.addListener(path, 'insert_at', function(){ 
 
    \t \t \t listenerFiltersApplied = true; 
 
    \t \t \t onOverlayComplete(shape); 
 
    \t \t }); 
 
    \t \t // Point was removed 
 
    \t \t google.maps.event.addListener(path, 'remove_at', function(){ 
 
    \t \t \t listenerFiltersApplied = true; 
 
    \t \t \t onOverlayComplete(shape); 
 
    \t \t }); 
 
    \t \t // Point was moved 
 
    \t \t google.maps.event.addListener(path, 'set_at', function(){ 
 
    \t \t \t listenerFiltersApplied = true; 
 
    \t \t \t onOverlayComplete(shape); 
 
    \t \t }); 
 
    \t }); 
 
    } 
 

 
    function setCenterChangedListener(shape) { 
 
    \t google.maps.event.addListener(shape.overlay, 'center_changed', function() { 
 
    \t \t listenerFiltersApplied = true; 
 
    \t \t onOverlayComplete(shape); 
 
    \t }); 
 
    } 
 

 
    function setRadiusChangedListener(shape) { 
 
    \t google.maps.event.addListener(shape.overlay, 'radius_changed', function() { 
 
    \t \t listenerFiltersApplied = true; 
 
    \t \t onOverlayComplete(shape); 
 
    \t }); 
 
    } 
 

 
    function addDeleteButtonToOverlay(shape) { 
 
    \t var deleteOverlayButton = new DeleteOverlayButton(); 
 
    \t if(("deleteButton" in shape) && (shape.deleteButton != null)) { 
 
    \t \t shape.deleteButton.div.remove(); 
 
    \t \t shape.deleteButton = deleteOverlayButton; 
 
    \t } else { 
 
    \t \t shape.deleteButton = deleteOverlayButton; 
 
    \t } 
 
    \t if(shape.type == google.maps.drawing.OverlayType.CIRCLE) { 
 
    \t \t var radiusInKms = convertDistance(Math.round(shape.overlay.getRadius()), "metres", "kms"); 
 
    \t \t var circleCenter = new google.maps.LatLng(shape.overlay.getCenter().lat(), shape.overlay.getCenter().lng()); 
 
    \t \t var deleteOverlayButtonPosition = circleCenter.destinationPoint(30, radiusInKms); 
 
    \t \t deleteOverlayButton.open(map, deleteOverlayButtonPosition, shape); 
 
    \t } else if (shape.type == google.maps.drawing.OverlayType.POLYGON) { 
 
    \t \t deleteOverlayButton.open(map, shape.overlay.getPath().getArray()[0], shape); 
 
    \t } 
 
     
 
     if (!('uid' in shape)) { 
 
    \t \t shape.uid = Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36); 
 
    \t } 
 
    \t overlays[shape.uid] = shape; 
 
    } 
 

 
    function clearAllOverlays() { 
 
    \t for(var shapeId in overlays) { 
 
    \t \t if(overlays.hasOwnProperty(shapeId)) { 
 
    \t \t \t var shape = overlays[shapeId]; 
 
    \t \t \t if(("deleteButton" in shape) && (shape.deleteButton != null)) { 
 
    \t \t \t \t shape.deleteButton.div.remove(); 
 
    \t \t \t } 
 
    \t \t \t shape.overlay.setMap(null); 
 
    \t \t } 
 
    \t } 
 
    \t overlays = {}; 
 
    } 
 

 
    /* 
 
    * Add any code that needs to be run or cleaned up in this method. 
 
    * This method is called in DeleteOverlayButton.removeShape(). 
 
    */ 
 
    function callOnDelete(shape) { 
 
    \t if(shape['uid'] in overlays) { 
 
    \t \t delete overlays[shape['uid']]; 
 
    \t } 
 
    } 
 
    /* -- Overlay Functions End Here -- */ 
 

 
    function convertDistance(distanceValue, actualDistanceUnit, expectedDistanceUnit) { 
 
    \t var distanceInKms = 0; 
 
    \t switch(actualDistanceUnit) { 
 
    \t \t case "miles": 
 
    \t \t \t distanceInKms = distanceValue/0.62137; 
 
    \t \t \t break; 
 
    \t \t case "kms": 
 
    \t \t \t distanceInKms = distanceValue; 
 
    \t \t \t break; 
 
    \t \t case "metres": 
 
    \t \t \t distanceInKms = distanceValue/1000; 
 
    \t \t \t break; 
 
    \t \t default: 
 
    \t \t \t distanceInKms = undefined; 
 
    \t } 
 
    \t 
 
    \t switch(expectedDistanceUnit) { 
 
    \t \t case "miles": 
 
    \t \t \t return distanceInKms * 0.62137; 
 
    \t \t case "kms": 
 
    \t \t \t return distanceInKms; 
 
    \t \t case "metres": 
 
    \t \t \t return distanceInKms * 1000; 
 
    \t \t default: 
 
    \t \t \t return undefined; 
 
    \t } 
 
    } 
 

 

 
    /* ***** Custom Library for Delete Overlay Button (Start) ***** */ 
 
    \t 
 
    \t /** 
 
    \t * A HTML Button that lets a user delete a component. 
 
    \t * @constructor 
 
    \t * @author: Loy Alvares 
 
    \t */ 
 
    \t function DeleteOverlayButton() { 
 
    \t \t this.div = document.createElement('div'); 
 
    \t \t this.div.id = 'deleteOverlayButton'; 
 
    \t \t this.div.className = 'deleteOverlayButton'; 
 
    \t \t this.div.title = 'Delete'; 
 
    \t \t this.div.innerHTML = '<span id="x">X</span>'; 
 
    \t \t var button = this; 
 
    \t \t google.maps.event.addDomListener(this.div, 'click', function() { 
 
    \t \t  button.removeShape(); 
 
    \t \t \t button.div.remove(); 
 
    \t \t }); 
 
    \t } 
 
    \t 
 
    \t function initializeDeleteOverlayButtonLibrary() { 
 
    \t \t 
 
      /* This needs to be initialized by initMap() */ 
 
    \t \t DeleteOverlayButton.prototype = new google.maps.OverlayView(); 
 
    \t \t 
 
    \t \t /** 
 
    \t \t * Add component to map. 
 
    \t \t */ 
 
    \t \t DeleteOverlayButton.prototype.onAdd = function() { 
 
    \t \t \t var deleteOverlayButton = this; 
 
    \t \t \t var map = this.getMap(); 
 
    \t \t \t this.getPanes().floatPane.appendChild(this.div); 
 
    \t \t }; 
 

 
    \t \t /** 
 
    \t \t * Clear data. 
 
    \t \t */ 
 
    \t \t DeleteOverlayButton.prototype.onRemove = function() { 
 
    \t \t \t google.maps.event.removeListener(this.divListener_); 
 
    \t \t \t this.div.parentNode.removeChild(this.div); 
 
    \t \t \t // Clear data 
 
    \t \t \t this.set('position'); 
 
    \t \t \t this.set('overlay'); 
 
    \t \t }; 
 

 
    \t \t /** 
 
    \t \t * Deletes an overlay. 
 
    \t \t */ 
 
    \t \t DeleteOverlayButton.prototype.close = function() { 
 
    \t \t \t this.setMap(null); 
 
    \t \t }; 
 

 
    \t \t /** 
 
    \t \t * Displays the Button at the position(in degrees) on the circle's circumference. 
 
    \t \t */ 
 
    \t \t DeleteOverlayButton.prototype.draw = function() { 
 
    \t \t \t var position = this.get('position'); 
 
    \t \t \t var projection = this.getProjection(); 
 
    \t \t \t if (!position || !projection) { 
 
    \t \t \t \t return; 
 
    \t \t \t } 
 
    \t \t \t var point = projection.fromLatLngToDivPixel(position); 
 
    \t \t \t this.div.style.top = point.y + 'px'; 
 
    \t \t \t this.div.style.left = point.x + 'px'; 
 
    \t \t \t if(this.get('overlay').type == google.maps.drawing.OverlayType.POLYGON) { 
 
    \t \t \t \t this.div.style.marginTop = '-16px'; 
 
    \t \t \t \t this.div.style.marginLeft = '0px'; 
 
    \t \t \t } 
 
    \t \t }; 
 

 
    \t \t /** 
 
    \t \t * Displays the Button at the position(in degrees) on the circle's circumference. 
 
    \t \t */ 
 
    \t \t DeleteOverlayButton.prototype.open = function(map, deleteOverlayButtonPosition, overlay) { 
 
    \t \t \t this.set('position', deleteOverlayButtonPosition); 
 
    \t \t \t this.set('overlay', overlay); 
 
    \t \t \t this.setMap(map); 
 
    \t \t \t this.draw(); 
 
    \t \t }; 
 

 
    \t \t /** 
 
    \t \t * Deletes the shape it is associated with. 
 
    \t \t */ 
 
    \t \t DeleteOverlayButton.prototype.removeShape = function() { 
 
    \t \t \t var position = this.get('position'); 
 
    \t \t \t var shape = this.get('overlay'); 
 
    \t \t \t if (shape != null) { 
 
    \t \t \t \t shape.overlay.setMap(null); 
 
      /* Add any cleanup code or any other events in the below method. */ 
 
    \t \t \t \t callOnDelete(shape); 
 
    \t \t \t \t return; 
 
    \t \t \t } 
 
    \t \t \t this.close(); 
 
    \t \t }; 
 
    \t \t 
 
    \t \t Number.prototype.toRadians = function() { 
 
    \t \t \t return this * Math.PI/180; 
 
    \t \t } 
 

 
    \t \t Number.prototype.toDegrees = function() { 
 
    \t \t \t return this * 180/Math.PI; 
 
    \t \t } 
 

 
    \t \t /* Based the on the Latitude/Longitude spherical geodesy formulae & scripts 
 
    \t \t at http://www.movable-type.co.uk/scripts/latlong.html 
 
    \t \t (c) Chris Veness 2002-2010 
 
    \t \t */ 
 
    \t \t google.maps.LatLng.prototype.destinationPoint = function(bearing, distance) { 
 
    \t \t \t distance = distance/6371; 
 
    \t \t \t bearing = bearing.toRadians(); 
 
    \t \t \t var latitude1 = this.lat().toRadians(), longitude1 = this.lng().toRadians(); 
 
    \t \t \t var latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(distance) + Math.cos(latitude1) * Math.sin(distance) * Math.cos(bearing)); 
 
    \t \t \t var longitude2 = longitude1 + Math.atan2(Math.sin(bearing) * Math.sin(distance) * Math.cos(latitude1), Math.cos(distance) - Math.sin(latitude1) * Math.sin(latitude2)); 
 
    \t \t \t if (isNaN(latitude2) || isNaN(longitude2)) return null; 
 
    \t \t \t return new google.maps.LatLng(latitude2.toDegrees(), longitude2.toDegrees()); 
 
    \t \t } 
 
    \t } 
 

 
    /* ***** Custom Library for Delete Overlay Button (End) ***** */
/* Always set the map height explicitly to define the size of the div element that contains the map. */ 
 
    .map { 
 
     height: 100%; 
 
    } 
 

 
    /* Optional: Makes the sample page fill the window. */ 
 
    html, body { 
 
     height: 100%; 
 
     margin: 0; 
 
     padding: 0; 
 
    } 
 

 
    /* CSS for the Delete Button. */ 
 
    .deleteOverlayButton { 
 
     background: #dee0df; 
 
     color: #000; 
 
     /* font-family: 'Helvetica', 'Arial', sans-serif; */ 
 
     font-size: 11.4px; 
 
     font-weight: bold; 
 
     text-align: center; 
 
     width: 14px; 
 
     height: 15px; 
 
     border-radius: 8px; 
 
     box-shadow: 1px 0px -1px rgba(0, 0, 0, .3); 
 
     position: absolute; 
 
     padding: 0px 0px 0px 0px; 
 
     margin-top: 7px; 
 
     margin-left: 8px; 
 
     border: 1px solid #999; 
 
     cursor: pointer; 
 
    } 
 

 
    .deleteOverlayButton:hover { 
 
     background: #eee; 
 
    } 
 

 
    #clearOverlays { 
 
     font-family: var(--websiteFont); 
 
     top: 10%; 
 
     position: absolute; 
 
     right: 1%; 
 
     background: rgb(34,55,65); 
 
     border-radius: 4px; 
 
     color: white; 
 
     border: 1px solid rgb(34,55,65); 
 
     padding: 2px 6px; 
 
     cursor: pointer; 
 
    }
<div id="map" class="map"></div> 
 
    <input id='clearOverlays' onclick="clearAllOverlays();" type=button value="Clear Shapes" /> 
 

 
    <link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.css" /> 
 
    <script \t src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD7MXQvcn_gskiZeZGhhXekqN1zjUX9fVM&libraries=drawing&callback=initMap" async defer></script>

相關問題