I have an application which has a rectangle on a google map at the certain point, I have to rotate the rectangle along the vertices as well as it should be editable, but the width of the rectangle should be always greater than its height.
I have seen several other solutions on stack overflow for rectangle rotation, there it is suggested to user polyline or polygon, but as I need angle difference of 90 between each side so I can't shift to other shapes.
Here is my code:
var rectangle;
var map;
var markers = [];
var north_east_degree=30;
var south_west_degree=210;
var center = new google.maps.LatLng(18.5021, 73.8774); // Circle center
map = new google.maps.Map(document.getElementById('map'), {
center: center,
mapTypeId: google.maps.MapTypeId.SATELLITE,
zoom: 90,
heading: 90,
tilt: 45
});
var north_point=center.destinationPoint(north_degree, 0.08);
var east_point=center.destinationPoint(east_degree, 0.08);
var south_point=center.destinationPoint(south_degree, 0.08);
var west_point=center.destinationPoint(west_degree, 0.08);
var bounds = {
north: north_point.lat(),
east: east_point.lng(),
south: south_point.lat(),
west: west_point.lng()
};
rectangle = new google.maps.Rectangle({
bounds: bounds,
editable: true,
draggable: true,
strokeColor: "#000000",
strokeOpacity: 0.8,
fillOpacity: 0.5,
zIndex: -1
});
rectangle.setMap(map);
as there is no rotate event available for rectangle so for now I have used on click event:see image here
rectangle.addListener('click', rotate_rect);
initially, i get this result if i maintain angles as given above, at second iteration, every angle increases by 30 it then rectangle looks quite slanted the at third click rectangle changes to be as a single line as angle difference between each side is the very small I guess.
function rotate_rect(event)
{
var nor_east = rectangle.getBounds().getNorthEast();
var south_west = rectangle.getBounds().getSouthWest();
x1 = nor_east.lat();
x2 = south_west.lat();
y1 = nor_east.lng();
y2 = south_west.lng();
var cx= x1 + ((x2 - x1) / 2);
var cy = y1 + ((y2 - y1) / 2);
cx = cx.toPrecision(6);
cy= cy.toPrecision(6)
var center_rec = new google.maps.LatLng(cx,cy);
north_east_degree=north_east_degree+30;
south_west_degree=south_west_degree+30;
if(north_east_degree==180){
north_east_degree=30;
south_west_degree=210;
}
var newPointNorthEast=center_rec.destinationPoint(north_east_degree, calcCrow(center_rec.lat(),center_rec.lng(),nor_east.lat(),nor_east.lng()).toFixed(2));
var newPointSouthWest=center_rec.destinationPoint(south_west_degree, calcCrow(center_rec.lat(),center_rec.lng(),south_west.lat(),south_west.lng()).toFixed(2));
var bounds = {
north: newPointNorthEast.lat(),
south: newPointSouthWest.lat(),
east: newPointNorthEast.lng(),
west: newPointSouthWest.lng()
};
rectangle.setBounds(bounds);
}//rotate_rect
You cant properly rotate rectangle in Google Maps since google.maps.Rectangle object does not support to set/get coordinates of the four vertices (with setBounds function it is supported to set northeast and southwest coordinates only)
Instead you could consider the following solution:
create a polygon from a rectangle object and display it on the map
rotate a polygon
Working example
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 13,
center: { lat: 33.678, lng: -116.243 },
mapTypeId: google.maps.MapTypeId.TERRAIN
});
var rectangle = new google.maps.Rectangle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: map,
bounds: {
north: 33.685,
south: 33.671,
east: -116.224,
west: -116.251
}
});
var rectPoly = createPolygonFromRectangle(rectangle); //create a polygom from a rectangle
rectPoly.addListener('click', function(e) {
rotatePolygon(rectPoly,10);
});
document.getElementById('btnRotate').onclick = function() {
window.setInterval(function() {
rotatePolygon(rectPoly, 10);
}, 500);
};
}
function createPolygonFromRectangle(rectangle) {
var map = rectangle.getMap();
var coords = [
{ lat: rectangle.getBounds().getNorthEast().lat(), lng: rectangle.getBounds().getNorthEast().lng() },
{ lat: rectangle.getBounds().getNorthEast().lat(), lng: rectangle.getBounds().getSouthWest().lng() },
{ lat: rectangle.getBounds().getSouthWest().lat(), lng: rectangle.getBounds().getSouthWest().lng() },
{ lat: rectangle.getBounds().getSouthWest().lat(), lng: rectangle.getBounds().getNorthEast().lng() }
];
// Construct the polygon.
var rectPoly = new google.maps.Polygon({
path: coords
});
var properties = ["strokeColor","strokeOpacity","strokeWeight","fillOpacity","fillColor"];
//inherit rectangle properties
var options = {};
properties.forEach(function(property) {
if (rectangle.hasOwnProperty(property)) {
options[property] = rectangle[property];
}
});
rectPoly.setOptions(options);
rectangle.setMap(null);
rectPoly.setMap(map);
return rectPoly;
}
function rotatePolygon(polygon,angle) {
var map = polygon.getMap();
var prj = map.getProjection();
var origin = prj.fromLatLngToPoint(polygon.getPath().getAt(0)); //rotate around first point
var coords = polygon.getPath().getArray().map(function(latLng){
var point = prj.fromLatLngToPoint(latLng);
var rotatedLatLng = prj.fromPointToLatLng(rotatePoint(point,origin,angle));
return {lat: rotatedLatLng.lat(), lng: rotatedLatLng.lng()};
});
polygon.setPath(coords);
}
function rotatePoint(point, origin, angle) {
var angleRad = angle * Math.PI / 180.0;
return {
x: Math.cos(angleRad) * (point.x - origin.x) - Math.sin(angleRad) * (point.y - origin.y) + origin.x,
y: Math.sin(angleRad) * (point.x - origin.x) + Math.cos(angleRad) * (point.y - origin.y) + origin.y
};
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
#floating-panel {
position: absolute;
top: 10px;
left: 25%;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
text-align: center;
font-family: 'Roboto','sans-serif';
line-height: 30px;
padding-left: 10px;
}
<div id="floating-panel"><input type="button" id="btnRotate" value="Auto Rotate"></div>
<div id="map"></div>
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>
JSFiddle
Related
I can't manage with drawing rectangle between two cities. I've searched everywhere on the Internet and can't find out why my polygon is drawn on Google Maps as parallelogram even so on 2d plane (not earth plane) this rectangle is drawn properly.
What I noticed is that the curvature sides of parallelogram depends on where cities are placed on map. If two cities are placed vis-a-vis then my function draw rectangle successfully. But If they are placed diagonally then my function draw parallelogram. The result should be rotated rectangle with height as distance between two cities and width as kilometers that user chooses.
Here is my function that should draw rectangle between two cities. As args we need to give position of first city ($x1 is lat, $y1 is lng), position of second city and as third arg a radius in kilometers ($l1) from center point of rectangle.
function getPolygon($x1,$y1,$x2,$y2,$l1){
var $l1 = $l1*0.010526; //approx kilometers
var $distanceV = [($x2 - $x1), ($y2 - $y1)];
var $vlen = Math.sqrt(Math.pow($distanceV[0], 2) +
Math.pow($distanceV[1],2));
if($vlen == 0)
return [[0,0],[0,0],[0,0],[0,0]];
var $l2 = $vlen;
var $normalized = [($distanceV[0] / $vlen), ($distanceV[1] / $vlen)];
var $rotated = [(-1 * $normalized[1]), ($normalized[0])];
var $p1 = [($x1 - $rotated[0] * $l1 / 2), ($y1 - $rotated[1] * $l1 / 2)];
var $p2 = [($p1[0] + $rotated[0] * $l1), ($p1[1] + $rotated[1] * $l1)];
var $p3 = [($p1[0] + $normalized[0] * $l2), ($p1[1] + $normalized[1] * $l2)];
var $p4 = [($p3[0] + $rotated[0] * $l1), ($p3[1] + $rotated[1] * $l1)];
var $points = [
{lat: $p1[0], lng: $p1[1]},
{lat: $p3[0], lng: $p3[1]},
{lat: $p4[0], lng: $p4[1]},
{lat: $p2[0], lng: $p2[1]},
{lat: $p1[0], lng: $p1[1]}
];
return $points;
}
Then I draw it on Google Maps like this:
new google.maps.Polygon({
paths: getPolygon(first_city_lat, first_city_lng, second_city_lat, second_city_lng, 30),
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.05
});
Here is an example should be rectangle between Birmingham and Oxford: JSFiddle
Additionally I'm sure that kilometers converter is not exact and it again depends how cities are placed.
The earth is curved. To get a polygon that appears rectangular on the curved sphere, you need to use calculations that take the projection of the map into account.
The Google Maps Javascript API v3 has a spherical geometry library that can be used to compute the desired points.
function getPolygon($x1,$y1,$x2,$y2,$l1){
var points = [];
var city1 = new google.maps.LatLng($x1, $y1);
var city2 = new google.maps.LatLng($x2, $y2);
var heading = google.maps.geometry.spherical.computeHeading(city1, city2);
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1/2*1000, heading+90));
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1/2*1000, heading-90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1/2*1000, heading-90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1/2*1000, heading+90));
points.push(points[0]);
return points;
}
proof of concept fiddle
code snippet:
var map;
google.maps.event.addDomListener(window, "load", function() {
var map = new google.maps.Map(document.getElementById("map_div"), {
center: new google.maps.LatLng(52.489471, -1.898575),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var trace = new google.maps.Polygon({
paths: getPolygon(52.489471, -1.898575, 51.752022, -1.257677, 30),
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.05,
map: map
});
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < trace.getPath().getLength(); i++) {
bounds.extend(trace.getPath().getAt(i));
}
map.fitBounds(bounds);
function getPolygon($x1, $y1, $x2, $y2, $l1) {
var points = [];
var city1 = new google.maps.LatLng($x1, $y1);
var city2 = new google.maps.LatLng($x2, $y2);
var heading = google.maps.geometry.spherical.computeHeading(city1, city2);
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1 / 2 * 1000, heading + 90));
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1 / 2 * 1000, heading - 90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1 / 2 * 1000, heading - 90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1 / 2 * 1000, heading + 90));
points.push(points[0]);
return points;
}
});
html,
body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
#map_div {
height: 95%;
}
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map_div"></div>
I am trying to make a figure here. But the browser is giving the following error. I am trying to use the google maps api with conjunction to geometry library. But not able to run it.
Error:curve.html:79 Uncaught TypeError: Cannot read property 'computeOffset' of undefined
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 50%;
}
</style>
</head>
<body>
<div id="map"></div>
<div>
</br>
<input type="number" name="" id="Radius" placeholder="FrontFace" style="margin:30px" onchange="initMap()">
</br>
<input type="number" name="" id="Backface" placeholder="BackFace" style="margin:30px" onchange="initMap()">
</div>
<script>
var map;
function initMap() {
debugger;
var radius=parseInt(document.getElementById("Radius").value);
var radius2=parseInt(document.getElementById("Backface").value);
var cen= {lat: -34.397, lng: 150.644}
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
google.maps.event.addListener(map,"click",function(event){
var lat=event.latLng.lat();
var lng=event.latLng.lng();
cen={lat:lat,lng:lng};
});
map.addListener('click', function(e) {
debugger;
placeMarkerAndPanTo(e.latLng, map);
// drawCircle(map,cen,radius);
drawBlastClearance(map,cen,radius,radius2)
});
}
function convertLat(r,angle,cen)
{
debugger;
sin=Math.sin(Math.PI*(angle/180))
dy=((r*sin)/ (110540) );
return cen.lat+dy;
}
function convertLng(r,angle,cen)
{
debugger;
cos=Math.cos(Math.PI*(angle/180))
dx=((r*cos)/ (11320*Math.cos(Math.PI*(angle/180))) );
return cen.lng+dx;
}
function drawBlastClearance(map,cen,r1,r2){
debugger;
LatLng=google.maps.LatLng
spherical=google.maps.spherical;
//CODE TO GENERATE BLAST CLEARANCE ZONE POINTS
Apos=spherical.computeOffset(cen, 158, -45);
Bpos= spherical.computeOffset(cen, 156, 45);
CPos=spherical.computeOffset(cen, 80, 237);
DPos=spherical.computeOffset(cen, 80, 113);
///LINE 1
var pos1 = new LatLng(Apos.lat, Apos.lng);
var pos2 = new LatLng(Bpos.lat, Bpos.lng);
var pos3 = new LatLng(CPos.lat, CPos.lng);
var pos4 = new LatLng(DPos.lat, DPos.lng);
var marker = new google.maps.Marker({
position: Apos,
map: map,
label:'A',
title: 'Hello World!'
});
var marker1 = new google.maps.Marker({
position: Bpos,
map: map,
label:'B',
dragable:true,
});
var marker2 = new google.maps.Marker({
position: CPos,
label:'C',
map: map,
});
var marker3 = new google.maps.Marker({
position: DPos,
map: map,
label:'D',
});
var line = new google.maps.Polyline({
path: [
DPos,Bpos
],
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});
var line1 = new google.maps.Polyline({
path: [
CPos,Apos
],
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});
function updateCurveMarker() {
Point=google.maps.Point;
curvature=-.45;
var curveMarker;
var pos1 = marker.getPosition(), // latlng
pos2 = marker1.getPosition(),
projection = map.getProjection(),
p1 = projection.fromLatLngToPoint(pos1), // xy
p2 = projection.fromLatLngToPoint(pos2);
// Calculate the arc.
// To simplify the math, these points
// are all relative to p1:
var e = new Point(p2.x - p1.x, p2.y - p1.y), // endpoint (p2 relative to p1)
m = new Point(e.x / 2, e.y / 2), // midpoint
o = new Point(e.y, -e.x), // orthogonal
c = new Point( // curve control point
m.x + curvature * o.x,
m.y + curvature * o.y);
var pathDef = 'M 0,0 ' +
'q ' + c.x + ',' + c.y + ' ' + e.x + ',' + e.y;
var zoom = map.getZoom(),
scale = 1 / (Math.pow(2, -zoom));
var symbol = {
path: pathDef,
scale: scale,
strokeWeight: 2,
fillColor: '#FF0000'
};
if (!curveMarker) {
curveMarker = new google.maps.Marker({
position: pos1,
clickable: false,
icon: symbol,
zIndex: 0, // behind the other markers
map: map
});
} else {
curveMarker.setOptions({
position: pos1,
icon: symbol,
});
}
}
google.maps.event.addListener(map, 'projection_changed', updateCurveMarker);
google.maps.event.addListener(map, 'zoom_changed', updateCurveMarker);
google.maps.event.addListener(marker1, 'position_changed', updateCurveMarker);
google.maps.event.addListener(marker2, 'position_changed', updateCurveMarker);
function updateCurveMarker1() {
Point=google.maps.Point;
curvature=.45;
var curveMarker;
var pos1 = marker2.getPosition(), // latlng
pos2 = marker3.getPosition(),
projection = map.getProjection(),
p1 = projection.fromLatLngToPoint(pos1), // xy
p2 = projection.fromLatLngToPoint(pos2);
// Calculate the arc.
// To simplify the math, these points
// are all relative to p1:
var e = new Point(p2.x - p1.x, p2.y - p1.y), // endpoint (p2 relative to p1)
m = new Point(e.x / 2, e.y / 2), // midpoint
o = new Point(e.y, -e.x), // orthogonal
c = new Point( // curve control point
m.x + curvature * o.x,
m.y + curvature * o.y);
var pathDef = 'M 0,0 ' +
'q ' + c.x + ',' + c.y + ' ' + e.x + ',' + e.y;
var zoom = map.getZoom(),
scale = 1 / (Math.pow(2, -zoom));
var symbol = {
path: pathDef,
scale: scale,
strokeWeight: 2,
fillColor: '#FF0000'
};
if (!curveMarker) {
curveMarker = new google.maps.Marker({
position: pos1,
clickable: false,
icon: symbol,
zIndex: 0, // behind the other markers
map: map
});
} else {
curveMarker.setOptions({
position: pos1,
icon: symbol,
});
}
}
google.maps.event.addListener(map, 'projection_changed', updateCurveMarker1);
google.maps.event.addListener(map, 'zoom_changed', updateCurveMarker1);
google.maps.event.addListener(marker1, 'position_changed', updateCurveMarker1);
google.maps.event.addListener(marker2, 'position_changed', updateCurveMarker1);
}
var markersArray=[];
var circleArray=[];
function placeMarkerAndPanTo(latLng, map) {
while(markersArray.length) { markersArray.pop().setMap(null); }
var marker = new google.maps.Marker({
position: latLng,
map: map
});
markersArray.push(marker) ;
}
function drawCircle(map,cen,radii)
{
while(circleArray.length){circleArray.pop().setMap(null);}
var cityCircle = new google.maps.Circle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
map: map,
center:cen,
radius: radii
});
circleArray.push(cityCircle);
}
</script>
<!-- <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCVhit3Aj--xP28zBUyThLQ7bAHOt72B1c&cal async defer></script> -->
<!-- lback=initMap libraries=geometry"&sensor=false
-->
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCVhit3Aj--xP28zBUyThLQ7bAHOt72B1c&libraries=geometry,places">
</script>
</body>
</html>
You have a typo in your code. This is incorrect:
spherical=google.maps.spherical;
It should be
spherical=google.maps.geometry.spherical;
fiddle
I'm currently building a webpage that shows customer reviews on a Google Maps. There is one issue and that is that there are already over 1200 reviews that needs to be shown on the map but those reviews only have a city attached to them so when I load all of those reviews in the map than a lot of them will share the exact same coordinates.
I am looking for a way to scatter identical markers within a certain radius. So lets say pick every single marker on the map and move them al 1% in a random direction to create distance between them.
I don't really mind how this will be done, be it by javascript or PHP, duriong the placement of the markers or beforehand with an algorithm that sets new coordinates one.
May be something like this
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 5,
center: { lat: -25.363, lng: 131.044 }
});
var originalMarker = new google.maps.Marker({
position: { lat: -25.363, lng: 131.044 },
map: map,
title: ''
});
google.maps.event.addListenerOnce(map, 'idle', function () {
var circle = new google.maps.Circle({
map: map,
radius: 1000 * 1000, //in metres
fillColor: '#AA0000'
});
circle.bindTo('center', originalMarker, 'position');
drawMarkersInCircle(circle, 200);
});
}
function drawMarkersInCircle(circle, count) {
var map = circle.getMap();
var proj = map.getProjection();
var centerPoint = proj.fromLatLngToPoint(circle.getCenter());
var radius = Math.abs(proj.fromLatLngToPoint(circle.getBounds().getNorthEast()).x - centerPoint.x);
for (var i = 0; i < count; i++) {
var point = createRandomPointInCircle(centerPoint, radius);
var pos = proj.fromPointToLatLng(point);
//console.log(point);
var marker = new google.maps.Marker({
position: pos,
map: map,
title: ''
});
}
}
function createRandomPointInCircle(centerPoint, radius) {
var angle = Math.random() * Math.PI * 2;
var x = (Math.cos(angle) * getRandomArbitrary(0, radius)) + centerPoint.x;
var y = (Math.sin(angle) * getRandomArbitrary(0, radius)) + centerPoint.y;
return new google.maps.Point(x, y);
}
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
google.maps.event.addDomListener(window, 'load', initMap);
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
<script src="http://maps.googleapis.com/maps/api/js?key=&sensor=false"></script>
<div id="map"></div>
The example demonstrates how to draw a markers randomly inside a circle.
Can anyone please help me in connecting specified points with an arc or parabola or any curve line in my google map? It is currently connected with a straight line. I have tried using the other stack overflow question where this was asked but those codes only connects two points, I might have multiple markers in the future so i need something that can be resused over and over... Please see the codes below...
<!DOCTYPE html>
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script>
var x=new google.maps.LatLng(14.560774500000008,121.02631410000006);
var rcbc=new google.maps.LatLng(14.560648, 121.016781);
var powerplant=new google.maps.LatLng(14.565066, 121.036184);
var trafalgar=new google.maps.LatLng(14.560774500000008,121.02631410000006);
var mapua=new google.maps.LatLng(14.562883, 121.022039);
function initialize()
{
var mapProp = {
center:x,
zoom:15,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
var myTrip=[trafalgar,rcbc];
var myTrip2=[rcbc,powerplant];
var flightPath2=new google.maps.Polyline({
path:myTrip2,
strokeColor:"##35495e",
strokeOpacity:0.8,
strokeWeight:3
});
var flightPath=new google.maps.Polyline({
path:myTrip,
strokeColor:"##35495e",
strokeOpacity:0.8,
strokeWeight:3
});
var marker=new google.maps.Marker({
position:x,
});
var marker2=new google.maps.Marker({
position:london,
});
var marker3=new google.maps.Marker({
position:rcbc,
});
var marker4=new google.maps.Marker({
position:powerplant,
});
marker4.setMap(map);
marker3.setMap(map);
marker2.setMap(map);
marker.setMap(map);
flightPath.setMap(map);
flightPath2.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="googleMap" style="width:1000px;height:680px;"></div>
</body>
</html>
One option would be to use the code from this related question: How to display curved polyline on one side of a straight line? (a Bezier curve).
proof of concept fiddle
code snippet:
function drawCurve(P1, P2, map) {
var lineLength = google.maps.geometry.spherical.computeDistanceBetween(P1, P2);
var lineHeading = google.maps.geometry.spherical.computeHeading(P1, P2);
if (lineHeading < 0) {
var lineHeading1 = lineHeading + 45;
var lineHeading2 = lineHeading + 135;
} else {
var lineHeading1 = lineHeading + -45;
var lineHeading2 = lineHeading + -135;
}
var pA = google.maps.geometry.spherical.computeOffset(P1, lineLength / 2.2, lineHeading1);
var pB = google.maps.geometry.spherical.computeOffset(P2, lineLength / 2.2, lineHeading2);
var curvedLine = new GmapsCubicBezier(P1, pA, pB, P2, 0.01, map);
}
var x = new google.maps.LatLng(14.560774500000008, 121.02631410000006);
var london = new google.maps.LatLng(51.5073509, -0.12775829999998223);
var rcbc = new google.maps.LatLng(14.560648, 121.016781);
var powerplant = new google.maps.LatLng(14.565066, 121.036184);
var trafalgar = new google.maps.LatLng(14.560774500000008, 121.02631410000006);
var mapua = new google.maps.LatLng(14.562883, 121.022039);
function initialize() {
var mapProp = {
center: x,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
var myTrip = [trafalgar, rcbc];
var myTrip2 = [rcbc, powerplant];
drawCurve(trafalgar, rcbc, map);
drawCurve(rcbc, powerplant, map);
var marker = new google.maps.Marker({
position: x,
});
var marker2 = new google.maps.Marker({
position: london,
});
var marker3 = new google.maps.Marker({
position: rcbc,
});
var marker4 = new google.maps.Marker({
position: powerplant,
});
marker4.setMap(map);
marker3.setMap(map);
marker2.setMap(map);
marker.setMap(map);
flightPath.setMap(map);
flightPath2.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);
// original Belzier Curve code from nicoabie's answer to this question on StackOverflow:
// https://stackoverflow.com/questions/5347984/letting-users-draw-curved-lines-on-a-google-map
var GmapsCubicBezier = function(latlong1, latlong2, latlong3, latlong4, resolution, map) {
var lat1 = latlong1.lat();
var long1 = latlong1.lng();
var lat2 = latlong2.lat();
var long2 = latlong2.lng();
var lat3 = latlong3.lat();
var long3 = latlong3.lng();
var lat4 = latlong4.lat();
var long4 = latlong4.lng();
var points = [];
for (it = 0; it <= 1; it += resolution) {
points.push(this.getBezier({
x: lat1,
y: long1
}, {
x: lat2,
y: long2
}, {
x: lat3,
y: long3
}, {
x: lat4,
y: long4
}, it));
}
var path = [];
for (var i = 0; i < points.length - 1; i++) {
path.push(new google.maps.LatLng(points[i].x, points[i].y));
path.push(new google.maps.LatLng(points[i + 1].x, points[i + 1].y, false));
}
var Line = new google.maps.Polyline({
path: path,
geodesic: true,
strokeColor: "##35495e",
strokeOpacity: 0.8,
strokeWeight: 3
/* dashed line:
icons: [{
icon: {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
scale: 4
},
offset: '0',
repeat: '20px'
}], */
});
Line.setMap(map);
return Line;
};
GmapsCubicBezier.prototype = {
B1: function(t) {
return t * t * t;
},
B2: function(t) {
return 3 * t * t * (1 - t);
},
B3: function(t) {
return 3 * t * (1 - t) * (1 - t);
},
B4: function(t) {
return (1 - t) * (1 - t) * (1 - t);
},
getBezier: function(C1, C2, C3, C4, percent) {
var pos = {};
pos.x = C1.x * this.B1(percent) + C2.x * this.B2(percent) + C3.x * this.B3(percent) + C4.x * this.B4(percent);
pos.y = C1.y * this.B1(percent) + C2.y * this.B2(percent) + C3.y * this.B3(percent) + C4.y * this.B4(percent);
return pos;
}
};
html,
body,
#googleMap {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="googleMap"></div>
When you load the Google Maps JS, specify the geometry library:
<script src="http://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
This means you can then add the geodesic attribute when you create the polylines, e.g.
var flightPath2=new google.maps.Polyline({
path:myTrip2,
geodesic: true,
strokeColor:"##35495e",
strokeOpacity:0.8,
strokeWeight:3
});
"When true, edges of the polygon are interpreted as geodesic and will
follow the curvature of the Earth. When false, edges of the polygon
are rendered as straight lines in screen space."
See Google's examples and documentation:
https://developers.google.com/maps/documentation/javascript/geometry#Navigation
https://developers.google.com/maps/documentation/javascript/examples/geometry-headings
https://developers.google.com/maps/documentation/javascript/3.exp/reference#PolylineOptions
I'm trying to draw a bezier curve in google maps by using a SVG path in a Polyline. At first I used a Marker instead similar to Curved line between two near points in google maps, which gave the results that I'm after. However, since it's not possible to drag the map under the marker, I can't use this method.
So I switched to a Polyline instead of a marker. Now I get the same good results when I zoom out, but when I zoom in the curve becomes "cropped".
Here is the code:
function initialize() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var coord1 = new google.maps.LatLng(49.165876, -123.152446);
var coord2 = new google.maps.LatLng(25.786328, -80.193694);
var bounds = new google.maps.LatLngBounds();
bounds.extend(coord1);
bounds.extend(coord2);
map.fitBounds(bounds);
pLineOpt = {
path: [coord1, coord2],
strokeWeight: 4,
strokeOpacity: 0,
map: map,
}
pLine = new google.maps.Polyline(pLineOpt);
var markers = [
new google.maps.Marker({
position: coord1,
map: map
}),
new google.maps.Marker({
position: coord2,
map: map
})
];
google.maps.event.addListener(map, 'zoom_changed', function () {
//points
var p1 = map.getProjection().fromLatLngToPoint(coord1);
var p2 = map.getProjection().fromLatLngToPoint(coord2);
//distance between points
var d = new google.maps.Point(p2.x - p1.x, p2.y - p1.y);
var lengthSqr = d.x * d.x + d.y * d.y;
//middle point
var m = new google.maps.Point(d.x / 2, d.y / 2);
//slope of perpendicular line
var perpK = -d.x / d.y;
//distance to control point
var ratioDistanceControlLengthSqr = 9;
var controlDSqr = lengthSqr / ratioDistanceControlLengthSqr;
var p3dX = Math.sqrt(controlDSqr / (Math.pow(perpK, 2) + 1));
var p3dY = perpK * p3dX;
//control point
var p3 = new google.maps.Point(m.x - p3dX, m.y - p3dY);
//curve path
var path = "M 0 0 q " + p3.x + " " + p3.y + " " + d.x + " " + d.y;
//calc scale
var zoom = map.getZoom();
var scale = 1 / (Math.pow(2, -zoom));
var icon = {
path: path,
scale: scale,
strokeWeight: 3,
strokeOpacity: 1,
};
pLineOpt.icons = [{
fixedRotation: true,
icon: icon,
offset: '0'
}];
pLine.setOptions(pLineOpt);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
I have made a jsfiddle with the code: http://jsfiddle.net/s7djLzyd/3/
Does anyone know why the Polyline is cropped when zooming, and if there is a way around this?
Thanks
You need to fix your Polyline Options :
pLineOpt = {
path: [coord1, coord2],
geodesic: true,
strokeColor: '#000',
strokeOpacity: 1.0,
strokeWeight: 4
}
Please try this code snippet : May be this is what you want... :)
function initialize() {
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var coord1 = new google.maps.LatLng(49.165876, -123.152446);
var coord2 = new google.maps.LatLng(25.786328, -80.193694);
var bounds = new google.maps.LatLngBounds();
bounds.extend(coord1);
bounds.extend(coord2);
map.fitBounds(bounds);
pLineOpt = {
path: [coord1, coord2],
geodesic: true,
strokeColor: '#000',
strokeOpacity: 1.0,
strokeWeight: 4
}
pLine = new google.maps.Polyline(pLineOpt);
var markers = [
new google.maps.Marker({
position: coord1,
map: map
}),
new google.maps.Marker({
position: coord2,
map: map
})];
pLine.setMap(map);
google.maps.event.addListener(map, 'zoom_changed', function () {
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html, body, #map-canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry,places&ext=.js"></script>
<div id="map-canvas"></div>
From this related question: Google Maps API: Bézier curve polyline wrap
var curvedLine = new GmapsCubicBezier(
49.165876, -123.152446,
33.811192,-115.032444,
30.820807,-123.749998,
25.786328, -80.193694,
0.01, map);
example fiddle
code snippet:
var map;
var origLoc = new google.maps.LatLng(45, -85);
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(33.811192, -115.032444),
zoom: 3
};
map = new google.maps.Map(document.getElementById("map"), mapOptions);
var coord1 = new google.maps.LatLng(49.165876, -123.152446);
var coord2 = new google.maps.LatLng(25.786328, -80.193694);
var marker1 = new google.maps.Marker({
position: coord1,
title: "marker 1",
map: map
});
var marker2 = new google.maps.Marker({
position: coord2,
title: "marker 2",
map: map
});
var curvedLine = new GmapsCubicBezier(
49.165876, -123.152446,
33.811192, -115.032444,
30.820807, -123.749998,
25.786328, -80.193694,
0.01, map);
}
google.maps.event.addDomListener(window, 'load', initialize);
var GmapsCubicBezier = function(lat1, long1, lat2, long2, lat3, long3, lat4, long4, resolution, map) {
var points = [];
for (it = 0; it <= 1; it += resolution) {
points.push(this.getBezier({
x: lat1,
y: long1
}, {
x: lat2,
y: long2
}, {
x: lat3,
y: long3
}, {
x: lat4,
y: long4
}, it));
}
for (var i = 0; i < points.length - 1; i++) {
var Line = new google.maps.Polyline({
path: [new google.maps.LatLng(points[i].x, points[i].y), new google.maps.LatLng(points[i + 1].x, points[i + 1].y, false)],
geodesic: true,
strokeOpacity: 1,
strokeColor: 'black',
/* icons: [{
icon: {
path: 'M 0,-2 0,2',
strokeColor: 'violet',
strokeOpacity: 1,
strokeWeight: 4
},
repeat: '36px'
}, {
icon: {
path: 'M -1,-2 -1,2',
strokeColor: 'black',
strokeOpacity: 1,
strokeWeight: 2
},
repeat: '36px'
}] */
});
Line.setMap(map);
}
// connect end of line to first point
var Line = new google.maps.Polyline({
path: [new google.maps.LatLng(lat1,long1),new google.maps.LatLng(points[points.length-1].x, points[points.length-1].y)],
geodesic: true,
strokeOpacity: 1,
strokeColor: 'black',
/* icons: [{
icon: {
path: 'M 0,-2 0,2',
strokeColor: 'violet',
strokeOpacity: 1,
strokeWeight: 4
},
repeat: '36px'
}, {
icon: {
path: 'M -1,-2 -1,2',
strokeColor: 'black',
strokeOpacity: 1,
strokeWeight: 2
},
repeat: '36px'
}] */
});
Line.setMap(map);
return Line;
};
GmapsCubicBezier.prototype = {
B1: function(t) {
return t * t * t;
},
B2: function(t) {
return 3 * t * t * (1 - t);
},
B3: function(t) {
return 3 * t * (1 - t) * (1 - t);
},
B4: function(t) {
return (1 - t) * (1 - t) * (1 - t);
},
getBezier: function(C1, C2, C3, C4, percent) {
var pos = {};
pos.x = C1.x * this.B1(percent) + C2.x * this.B2(percent) + C3.x * this.B3(percent) + C4.x * this.B4(percent);
pos.y = C1.y * this.B1(percent) + C2.y * this.B2(percent) + C3.y * this.B3(percent) + C4.y * this.B4(percent);
return pos;
}
};
html,
body,
#map {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=geometry"></script>
<div id="map" style="float:left;width:100%;height:100%;"></div>