Does anyone have any examples or source for letting users draw curved maps from point a to point b?
Thanks,
Alex
You can draw Bezier curves this way:
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)],
geodesic: true,
strokeOpacity: 0,
strokeColor: 'yellow',
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);
}
};
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;
}
};
You can modify the code, to provide differents strategies to draw the lines. The one implemented is pointed with "shadow".
The usage is pretty easy:
var curvedLine = new GmapsCubicBezier(initLat, initLong, control1Lat, control1Long, control2Lat, control2Long, endLat, endLong, 0.1, map);
you might have to use some sort of layer on top of google map. I know there's a cloud app that allows you to scrabble on a google map, but it uses flash to embed the google map scribblemaps.com/… i don't think it's possible to use two points to create a curve perhaps more than two points.
If i understand your application correctly, based on your website, the goal that you wish to achieve is to let users to "blaze a trail"? If that is the case maybe you can create a form where the users can submit Lat Lng coordinates of the "trials" that they've "blazed," and then use Polyline to draw the curve line similar to this google map draw curved line.
However, if users just want to know how to hike from point a to point b and etc, then you can use DirectionService and DirectionRenderer, and set the DirectionsTravelMode to google.maps.DirectionsTravelMode.WALKING and render the direction on the map that way so the user would know how to hike a route with directions drawn on the map + actual direction instructions.
Related
Please forgive me, this is my first question after searching a lot for it here.
I am trying to automatically select different color circles on a leaflet map for an attribute in an object.
The ID has different values in the database, so unfortunately I can't assign it to fixed colors.
The JSON object I am working with looks like this:
fcoord = { id: "xxxxxxxx", lat: "xxxxxx", lon: "xxxxxx" }
The thing is that for every different ID in the Object it should automatic mark a Circle on the map in a different Color.
My JavaScript Code looks like this:
var fMarkers = newSet([]);
for (var i:0;i<fcoord.length;i++) {
drawCirclef(fcoord[i], mymap, fMarkers);
}
function drawCirclef(fcoord, map, fMarkers){
var circle = L.circle(fcoord.lat, fcoord.lon] {
fillOpacity: 0.1,
radius: 1500,
fillColor: 'green',
}).addTo(map)
fMarkers.add(circle);
The result is that every ID in the object is highlighted in the same color because I have defined it as 'green'.
I'm stuck on how to make it mark in a different color for each ID.
Can someone please help me move forward or find a solution.
Many many thanks in advance
Create a function that retuns the wanted color for the id
function getColor(id){
switch(id){
case 'id1': return 'green';
case 'id2': return 'blue';
default: return 'red';
}
}
var fMarkers = newSet([]);
for (var i:0;i<fcoord.length;i++) {
drawCirclef(fcoord[i], mymap, fMarkers);
}
function drawCirclef(fcoord, map, fMarkers){
var circle = L.circle(fcoord.lat, fcoord.lon] {
fillOpacity: 0.1,
radius: 1500,
fillColor: getColor(fcoord.id),
}).addTo(map)
fMarkers.add(circle);
}
I found a solution/workaround with a friend of mine:
First creating a var for the Colors of the future Circles:
var colors = ['cyan', 'grey', 'pink', 'green', 'purple', 'black', 'orange']
var colorsForKey = {}
Edit the JSON-Object so that each ID will be a Key with all appearing Lat, Lon etc. inside it.
Creating a Counter which walks through the Var and everytime a new ID appears, jump to the next Color.
function createColors(fcoord){
counter = 0;
for (i in fcoord) {
counter = 0
colorsForKey[i] = colors[counter];
counter = counter + 1
}
}
function getColor(id) {
return colorsForKey[ID];
}
function drawCirclef(fcoord, map, fMarkers, ID){
var circle = L.circle([fcoord.lat, fcoord.lon] {
fillOpacity: 0.1,
radius: 1500,
fillColor: getColor(ID),
color: getColor(ID)
}.addTo(map)
.fMarkers.add(circle);
}
var fMarkers = newSet([]);
createColors(fcoord);
for (var ID in fcoord){
for (var i=0;<fcoord[ID].length;i++){
drawCirclef(fcoord[ID][i], mymap, fMarkers, ID);
I'm new to React and have been playing around with the react-google-maps package. I'm trying to curve a Polyline that joins two places. After going through the documentation, I'm trying to incorporate the curve polyline function under the 'editable' prop.
Here's the function to curve the polyline:
var map;
var curvature = 0.4; // Arc of the Polyline
function init() {
var Map = google.maps.Map,
LatLng = google.maps.LatLng,
LatLngBounds = google.maps.LatLngBounds,
Marker = google.maps.Marker,
Point = google.maps.Point;
// Initial location of the points
var pos1 = new LatLng(this.state.srcMarker);
var pos2 = new LatLng(this.state.desMarker);
var bounds = new LatLngBounds();
bounds.extend(pos1);
bounds.extend(pos2);
map = new Map(document.getElementById('map-canvas'), {
center: bounds.getCenter(),
zoom: 12
});
map.fitBounds(bounds);
var markerP1 = new Marker({
position: pos1,
map: map
});
var markerP2 = new Marker({
position: pos2,
map: map
});
var curveMarker;
function updateCurveMarker() {
var pos1 = markerP1.getPosition(),
pos2 = markerP2.getPosition(),
projection = map.getProjection(),
p1 = projection.fromLatLngToPoint(pos1),
p2 = projection.fromLatLngToPoint(pos2);
// Calculating the arc.
var e = new Point(p2.x - p1.x, p2.y - p1.y), // endpoint
m = new Point(e.x / 2, e.y / 2), // midpoint
o = new Point(e.y, -e.x), // orthogonal
c = new Point( m.x + curvature * o.x, m.y + curvature * o.y); //curve control point
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: 1,
fillColor: 'none'
};
if (!curveMarker) {
curveMarker = new 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(markerP1, 'position_changed', updateCurveMarker);
google.maps.event.addListener(markerP2, 'position_changed', updateCurveMarker);
}
google.maps.event.addDomListener(window, 'load', init);
I'm not able to understand how to use this function in the Polyline component. I'm able to mark a line between any two places, but not able to use this function in order to curve the given polyline. This is the Polyline component that I'm using.
<Polyline
path={pathCoordinates}
geodesic={true}
options={{
strokeColor: '#ff2527',
strokeOpacity: 1.0,
strokeWeight: 5,
}}
/>
I have two markers in my state (srcMarker, desMarker) that store the coordinates of the given cities once the user inputs the city name. Any help would be appreciated in incorporating this function with the Polyline component. I haven't come across any built in feature that allows curving of the polyline. Thanks in advance!
I took the code you provided and adapted it to work with React and react-google-maps. Check out this CodeSandbox to see a simple application that contains two markers and a curved line between them.
The curved line that connects the two markers is actually a marker as well. The only difference between it and the two red markers is that its icon prop is set to the curved line (which is computed beforehand).
Here is the code for the CurveMarker component:
const CurveMarker = ({ pos1, pos2, mapProjection, zoom }) => {
if (!mapProjection) return <div/>;
var curvature = 0.4
const p1 = mapProjection.fromLatLngToPoint(pos1),
p2 = mapProjection.fromLatLngToPoint(pos2);
// Calculating the arc.
const e = new google.maps.Point(p2.x - p1.x, p2.y - p1.y), // endpoint
m = new google.maps.Point(e.x / 2, e.y / 2), // midpoint
o = new google.maps.Point(e.y, -e.x), // orthogonal
c = new google.maps.Point(m.x + curvature * o.x, m.y + curvature * o.y); //curve control point
const pathDef = 'M 0,0 ' + 'q ' + c.x + ',' + c.y + ' ' + e.x + ',' + e.y;
const scale = 1 / (Math.pow(2, -zoom));
const symbol = {
path: pathDef,
scale: scale,
strokeWeight: 2,
fillColor: 'none'
};
return <Marker
position={pos1}
clickable={false}
icon={symbol}
zIndex={0}
/>;
};
Let me know if you have any questions.
I'm trying to draw a hexagonal grid in Google Maps. I've come up with a solution based off this answer which looks fine at higher zooms, but when zoomed further out I find that the classic "orange-peel" problem occurs: The hexagons no longer fit together like they should:
I'm using this rather cool geodesy library to calculate hexagon centers based on an ellipsoidal model (since a 2d model clearly doesn't work on a real-world map) but it's still looking pretty bad when zoomed out.
Preferably, I'd like to draw the hexagons in such a way that they are exactly the same shape and size on screen.
Here's the code I've been working with, also available as a Plunker here. I've tried calculating the vertices of each polygon using the same geodesy library that I'm using to calculate the polygon centers, but it still doesn't look right when zoomed out.
var hexgrid = [];
function initialize(){
// Create the map.
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 51.5, lng: 0},
scrollwheel: true,
zoom: 8
});
// This listener waits until the map is done zooming or panning,
// Then clears all existing polygons and re-draws them.
map.addListener('idle', function() {
// Figure out how big our grid needs to be
var spherical = google.maps.geometry.spherical,
bounds = map.getBounds(),
cor1 = bounds.getNorthEast(),
cor2 = bounds.getSouthWest(),
cor3 = new google.maps.LatLng(cor2.lat(), cor1.lng()),
cor4 = new google.maps.LatLng(cor1.lat(), cor2.lng()),
diagonal = spherical.computeDistanceBetween(cor1,cor2),
gridSize = diagonal / 20;
// Determine the actual distance between tiles
var d = 2 * gridSize * Math.cos(Math.PI / 6);
// Clear all the old tiles
hexgrid.forEach(function(hexagon){
hexagon.setMap(null);
});
hexgrid = [];
// Determine where the upper left-hand corner is.
bounds = map.getBounds();
ne = bounds.getNorthEast();
sw = bounds.getSouthWest();
var point = new LatLon(ne.lat(), sw.lng());
// ... Until we're at the bottom of the screen...
while(point.lat > sw.lat()){
// Keep this so that we know where to return to when we're done moving across to the right
leftPoint = new LatLon(point.lat, point.lon).destinationPoint(d, 150).destinationPoint(d, 210).destinationPoint(d, 270).destinationPoint(d, 90)
step = 1;
while(point.lon < ne.lng()){
// Use the modulus of step to determing if we want to angle up or down
if (step % 2 === 0){
point = new LatLon(point.lat, point.lon).destinationPoint(d, 30);
} else {
point = new LatLon(point.lat, point.lon).destinationPoint(d, 150);
}
step++; // Increment the step
// Draw the hexagon!
// First, come up with the corners.
vertices = [];
for(v = 1; v < 7; v++){
angle = v * 60;
vertex = point.destinationPoint(d / Math.sqrt(3), angle);
vertices.push({lat: vertex.lat, lng: vertex.lon});
}
// Create the shape
hexagon = new google.maps.Polygon({
map: map,
paths: vertices,
strokeColor: '#090',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#090',
fillOpacity: 0.1,
draggable: false,
});
// Push it to hexgrid so we can delete it later
hexgrid.push(hexagon)
}
// Return to the left.
point = leftPoint;
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
Please consider that Google Maps is in Mercator Projection.
You have to compensate for the sphere of the globe on the projection.
https://en.wikipedia.org/wiki/Mercator_projection
EDIT This question has been answered but I've clarified it for future readers.
RouteBoxer provides a solution of 'boxing in' a route in Google maps so that I can list various points of interest along that route. This technic though creates borders around each box presented on the map. I've attached an image to describe what it looks like.
The code produced to create RouteBoxer looks like this:
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/routeboxer/src/RouteBoxer.js"></script>
var directionService = new google.maps.DirectionsService();
var rboxer = new RouteBoxer();
var distance = 20; // km
directionService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
// Box the overview path of the first route
var path = result.routes[0].overview_path;
var boxes = routeBoxer.box(path, distance);
for (var i = 0; i < boxes.length; i++) {
var bounds = box[i];
// Perform search over this bounds
}
}
});
Is it possible to remove the borders surrounding each box on the map?
You have full control. Here is the example above in a fiddle, without black borders -> http://jsfiddle.net/ftgr8dyp/ Look at the function drawBoxes() :
function drawBoxes(boxes) {
boxpolys = new Array(boxes.length);
for (var i = 0; i < boxes.length; i++) {
boxpolys[i] = new google.maps.Rectangle({
bounds: boxes[i],
fillOpacity: 0,
strokeOpacity: 1.0,
strokeColor: '#000000', //<-- change color
strokeWeight: 0, //<-- change strokeWeight from 1 to 0
map: map
});
}
}
It is standard google.maps.Rectangle's you can style as you are used to. There is nothing in the RouterBoxer-code that forces certain design or styles.
I try to do this 3 months - I need to create a polygon by route direction like here:
so so I write this:
directionService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsRenderer.setDirections(result);
var r = [];
var z = 0.5;
var bla = result.routes[0].overview_path;
for(var i=0 in result.routes[0].overview_path) {
r.push(new google.maps.LatLng(bla[i].lat()+z, bla[i].lng()-z));
}
bla.reverse();
for(var x=0 in bla) {
r.push(new google.maps.LatLng(bla[x].lat()-z, bla[x].lng()+z));
}
var prva = new google.maps.Polyline({
path: result.routes[0].overview_path,
strokeColor: "#00000",
strokeOpacity: 1.0,
strokeWeight: 2
});
prva.setMap(map);
druga = new google.maps.Polygon({
paths: r,
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35
});
druga.setMap(map);
} else {
alert("Directions query failed: " + status);
}
});
but in some cases is good in some cases not, so my code produce this:
BAD case:
GOOD case:
So how I can solve this problem to get nice polygon by route direction ??? Does someody have idea?
How I can implement this into my code:
CONVOLUTION ALGORITHM
Is there any solution for my problem?
Is there some other way than this to create what I need?
The algorithm to produce the second image is quite simple geometrically. I'll write you some pseudocode, assuming you have an array of x,y arrays:
coordinates = [[x1,y1],[x2,y2] ... [xn,yn]]
leftcoords = []
rightcoords = []
projectionwidth = 1 # How wide the path is
for each coordinate in coordinates:
pathvector = coordinate(index + 1) - coordinate(index - 1)
normpathvector = pathvector/(length(pathvector))
perpvector = projectionwidth*[-normpathvector[1],normpathvector[0]]
leftcoords.append(coordinate + perpvector)
rightcoords.append(coordinate - perpvector)
You have to take care at the end of the path to only choose coordinates ahead or behind, but you get the idea. You end up with three sets of coordinate trajectories. You can set it up to average several points if you'd like to smooth the path.
Ok, so here is code that works, but you'll have to do some work to smooth it out to account for the jitter in the path. My suggestion would be to average several previous points, or just grab a point several back.
http://jsbin.com/uTATePe/2/