根据路径方向更改谷歌地图标记方向
Posted
技术标签:
【中文标题】根据路径方向更改谷歌地图标记方向【英文标题】:Change Google map marker orientation according path direction 【发布时间】:2014-06-02 16:43:54 【问题描述】:我想知道是否可以根据地图上绘制的路径更改标记方向。这是一个例子:
如您所见,标记是一辆汽车(带有前保险杠和尾灯)。我想将汽车定位在路径前进的方向上(在此示例中,将汽车定位在右侧约 45 度)。
我正在使用DirectionsService
来绘制路径,并且我有一个随机点数。有时只有 1 点,有时 10 点。我在绘制路径之前添加了标记。这是我绘制路径的方式:
// Intialize the Path Array
var path = new google.maps.MVCArray();
// Intialise the Direction Service
var service = new google.maps.DirectionsService();
// Set the Path Stroke Color
var poly = new google.maps.Polyline( map: gmap, strokeColor: '#dd0000' ); // #4986E7
// Draw the path for this vehicle
for (var i = 0; i < pathPoints.length; i++)
if ((i + 1) < pathPoints.length)
var src = pathPoints[i];
var des = pathPoints[i + 1];
path.push(src);
poly.setPath(path);
service.route(
origin: src,
destination: des,
travelMode: google.maps.DirectionsTravelMode.DRIVING
, function (result, status)
if (status == google.maps.DirectionsStatus.OK)
for (var i = 0, len = result.routes[0].overview_path.length; i < len; i++)
path.push(result.routes[0].overview_path[i]);
);
有可能吗?
【问题讨论】:
【参考方案1】:一种选择是将您的图标转换为 SVG,然后使用 Symbol rotation
属性将其与道路对齐(您可以对 PNG 图像执行相同的操作,方法是制作大量旋转图标的副本度数或二度,或者通过制作允许您任意旋转PNG图标的自定义图标)
marker.setPosition(p);
var heading = google.maps.geometry.spherical.computeHeading(lastPosn,p);
icon.rotation = heading;
marker.setIcon(icon);
proof of concept fiddle
代码 sn-p:
var map;
var directionDisplay;
var directionsService;
var stepDisplay;
var markerArray = [];
var position;
var marker = null;
var polyline = null;
var poly2 = null;
var speed = 0.000005,
wait = 1;
var infowindow = null;
var timerHandle = null;
function createMarker(latlng, label, html)
var contentString = '<b>' + label + '</b><br>' + html;
var marker = new google.maps.Marker(
position: latlng,
map: map,
title: label,
zIndex: Math.round(latlng.lat() * -100000) << 5
);
marker.myname = label;
google.maps.event.addListener(marker, 'click', function()
infowindow.setContent(contentString);
infowindow.open(map, marker);
);
return marker;
function initialize()
infowindow = new google.maps.InfoWindow(
size: new google.maps.Size(150, 50)
);
// Instantiate a directions service.
directionsService = new google.maps.DirectionsService();
// Create a map and center it on Manhattan.
var myOptions =
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
;
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
address = 'new york';
geocoder = new google.maps.Geocoder();
geocoder.geocode(
'address': address
, function(results, status)
map.setCenter(results[0].geometry.location);
);
// Create a renderer for directions and bind it to the map.
var rendererOptions =
map: map
;
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
// Instantiate an info window to hold step text.
stepDisplay = new google.maps.InfoWindow();
polyline = new google.maps.Polyline(
path: [],
strokeColor: '#FF0000',
strokeWeight: 3
);
poly2 = new google.maps.Polyline(
path: [],
strokeColor: '#FF0000',
strokeWeight: 3
);
var steps = [];
function calcRoute()
if (timerHandle)
clearTimeout(timerHandle);
if (marker)
marker.setMap(null);
polyline.setMap(null);
poly2.setMap(null);
directionsDisplay.setMap(null);
polyline = new google.maps.Polyline(
path: [],
strokeColor: '#FF0000',
strokeWeight: 3
);
poly2 = new google.maps.Polyline(
path: [],
strokeColor: '#FF0000',
strokeWeight: 3
);
// Create a renderer for directions and bind it to the map.
var rendererOptions =
map: map
;
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var start = document.getElementById("start").value;
var end = document.getElementById("end").value;
var travelMode = google.maps.DirectionsTravelMode.DRIVING;
var request =
origin: start,
destination: end,
travelMode: travelMode
;
// Route the directions and pass the response to a
// function to create markers for each step.
directionsService.route(request, function(response, status)
if (status == google.maps.DirectionsStatus.OK)
directionsDisplay.setDirections(response);
var bounds = new google.maps.LatLngBounds();
var route = response.routes[0];
startLocation = new Object();
endLocation = new Object();
// For each route, display summary information.
var path = response.routes[0].overview_path;
var legs = response.routes[0].legs;
for (i = 0; i < legs.length; i++)
if (i === 0)
startLocation.latlng = legs[i].start_location;
startLocation.address = legs[i].start_address;
// marker = createMarker(legs[i].start_location, "start", legs[i].start_address, "green");
endLocation.latlng = legs[i].end_location;
endLocation.address = legs[i].end_address;
var steps = legs[i].steps;
for (j = 0; j < steps.length; j++)
var nextSegment = steps[j].path;
for (k = 0; k < nextSegment.length; k++)
polyline.getPath().push(nextSegment[k]);
bounds.extend(nextSegment[k]);
polyline.setMap(map);
map.fitBounds(bounds);
map.setZoom(18);
startAnimation();
);
var step = 50; // 5; // metres
var tick = 100; // milliseconds
var eol;
var k = 0;
var stepnum = 0;
var speed = "";
var lastVertex = 1;
//=============== animation functions ======================
function updatePoly(d)
// Spawn a new polyline every 20 vertices, because updating a 100-vertex poly is too slow
if (poly2.getPath().getLength() > 20)
poly2 = new google.maps.Polyline([polyline.getPath().getAt(lastVertex - 1)]);
// map.addOverlay(poly2)
if (polyline.GetIndexAtDistance(d) < lastVertex + 2)
if (poly2.getPath().getLength() > 1)
poly2.getPath().removeAt(poly2.getPath().getLength() - 1);
poly2.getPath().insertAt(poly2.getPath().getLength(), polyline.GetPointAtDistance(d));
else
poly2.getPath().insertAt(poly2.getPath().getLength(), endLocation.latlng);
function animate(d)
if (d > eol)
map.panTo(endLocation.latlng);
marker.setPosition(endLocation.latlng);
return;
var p = polyline.GetPointAtDistance(d);
map.panTo(p);
var lastPosn = marker.getPosition();
marker.setPosition(p);
var heading = google.maps.geometry.spherical.computeHeading(lastPosn, p);
icon.rotation = heading;
marker.setIcon(icon);
updatePoly(d);
timerHandle = setTimeout("animate(" + (d + step) + ")", tick);
function startAnimation()
eol = polyline.Distance();
map.setCenter(polyline.getPath().getAt(0));
marker = new google.maps.Marker(
position: polyline.getPath().getAt(0),
map: map,
icon: icon
);
poly2 = new google.maps.Polyline(
path: [polyline.getPath().getAt(0)],
strokeColor: "#0000FF",
strokeWeight: 10
);
// map.addOverlay(poly2);
setTimeout("animate(50)", 2000); // Allow time for the initial map display
google.maps.event.addDomListener(window, 'load', initialize);
//=============== ~animation funcitons =====================
var car = "M17.402,0H5.643C2.526,0,0,3.467,0,6.584v34.804c0,3.116,2.526,5.644,5.643,5.644h11.759c3.116,0,5.644-2.527,5.644-5.644 V6.584C23.044,3.467,20.518,0,17.402,0z M22.057,14.188v11.665l-2.729,0.351v-4.806L22.057,14.188z M20.625,10.773 c-1.016,3.9-2.219,8.51-2.219,8.51H4.638l-2.222-8.51C2.417,10.773,11.3,7.755,20.625,10.773z M3.748,21.713v4.492l-2.73-0.349 V14.502L3.748,21.713z M1.018,37.938V27.579l2.73,0.343v8.196L1.018,37.938z M2.575,40.882l2.218-3.336h13.771l2.219,3.336H2.575z M19.328,35.805v-7.872l2.729-0.355v10.048L19.328,35.805z";
var icon =
path: car,
scale: .7,
strokeColor: 'white',
strokeWeight: .10,
fillOpacity: 1,
fillColor: '#404040',
offset: '5%',
// rotation: parseInt(heading[i]),
anchor: new google.maps.Point(10, 25) // orig 10,50 back of car, 10,0 front of car, 10,25 center of car
;
/*********************************************************************\
* *
* epolys.js by Mike Williams *
* updated to API v3 by Larry Ross *
* *
* A Google Maps API Extension *
* *
* Adds various Methods to google.maps.Polygon and google.maps.Polyline *
* *
* .Contains(latlng) returns true is the poly contains the specified *
* GLatLng *
* *
* .Area() returns the approximate area of a poly that is *
* not self-intersecting *
* *
* .Distance() returns the length of the poly path *
* *
* .Bounds() returns a GLatLngBounds that bounds the poly *
* *
* .GetPointAtDistance() returns a GLatLng at the specified distance *
* along the path. *
* The distance is specified in metres *
* Reurns null if the path is shorter than that *
* *
* .GetPointsAtDistance() returns an array of GLatLngs at the *
* specified interval along the path. *
* The distance is specified in metres *
* *
* .GetIndexAtDistance() returns the vertex number at the specified *
* distance along the path. *
* The distance is specified in metres *
* Returns null if the path is shorter than that *
* *
* .Bearing(v1?,v2?) returns the bearing between two vertices *
* if v1 is null, returns bearing from first to last *
* if v2 is null, returns bearing from v1 to next *
* *
* *
***********************************************************************
* *
* This javascript is provided by Mike Williams *
* Blackpool Community Church Javascript Team *
* http://www.blackpoolchurch.org/ *
* http://econym.org.uk/gmap/ *
* *
* This work is licenced under a Creative Commons Licence *
* http://creativecommons.org/licenses/by/2.0/uk/ *
* *
***********************************************************************
* *
* Version 1.1 6-Jun-2007 *
* Version 1.2 1-Jul-2007 - fix: Bounds was omitting vertex zero *
* add: Bearing *
* Version 1.3 28-Nov-2008 add: GetPointsAtDistance() *
* Version 1.4 12-Jan-2009 fix: GetPointsAtDistance() *
* Version 3.0 11-Aug-2010 update to v3 *
* *
\*********************************************************************/
// === first support methods that don't (yet) exist in v3
google.maps.LatLng.prototype.distanceFrom = function(newLatLng)
var EarthRadiusMeters = 6378137.0; // meters
var lat1 = this.lat();
var lon1 = this.lng();
var lat2 = newLatLng.lat();
var lon2 = newLatLng.lng();
var dLat = (lat2 - lat1) * Math.PI / 180;
var dLon = (lon2 - lon1) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * 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 = EarthRadiusMeters * c;
return d;
google.maps.LatLng.prototype.latRadians = function()
return this.lat() * Math.PI / 180;
google.maps.LatLng.prototype.lngRadians = function()
return this.lng() * Math.PI / 180;
// === A method which returns the length of a path in metres ===
google.maps.Polygon.prototype.Distance = function()
var dist = 0;
for (var i = 1; i < this.getPath().getLength(); i++)
dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i - 1));
return dist;
// === A method which returns a GLatLng of a point a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
google.maps.Polygon.prototype.GetPointAtDistance = function(metres)
// some awkward special cases
if (metres == 0) return this.getPath().getAt(0);
if (metres < 0) return null;
if (this.getPath().getLength() < 2) return null;
var dist = 0;
var olddist = 0;
for (var i = 1;
(i < this.getPath().getLength() && dist < metres); i++)
olddist = dist;
dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i - 1));
if (dist < metres)
return null;
var p1 = this.getPath().getAt(i - 2);
var p2 = this.getPath().getAt(i - 1);
var m = (metres - olddist) / (dist - olddist);
return new google.maps.LatLng(p1.lat() + (p2.lat() - p1.lat()) * m, p1.lng() + (p2.lng() - p1.lng()) * m);
// === A method which returns an array of GLatLngs of points a given interval along the path ===
google.maps.Polygon.prototype.GetPointsAtDistance = function(metres)
var next = metres;
var points = [];
// some awkward special cases
if (metres <= 0) return points;
var dist = 0;
var olddist = 0;
for (var i = 1;
(i < this.getPath().getLength()); i++)
olddist = dist;
dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i - 1));
while (dist > next)
var p1 = this.getPath().getAt(i - 1);
var p2 = this.getPath().getAt(i);
var m = (next - olddist) / (dist - olddist);
points.push(new google.maps.LatLng(p1.lat() + (p2.lat() - p1.lat()) * m, p1.lng() + (p2.lng() - p1.lng()) * m));
next += metres;
return points;
// === A method which returns the Vertex number at a given distance along the path ===
// === Returns null if the path is shorter than the specified distance ===
google.maps.Polygon.prototype.GetIndexAtDistance = function(metres)
// some awkward special cases
if (metres == 0) return this.getPath().getAt(0);
if (metres < 0) return null;
var dist = 0;
var olddist = 0;
for (var i = 1;
(i < this.getPath().getLength() && dist < metres); i++)
olddist = dist;
dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i - 1));
if (dist < metres)
return null;
return i;
// === Copy all the above functions to GPolyline ===
google.maps.Polyline.prototype.Distance = google.maps.Polygon.prototype.Distance;
google.maps.Polyline.prototype.GetPointAtDistance = google.maps.Polygon.prototype.GetPointAtDistance;
google.maps.Polyline.prototype.GetPointsAtDistance = google.maps.Polygon.prototype.GetPointsAtDistance;
google.maps.Polyline.prototype.GetIndexAtDistance = google.maps.Polygon.prototype.GetIndexAtDistance;
html
height: 100%;
body
height: 100%;
margin: 0px;
font-family: Helvetica, Arial;
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="tools">start:
<input type="text" name="start" id="start" value="union square, NY" />end:
<input type="text" name="end" id="end" value="times square, NY" />
<input type="submit" onclick="calcRoute();" />
</div>
<div id="map_canvas" style="width:100%;height:90%;"></div>
【讨论】:
【参考方案2】:最简单的解决方案(用于谷歌地图):
var rotationAngle = google.maps.geometry.spherical.computeHeading(oldLatlng, currentlatlng);
$('img[src="path_to_marker_icon_image"]').css(
transform: "rotate(" + rotationAngle + "deg)"
);
【讨论】:
【参考方案3】:借助 'GMSMapView' Delegates 方法,您可以轻松使用它。
var lastMapBearing: CLLocationDirection?
var lastUserBearing: CLLocationDirection?
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition)
lastMapBearing = position.bearing
driverMarker?.rotation = (lastUserBearing ?? 0) - lastMapBearing!
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading)
lastUserBearing = newHeading.trueHeading
driverMarker?.rotation = lastUserBearing! - (lastMapBearing ?? 0)
确保您可以分配委托 itSelf。
【讨论】:
以上是关于根据路径方向更改谷歌地图标记方向的主要内容,如果未能解决你的问题,请参考以下文章