Google Maps Drag & Drop
Drag & Drop demo to add or remove icons from a Google Map bij dragging them onto it, and use the coordinates if needed. The code also requires jQuery UI.
You can only drag icons from outside the map with a mouse. It won't work with a touch event so you can also double-click on them to add them to the map.
Download the JavaScript (Minified)
Download the Dutch Province outline coordinates.
View source on GitHubIcons on map: 0
Code Snippets
The HTML part.
<div class="container"> <div class="row"> <div class="col-12 col-md-10"> <div id="map_container" class="map_container"> <div id="map_dragdrop" class="map_dragdrop"></div> <div id="map_recyclebin" class="map_recyclebin"> <img src="/images/trash.png" /> </div> </div> </div> <div class="col-12 col-md-2 text-center pt-4 pt-md-0"> <div id="map_icon_container" class="map_icon_container"></div> </div> </div> <div class="row"> <div class="col-12 col-md-10 pt-3"> <textarea id="map_results" class="form-control"></textarea> </div> </div> </div> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> <script src="https://maps.googleapis.com/maps/api/js?key=YourGoogleApiKey"></script>
The CSS.
.map_container { width: 100%; height: 500px; overflow: hidden; } .map_dragdrop { width: 100%; height: 100%; } .map_recyclebin { position: relative; height: 60px; width: 60px; top: -85px; right: -10px; background: white; box-shadow: rgba(0, 0, 0, 0.4) 0px 1px 4px -1px; border-radius: 2px; } .map_icon_container { font-size: 12px; font-weight: bold; width: 100%; } .map_icon { cursor: pointer; margin: 3px 0px 15px 0px; } .map_button { width: 150px; } /* make responsive */ @media (max-width: 767.98px) { .map_icon_container div { float: left; width: 20%; } }
And finally the Javascript. THere is some code in there to generate the Dutch Provinces, but you can remove that easily.
var map; var overlay; var poiIconWidth = 32; var poiIconHeight = 42; var zIndex = 100; var poiMarkerArry = []; var binDimensions; var binXoffset = 10; var binYoffset = 25; var zoomLevel = 7; var $map_results; var $map_dragdrop; var $map_iconcounter; //the icons var poiData = [{ id: 10, name: 'Icon #1', icon: '/files/icon_1.png' }, { id: 20, name: 'Icon #2', icon: '/files/icon_2.png' }, { id: 300, name: 'Icon #3', icon: '/files/icon_3.png' }, { id: 400, name: 'Icon #4', icon: '/files/icon_4.png' }, { id: 5000, name: 'Icon #5', icon: '/files/icon_5.png' }]; //timeout because jquery script is loaded later that this js file on this page setTimeout(function () { $map_results = $('#map_results'); $map_dragdrop = $('#map_dragdrop'); binDimensions = $('#map_recyclebin').height(); $map_iconcounter = $('#map_iconcounter'); $('#map_reset_button').bind('click', function () { resetPoiMap(); }); $('#map_load_button').bind('click', function () { loadJsonData(); }); initializePoiMap(52.52000, 5.28662); }, 50); //create the map function initializePoiMap(lat, lng) { //coord for the center of the map var startpos = new google.maps.LatLng(lat, lng); //map options var options = { zoom: zoomLevel, center: startpos, zoomControl: true, mapTypeControl: false, scaleControl: false, streetViewControl: false, rotateControl: false, fullscreenControl: false, mapTypeId: google.maps.MapTypeId.TERRAIN }; //start the map map = new google.maps.Map(document.getElementById('map_dragdrop'), options); //add an overlay overlay = new google.maps.OverlayView(); overlay.draw = function () { }; overlay.setMap(map); generatePoiMarkerlist(); loadJsonData(); //for netherlands only buildProvinces(); buildIslands(); } //add the icons that can be dragged to the html page and attach the drag function function generatePoiMarkerlist() { //add the icons for (var i = 0; i < poiData.length; i++) { var content = '<div>' + poiData[i].name + '<br><img data-id="' + poiData[i].id + '" data-index="' + i + '" class="map_icon" src="' + poiData[i].icon + '" /></div>'; $('#map_icon_container').append(content); } var $icons = $('.map_icon'); //attach the drag event $icons.draggable({ stop: function (e) { dragIn(e, this, $(this).data('index')); } }); //attach the double click event $icons.dblclick(function () { addIconToMap([map.getCenter().lat(), map.getCenter().lng()], this, $(this).data('index')); }); //make the double click working on touch devices var tap = 0; $icons.on('touchend', function () { var now = new Date().getTime(); var ms = now - tap; if (ms > 0 && ms < 500) { addIconToMap([map.getCenter().lat(), map.getCenter().lng()], this, $(this).data('index')); } tap = new Date().getTime(); }); } //generate a marker on the map function generatePoiMarker(poi) { var marker = new google.maps.Marker({ position: new google.maps.LatLng(poi.mapPosition[0], poi.mapPosition[1]), map: map, draggable: true, icon: { url: poi.icon, size: google.maps.Size(poiIconWidth, poiIconHeight), target: google.maps.Point(poiIconWidth / 2, poiIconHeight / 2), origin: google.maps.Point(poiIconWidth / 2, poiIconHeight / 2) }, title: poi.name, type: poi.id, zIndex: zIndex }); marker.idnr = poiMarkerArry.length; poiMarkerArry.push(marker); zIndex++; updatePoiCoords(); //add the mouse over event to put an icon always on top on hover google.maps.event.addListener(marker, 'mouseover', function () { this.setZIndex(zIndex); zIndex++; }); //drag end event to update the marker data google.maps.event.addListener(marker, 'dragstart', function () { //set the map drag to false, otherwise the maps starts scrolling when you get to the edges map.setOptions({ draggable: false }); }); //drag end event to update the marker data google.maps.event.addListener(marker, 'dragend', function (e) { //enable map scrolling again map.setOptions({ draggable: true }); var pixelPosition = getPixelPosition(this); //check if the icon is inside the recycle bin if (pixelPosition.x < binDimensions + binXoffset && pixelPosition.x > binXoffset && pixelPosition.y > ($map_dragdrop.height() - binDimensions) - binYoffset && pixelPosition.y < $map_dragdrop.height() - binYoffset) { dragOut(e, this); } else { poiMarkerArry[this.idnr].position = e.latLng; updatePoiCoords(); } }); } //update the coord after dragging an icon function updatePoiCoords() { var poiArr = []; for (var i = 0; i < poiMarkerArry.length; i++) { if (poiMarkerArry[i] !== null) { var poiMarker = { lat: poiMarkerArry[i].position.lat(), lng: poiMarkerArry[i].position.lng(), type: poiMarkerArry[i].type }; poiArr.push(poiMarker); } } //make a json var json = JSON.stringify(poiArr); //not really needed, just used to neatly display the output inside the textarea json = json.replace('[', '[\n ').replace(/},{/g, '},\n {').replace(']', '\n]'); //put it in an input $map_results.val(json); //show counter $map_iconcounter.html(poiArr.length); } //translate the map coordinates into pixels function getPixelPosition(marker) { var scale = Math.pow(2, map.getZoom()); var nw = new google.maps.LatLng( map.getBounds().getNorthEast().lat(), map.getBounds().getSouthWest().lng() ); var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw); var worldCoordinate = map.getProjection().fromLatLngToPoint(marker.getPosition()); var pixelOffset = new google.maps.Point( Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale), Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale) ); return { x: pixelOffset.x, y: pixelOffset.y, right: $map_dragdrop.width() - pixelOffset.x, bottom: $map_dragdrop.height() - pixelOffset.y }; } //an icon is dragged function dragIn(e, icon, index) { var x = e.pageX - $map_dragdrop.offset().left; var y = e.pageY - $map_dragdrop.offset().top + 25; //check if the drag is on the map if (x > 0 && x < $map_dragdrop.width() && y > 0) { var point = new google.maps.Point(x, y); var position = overlay.getProjection().fromContainerPixelToLatLng(point); addIconToMap([position.lat(), position.lng()], icon, index); } } //place the icon on the map function addIconToMap(position, icon, index) { var poi = { mapPosition: position, icon: poiData[index].icon, name: poiData[index].name, id: poiData[index].id }; generatePoiMarker(poi); $(icon).attr('style', 'position: relative; left: 0px; top: 0px'); } //an icon is stopped dragging function dragOut(e, marker) { poiMarkerArry[marker.idnr] = null; marker.setMap(null); updatePoiCoords(); } //load the json data from the textbox function loadJsonData() { //if there are existings icons, add them to the map if ($map_results.val() === '') return; //here the data comes from a textarea. but could be from any other source var data = $.parseJSON($map_results.val()); //reset map also resetPoiMap(); //loop all poi's for (var i = 0; i < data.length; i++) { //find the right marker based on id for (var j = 0; j < poiData.length; j++) { //if the item matches the id of the poi icon if (poiData[j].id === data[i].type) { var poi = { mapPosition: [data[i].lat, data[i].lng], icon: poiData[j].icon, name: poiData[j].name, id: poiData[j].id }; generatePoiMarker(poi); } } } } //reset the map data function resetPoiMap() { for (var i = 0; i < poiMarkerArry.length; i++) { poiMarkerArry[i].setMap(null); } $map_iconcounter.html('0'); $map_results.val(''); poiMarkerArry = []; //if you use the dutch province polygons for (var i = 0; i < polygonArr.length; i++) { polygonArr[i].setMap(null); } polygonArr = []; } //below code specifically for The Netherlands var polygonArr = []; //build the dutch province polygons function buildProvinces() { for (var i = 0; i < provincesNL.length; i++) { var polygon = new google.maps.Polygon({ paths: provincesNL[i], strokeColor: "#000000", strokeOpacity: 1.0, strokeWeight: 2, fillColor: provinceColors[i], fillOpacity: 0.2, clickable: true }); polygonArr.push(polygon); polygon.setMap(map); attachToPolygon(polygon, provinceCenters[i]); } } //build the dutch island polygons function buildIslands() { for (var i = 0; i < islandsNL.length; i++) { var polygon = new google.maps.Polygon({ paths: islandsNL[i], strokeColor: "#000000", strokeOpacity: 1.0, strokeWeight: 2, fillColor: islandColors[i], fillOpacity: 0.2, clickable: true }); polygonArr.push(polygon); polygon.setMap(map); attachToPolygon(polygon, islandCenters[i]); } } //add a function to the polygon that centers on the province centre on clicking function attachToPolygon(poly, centerPoint) { //zoom and center to province google.maps.event.addListener(poly, 'click', function () { map.panTo(centerPoint); map.setZoom(9); }); //zoom out the province to original zoom level google.maps.event.addListener(poly, 'rightclick', function () { map.setZoom(zoomLevel); map.panTo(dutchCenterPoint); }); }