На страницах своего блога я уже рассказывал о том, как нарисовать полилинию в заметке: «API Google Maps рисуем полилинию и сохраняем ее в базе данных MySQL».
В этот раз я расскажу как примерно это же можно сделать, используя API Google Maps v3 и определить длину нарисованной полилинии.
Код для примера рисования и редактирования полилинии я взял отсюда и немного переработал.
Код файла plineedit-gmap3.html с изменениями:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Google Maps api v3 - Рисуем полилинию и определяем ее длину</title> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript"> var map = null; var polyLine; var tmpPolyLine; var markers = []; var vmarkers = []; var g = google.maps; var initMap = function(mapHolder) { markers = []; vmarkers = []; var mapOptions = { zoom: 14, center: new g.LatLng(56.316667, 44), mapTypeId: g.MapTypeId.ROADMAP, draggableCursor: 'auto', draggingCursor: 'move', disableDoubleClickZoom: true }; map = new g.Map(document.getElementById(mapHolder), mapOptions); g.event.addListener(map, "click", mapLeftClick); mapHolder = null; mapOptions = null; }; var initPolyline = function() { var polyOptions = { strokeColor: "#ff0061", strokeOpacity: 0.8, strokeWeight: 4 }; var tmpPolyOptions = { strokeColor: "#ff0061", strokeOpacity: 0.4, strokeWeight: 4 }; polyLine = new g.Polyline(polyOptions); polyLine.setMap(map); tmpPolyLine = new g.Polyline(tmpPolyOptions); tmpPolyLine.setMap(map); }; var mapLeftClick = function(event) { if (event.latLng) { var marker = createMarker(event.latLng); markers.push(marker); if (markers.length != 1) { var vmarker = createVMarker(event.latLng); vmarkers.push(vmarker); vmarker = null; } var path = polyLine.getPath(); path.push(event.latLng); marker = null; } event = null; }; var createMarker = function(point) { var imageNormal = new g.MarkerImage( "ris/square.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var imageHover = new g.MarkerImage( "ris/square_over.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var marker = new g.Marker({ position: point, map: map, icon: imageNormal, draggable: true }); g.event.addListener(marker, "mouseover", function() { marker.setIcon(imageHover); }); g.event.addListener(marker, "mouseout", function() { marker.setIcon(imageNormal); }); g.event.addListener(marker, "drag", function() { for (var m = 0; m < markers.length; m++) { if (markers[m] == marker) { polyLine.getPath().setAt(m, marker.getPosition()); moveVMarker(m); break; } } m = null; }); g.event.addListener(marker, "click", function() { for (var m = 0; m < markers.length; m++) { if (markers[m] == marker) { marker.setMap(null); markers.splice(m, 1); polyLine.getPath().removeAt(m); removeVMarkers(m); break; } } m = null; }); return marker; }; var createVMarker = function(point) { var prevpoint = markers[markers.length-2].getPosition(); var imageNormal = new g.MarkerImage( "ris/square_transparent.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var imageHover = new g.MarkerImage( "ris/square_transparent_over.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var marker = new g.Marker({ position: new g.LatLng( point.lat() - (0.5 * (point.lat() - prevpoint.lat())), point.lng() - (0.5 * (point.lng() - prevpoint.lng())) ), map: map, icon: imageNormal, draggable: true }); g.event.addListener(marker, "mouseover", function() { marker.setIcon(imageHover); }); g.event.addListener(marker, "mouseout", function() { marker.setIcon(imageNormal); }); g.event.addListener(marker, "dragstart", function() { for (var m = 0; m < vmarkers.length; m++) { if (vmarkers[m] == marker) { var tmpPath = tmpPolyLine.getPath(); tmpPath.push(markers[m].getPosition()); tmpPath.push(vmarkers[m].getPosition()); tmpPath.push(markers[m+1].getPosition()); break; } } m = null; }); g.event.addListener(marker, "drag", function() { for (var m = 0; m < vmarkers.length; m++) { if (vmarkers[m] == marker) { tmpPolyLine.getPath().setAt(1, marker.getPosition()); break; } } m = null; }); g.event.addListener(marker, "dragend", function() { for (var m = 0; m < vmarkers.length; m++) { if (vmarkers[m] == marker) { var newpos = marker.getPosition(); var startMarkerPos = markers[m].getPosition(); var firstVPos = new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - startMarkerPos.lat())), newpos.lng() - (0.5 * (newpos.lng() - startMarkerPos.lng())) ); var endMarkerPos = markers[m+1].getPosition(); var secondVPos = new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - endMarkerPos.lat())), newpos.lng() - (0.5 * (newpos.lng() - endMarkerPos.lng())) ); var newVMarker = createVMarker(secondVPos); newVMarker.setPosition(secondVPos);//apply the correct position to the vmarker var newMarker = createMarker(newpos); markers.splice(m+1, 0, newMarker); polyLine.getPath().insertAt(m+1, newpos); marker.setPosition(firstVPos); vmarkers.splice(m+1, 0, newVMarker); tmpPolyLine.getPath().removeAt(2); tmpPolyLine.getPath().removeAt(1); tmpPolyLine.getPath().removeAt(0); newpos = null; startMarkerPos = null; firstVPos = null; endMarkerPos = null; secondVPos = null; newVMarker = null; newMarker = null; break; } } }); return marker; }; var moveVMarker = function(index) { var newpos = markers[index].getPosition(); if (index != 0) { var prevpos = markers[index-1].getPosition(); vmarkers[index-1].setPosition(new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - prevpos.lat())), newpos.lng() - (0.5 * (newpos.lng() - prevpos.lng())) )); prevpos = null; } if (index != markers.length - 1) { var nextpos = markers[index+1].getPosition(); vmarkers[index].setPosition(new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - nextpos.lat())), newpos.lng() - (0.5 * (newpos.lng() - nextpos.lng())) )); nextpos = null; } newpos = null; index = null; }; var removeVMarkers = function(index) { if (markers.length > 0) {//при клике на маркере он удаляется if (index != markers.length) { vmarkers[index].setMap(null); vmarkers.splice(index, 1); } else { vmarkers[index-1].setMap(null); vmarkers.splice(index-1, 1); } } if (index != 0 && index != markers.length) { var prevpos = markers[index-1].getPosition(); var newpos = markers[index].getPosition(); vmarkers[index-1].setPosition(new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - prevpos.lat())), newpos.lng() - (0.5 * (newpos.lng() - prevpos.lng())) )); prevpos = null; newpos = null; } index = null; }; window.onload = function() { initMap('mapcontainer'); initPolyline(); }; </script> <style type="text/css"> html, body { height: 100%; margin: 0; padding:0; } #mapcontainer {width: 800px; height: 600px; border: 1px solid black;} </style> </head> <body> <div id="mapcontainer"></div> </html> |
Поясню что в этом коде реализовано.
В начале задаются глобальные переменные и параметры для нашей карты.
Так же задается стиль для отображения полилинии.
В ходе кода отслеживаются различные события на карте.
При первом клике на карте ставиться маркер начала полилинии.
При следующих кликах рисуются участки полилинии и в их центре также добавляется маркер, но уже другого вида.
Кликнув по маркеру и удерживая левую кнопку мыши, мы можем изменять расположение узла полилинии и тем самым ее форму.
Удалить узел полилинии можно два раза кликнув по нему левой кнопкой мыши (удалять можно только маркеры на концах участков, но не в середине).
Теперь давайте изменим наш код так, чтобы можно было определить длину построенной полилинии.
Координаты всех узлов полилинии хранятся в массиве markers, нам необходимо определить расстояния между узлами и сложить их.
Это будет делать функция distance().
Ее исходный код:
function distance() { var dist = 0; if (markers.length > 0) { for (var im = 0; im < markers.length-1; im++) { var marpos1 = markers[im].getPosition(); var marpos2 = markers[im+1].getPosition(); var R = 6371000; // km (коэффициент для определения расстояния между двумя точками в километрах) var dLat = (marpos2.lat()-marpos1.lat()) * Math.PI / 180; var dLon = (marpos2.lng()-marpos1.lng()) * Math.PI / 180; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(marpos1.lat() * Math.PI / 180 ) * Math.cos(marpos2.lat() * Math.PI / 180 ) * Math.sin(dLon/2) * Math.sin(dLon/2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; dist = dist+d; } var distans = Math.round(dist/10)/100+" км"; document.getElementById('rast').value = distans; } } |
В ней мы в цикле перебираем все пары меток концов участков полилинии, определяем расстояние между ними и суммируем.
Полученное значение в километрах мы передаем поле input с id=»rast».
Окончательный код примера:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Google Maps api v3 - Рисуем полилинию и определяем ее длину</title> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript"> var map = null; var polyLine; var tmpPolyLine; var markers = []; var vmarkers = []; var g = google.maps; var initMap = function(mapHolder) { markers = []; vmarkers = []; var mapOptions = { zoom: 14, center: new g.LatLng(56.316667, 44), mapTypeId: g.MapTypeId.ROADMAP, draggableCursor: 'auto', draggingCursor: 'move', disableDoubleClickZoom: true }; map = new g.Map(document.getElementById(mapHolder), mapOptions); g.event.addListener(map, "click", mapLeftClick); mapHolder = null; mapOptions = null; }; var initPolyline = function() { var polyOptions = { strokeColor: "#ff0061", strokeOpacity: 0.8, strokeWeight: 4 }; var tmpPolyOptions = { strokeColor: "#ff0061", strokeOpacity: 0.4, strokeWeight: 4 }; polyLine = new g.Polyline(polyOptions); polyLine.setMap(map); tmpPolyLine = new g.Polyline(tmpPolyOptions); tmpPolyLine.setMap(map); }; var mapLeftClick = function(event) { if (event.latLng) { var marker = createMarker(event.latLng); markers.push(marker); if (markers.length != 1) { var vmarker = createVMarker(event.latLng); vmarkers.push(vmarker); vmarker = null; } var path = polyLine.getPath(); path.push(event.latLng); marker = null; } event = null; }; var createMarker = function(point) { var imageNormal = new g.MarkerImage( "ris/square.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var imageHover = new g.MarkerImage( "ris/square_over.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var marker = new g.Marker({ position: point, map: map, icon: imageNormal, draggable: true }); g.event.addListener(marker, "mouseover", function() { marker.setIcon(imageHover); }); g.event.addListener(marker, "mouseout", function() { marker.setIcon(imageNormal); }); g.event.addListener(marker, "drag", function() { for (var m = 0; m < markers.length; m++) { if (markers[m] == marker) { polyLine.getPath().setAt(m, marker.getPosition()); moveVMarker(m); break; } } m = null; }); g.event.addListener(marker, "click", function() { for (var m = 0; m < markers.length; m++) { if (markers[m] == marker) { marker.setMap(null); markers.splice(m, 1); polyLine.getPath().removeAt(m); removeVMarkers(m); break; } } m = null; }); return marker; }; var createVMarker = function(point) { var prevpoint = markers[markers.length-2].getPosition(); var imageNormal = new g.MarkerImage( "ris/square_transparent.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var imageHover = new g.MarkerImage( "ris/square_transparent_over.png", new g.Size(11, 11), new g.Point(0, 0), new g.Point(6, 6) ); var marker = new g.Marker({ position: new g.LatLng( point.lat() - (0.5 * (point.lat() - prevpoint.lat())), point.lng() - (0.5 * (point.lng() - prevpoint.lng())) ), map: map, icon: imageNormal, draggable: true }); g.event.addListener(marker, "mouseover", function() { marker.setIcon(imageHover); }); g.event.addListener(marker, "mouseout", function() { marker.setIcon(imageNormal); }); g.event.addListener(marker, "dragstart", function() { for (var m = 0; m < vmarkers.length; m++) { if (vmarkers[m] == marker) { var tmpPath = tmpPolyLine.getPath(); tmpPath.push(markers[m].getPosition()); tmpPath.push(vmarkers[m].getPosition()); tmpPath.push(markers[m+1].getPosition()); break; } } m = null; }); g.event.addListener(marker, "drag", function() { for (var m = 0; m < vmarkers.length; m++) { if (vmarkers[m] == marker) { tmpPolyLine.getPath().setAt(1, marker.getPosition()); break; } } m = null; }); g.event.addListener(marker, "dragend", function() { for (var m = 0; m < vmarkers.length; m++) { if (vmarkers[m] == marker) { var newpos = marker.getPosition(); var startMarkerPos = markers[m].getPosition(); var firstVPos = new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - startMarkerPos.lat())), newpos.lng() - (0.5 * (newpos.lng() - startMarkerPos.lng())) ); var endMarkerPos = markers[m+1].getPosition(); var secondVPos = new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - endMarkerPos.lat())), newpos.lng() - (0.5 * (newpos.lng() - endMarkerPos.lng())) ); var newVMarker = createVMarker(secondVPos); newVMarker.setPosition(secondVPos);//apply the correct position to the vmarker var newMarker = createMarker(newpos); markers.splice(m+1, 0, newMarker); polyLine.getPath().insertAt(m+1, newpos); marker.setPosition(firstVPos); vmarkers.splice(m+1, 0, newVMarker); tmpPolyLine.getPath().removeAt(2); tmpPolyLine.getPath().removeAt(1); tmpPolyLine.getPath().removeAt(0); newpos = null; startMarkerPos = null; firstVPos = null; endMarkerPos = null; secondVPos = null; newVMarker = null; newMarker = null; break; } } }); return marker; }; var moveVMarker = function(index) { var newpos = markers[index].getPosition(); if (index != 0) { var prevpos = markers[index-1].getPosition(); vmarkers[index-1].setPosition(new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - prevpos.lat())), newpos.lng() - (0.5 * (newpos.lng() - prevpos.lng())) )); prevpos = null; } if (index != markers.length - 1) { var nextpos = markers[index+1].getPosition(); vmarkers[index].setPosition(new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - nextpos.lat())), newpos.lng() - (0.5 * (newpos.lng() - nextpos.lng())) )); nextpos = null; } newpos = null; index = null; }; var removeVMarkers = function(index) { if (markers.length > 0) {//при клике на маркере он удаляется if (index != markers.length) { vmarkers[index].setMap(null); vmarkers.splice(index, 1); } else { vmarkers[index-1].setMap(null); vmarkers.splice(index-1, 1); } } if (index != 0 && index != markers.length) { var prevpos = markers[index-1].getPosition(); var newpos = markers[index].getPosition(); vmarkers[index-1].setPosition(new g.LatLng( newpos.lat() - (0.5 * (newpos.lat() - prevpos.lat())), newpos.lng() - (0.5 * (newpos.lng() - prevpos.lng())) )); prevpos = null; newpos = null; } index = null; }; window.onload = function() { initMap('mapcontainer'); initPolyline(); }; //Функция для определения длины полилинии function distance() { var dist = 0; if (markers.length > 0) { for (var im = 0; im < markers.length-1; im++) { var marpos1 = markers[im].getPosition(); var marpos2 = markers[im+1].getPosition(); var R = 6371000; // km (коэффициент для определения расстояния между двумя точками в километрах) var dLat = (marpos2.lat()-marpos1.lat()) * Math.PI / 180; var dLon = (marpos2.lng()-marpos1.lng()) * Math.PI / 180; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(marpos1.lat() * Math.PI / 180 ) * Math.cos(marpos2.lat() * Math.PI / 180 ) * Math.sin(dLon/2) * Math.sin(dLon/2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; dist = dist+d; } var distans = Math.round(dist/10)/100+" км"; document.getElementById('rast').value = distans; } } </script> <style type="text/css"> html, body { height: 100%; margin: 0; padding:0; } #mapcontainer {width: 800px; height: 600px; border: 1px solid black;} #distanse { margin-top: 15px;} #rast {width: 50px;} </style> </head> <body> <div id="mapcontainer"></div> <div id="distanse"><input type="button" onclick="distance();" value="Определить расстояние"/></div> <p>Длина полилиниии равна: <input id="rast" type="text"></p> </body> </html> |
Посмотреть работу примера в действии
Мы рисуем полилинию, последовательно задавая ее участки, для определения длины нажимаем на кнопку «Определить расстояние» в низу карты и в поле «Длина полилиниии равна:» появляется значение расстояния в километрах.
Неплохой пример, но по моему сильно наворочен…. Можно ли сделать пример с прямой (что-то типа измерения расстояния с одним участком, и выводом информации например в tooltip)? Он по моему будет проще в понимании…
Есть статья с примером, правда на английском. В ней как раз делается пример с измерением расстояния между двумя точками.
Здравствуйте.
Подскажите пожалуйста, каким образом можно добавить на Polylines «стрелочки» направления?
На карту загрузил KML-маршрут, но нужны еще указатели.
Спасибо.
Admin, ввиду актуальности и по личной просьбе прошу написать статью похожую на эту, но для другого компонента : «Заменяем карты Google Maps на Яндекс.Карты в компоненте EZ Realty — Realty Map для Joomla 1.5»
Хотелось бы, чтобы этот пример был дополнен кнопкой и функцией по сбросу и удалению всех точек перед созданием новой полилинии без перезагрузки всей карты.