Возможно, вы захотите решить эту проблему, добавив дополнительные круги с интервалом x
с увеличением радиуса между каждой точкой пути. Это было бы очень легко реализовать и будет работать для любого направления циклона. Очевидно, что предложенное Матти решение для создания многоугольника путем соединения всех касательных было бы более точно, но вы можете рассмотреть это как возможную альтернативу. Основным недостатком является то, что могут потребоваться некоторые усилия, чтобы он выглядел красиво, и, очевидно, он будет использовать больше ресурсов на стороне клиента, чем если бы вы визуализировали один полигон.
Давайте начнем с воссоздания вашей карты:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps Cyclones</title>
<script src="http://maps.google.com/maps/api/js?sensor=false"
type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script type="text/javascript">
var i;
var mapOptions = {
mapTypeId: google.maps.MapTypeId.TERRAIN,
center: new google.maps.LatLng(28.50, -81.50),
zoom: 5
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
var pathPoints = [
new google.maps.LatLng(25.48, -71.26),
new google.maps.LatLng(25.38, -73.70),
new google.maps.LatLng(25.28, -77.00),
new google.maps.LatLng(25.24, -80.11),
new google.maps.LatLng(25.94, -82.71),
new google.maps.LatLng(27.70, -87.14)
];
pathPoints[0].radius = 80;
pathPoints[1].radius = 100;
pathPoints[2].radius = 200;
pathPoints[3].radius = 300;
pathPoints[4].radius = 350;
pathPoints[5].radius = 550;
new google.maps.Polyline({
path: pathPoints,
strokeColor: '#00FF00',
strokeOpacity: 1.0,
strokeWeight: 3,
map: map
});
for (i = 0; i < pathPoints.length; i++) {
new google.maps.Circle({
center: pathPoints[i],
radius: pathPoints[i].radius * 1000,
fillColor: '#FF0000',
fillOpacity: 0.2,
strokeOpacity: 0.5,
strokeWeight: 1,
map: map
});
}
</script>
</body>
</html>
http://img186.imageshack.us/img186/1197/mp1h.png
Я предполагаю, что вы уже пришли к этому моменту, и поэтому приведенный выше пример не требует пояснений. По сути, мы только что определили 6 точек вместе с 6 радиусами и отрендерили круги на карте вместе с зеленым путем.
Прежде чем мы продолжим, нам нужно определить несколько методов, чтобы иметь возможность вычислять расстояние и пеленг от одной точки к другой. Нам также понадобится метод, который будет возвращать точку назначения при задании пеленга и пройденного расстояния от исходной точки. К счастью, есть очень хорошая реализация этих методов на JavaScript от Криса Венесса по адресу Рассчитать расстояние. , азимут и многое другое между точками широты/долготы. Следующие методы были адаптированы для работы с google.maps.LatLng
Google:
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
}
google.maps.LatLng.prototype.destinationPoint = function(brng, dist) {
dist = dist / 6371;
brng = brng.toRad();
var lat1 = this.lat().toRad(), lon1 = this.lng().toRad();
var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) +
Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) );
var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1),
Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2));
if (isNaN(lat2) || isNaN(lon2)) return null;
return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg());
}
google.maps.LatLng.prototype.bearingTo = function(point) {
var lat1 = this.lat().toRad(), lat2 = point.lat().toRad();
var dLon = (point.lng()-this.lng()).toRad();
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x);
return ((brng.toDeg()+360) % 360);
}
google.maps.LatLng.prototype.distanceTo = function(point) {
var lat1 = this.lat().toRad(), lon1 = this.lng().toRad();
var lat2 = point.lat().toRad(), lon2 = point.lng().toRad();
var dLat = lat2 - lat1;
var dLon = lon2 - lon1;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon/2) * Math.sin(dLon/2);
return 6371 * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)));
}
Затем нам нужно будет добавить еще один цикл, который рендерит промежуточные круги внутри цикла for
, который мы использовали ранее для рендеринга исходных кругов. Вот как это можно реализовать:
var distanceStep = 50; // Render an intermediate circle every 50km.
for (i = 0; i < pathPoints.length; i++) {
new google.maps.Circle({
center: pathPoints[i],
radius: pathPoints[i].radius * 1000,
fillColor: '#FF0000',
fillOpacity: 0.2,
strokeOpacity: 0.5,
strokeWeight: 1,
map: map
});
if (i < (pathPoints.length - 1)) {
distanceToNextPoint = pathPoints[i].distanceTo(pathPoints[i + 1]);
bearingToNextPoint = pathPoints[i].bearingTo(pathPoints[i + 1]);
radius = pathPoints[i].radius;
radiusIncrement = (pathPoints[i + 1].radius - radius) /
(distanceToNextPoint / distanceStep);
for (j = distanceStep;
j < distanceToNextPoint;
j += distanceStep, radius += radiusIncrement) {
new google.maps.Circle({
center: pathPoints[i].destinationPoint(bearingToNextPoint, j),
radius: radius * 1000,
fillColor: '#FF0000',
fillOpacity: 0.2,
strokeWeight: 0,
map: map
});
}
}
}
Вот что мы бы получили:
![Циклоны на Google Картах – рис. 2](https://i.stack.imgur.com/93i6h.png)
А вот как это выглядело бы без черной обводки вокруг исходных кругов:
http://img181.imageshack.us/img181/2908/mp3t.png
Как вы могли заметить, основной задачей будет отрисовка кругов с постоянной непрозрачностью, даже если они накладываются друг на друга. Есть несколько вариантов достижения этого, но это может быть темой другого вопроса.
В любом случае ниже приведена полная реализация этого примера:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps Cyclones</title>
<script src="http://maps.google.com/maps/api/js?sensor=false"
type="text/javascript"></script>
</head>
<body>
<div id="map" style="width: 600px; height: 400px"></div>
<script type="text/javascript">
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
}
google.maps.LatLng.prototype.destinationPoint = function(brng, dist) {
dist = dist / 6371;
brng = brng.toRad();
var lat1 = this.lat().toRad(), lon1 = this.lng().toRad();
var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) +
Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) );
var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1),
Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2));
if (isNaN(lat2) || isNaN(lon2)) return null;
return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg());
}
google.maps.LatLng.prototype.bearingTo = function(point) {
var lat1 = this.lat().toRad(), lat2 = point.lat().toRad();
var dLon = (point.lng()-this.lng()).toRad();
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x);
return ((brng.toDeg()+360) % 360);
}
google.maps.LatLng.prototype.distanceTo = function(point) {
var lat1 = this.lat().toRad(), lon1 = this.lng().toRad();
var lat2 = point.lat().toRad(), lon2 = point.lng().toRad();
var dLat = lat2 - lat1;
var dLon = lon2 - lon1;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon/2) * Math.sin(dLon/2);
return 6371 * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)));
}
var i;
var j;
var distanceToNextPoint;
var bearingToNextPoint;
var radius;
var radiusIncrement;
var distanceStep = 50; // Render an intermediate circle every 50km.
var mapOptions = {
mapTypeId: google.maps.MapTypeId.TERRAIN,
center: new google.maps.LatLng(28.50, -81.50),
zoom: 5
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var pathPoints = [
new google.maps.LatLng(25.48, -71.26),
new google.maps.LatLng(25.38, -73.70),
new google.maps.LatLng(25.28, -77.00),
new google.maps.LatLng(25.24, -80.11),
new google.maps.LatLng(25.94, -82.71),
new google.maps.LatLng(27.70, -87.14)
];
pathPoints[0].radius = 80;
pathPoints[1].radius = 100;
pathPoints[2].radius = 200;
pathPoints[3].radius = 300;
pathPoints[4].radius = 350;
pathPoints[5].radius = 550;
new google.maps.Polyline({
path: pathPoints,
strokeColor: '#00FF00',
strokeOpacity: 1.0,
strokeWeight: 3,
map: map
});
for (i = 0; i < pathPoints.length; i++) {
new google.maps.Circle({
center: pathPoints[i],
radius: pathPoints[i].radius * 1000,
fillColor: '#FF0000',
fillOpacity: 0.2,
strokeOpacity: 0.5,
strokeWeight: 0,
map: map
});
if (i < (pathPoints.length - 1)) {
distanceToNextPoint = pathPoints[i].distanceTo(pathPoints[i + 1]);
bearingToNextPoint = pathPoints[i].bearingTo(pathPoints[i + 1]);
radius = pathPoints[i].radius;
radiusIncrement = (pathPoints[i + 1].radius - radius) /
(distanceToNextPoint / distanceStep);
for (j = distanceStep;
j < distanceToNextPoint;
j += distanceStep, radius += radiusIncrement) {
new google.maps.Circle({
center: pathPoints[i].destinationPoint(bearingToNextPoint, j),
radius: radius * 1000,
fillColor: '#FF0000',
fillOpacity: 0.2,
strokeWeight: 0,
map: map
});
}
}
}
</script>
</body>
</html>
person
Daniel Vassallo
schedule
11.04.2010