На страницах своего блога я уже рассказывал о том, как нарисовать полилинию в заметке: «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»
Хотелось бы, чтобы этот пример был дополнен кнопкой и функцией по сбросу и удалению всех точек перед созданием новой полилинии без перезагрузки всей карты.