I want to add a marker every 5 or 10 Kilometer on the polylines of the direction given by google maps api.
something like this :
http://www.geocodezip.com/v3_polyline_example_kmmarkers_0.html
but with the google direction's
I found a formula that works like a charm. It adds a marker every 8 meter between to given points.
I got the formula from here: How to calculate the points between two given points and given distance?
PointF pointA, pointB;
var diff_X = pointB.X - pointA.X;
var diff_Y = pointB.Y - pointA.Y;
int pointNum = 8;
var interval_X = diff_X / (pointNum + 1);
var interval_Y = diff_Y / (pointNum + 1);
List<PointF> pointList = new List<PointF>();
for (int i = 1; i <= pointNum; i++)
{
pointList.Add(new PointF(pointA.X + interval_X * i, pointA.Y + interval_Y*i));
}
Android
My end result translation
//GeoPoint PointF, pointA, pointB;
Double diff_X = lat2 - lat1;
Double diff_Y = lon2 - lon1;
int pointNum = 8;
Double interval_X = diff_X / (pointNum + 1);
Double interval_Y = diff_Y / (pointNum + 1);
//ArrayList<GeoPoint> geoPoints = new ArrayList<>();
List<GeoPoint> pointList = new ArrayList<>();
for (int i = 1; i <= pointNum; i++)
{
GeoPoint g = new GeoPoint(lat1 + interval_X * i, lon1 + interval_Y*i);
pointList.add(g);
itemizedLayer.addItem(createMarkerItem(g, R.drawable.ic_my_location));
}
map.map().updateMap(true);
Given a start point, initial bearing, and distance, this will
calculate the destination point and final bearing travelling along a
(shortest distance) great circle arc.
var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng) );
var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),
Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));
source: http://www.movable-type.co.uk/scripts/latlong.html
The radius of the earth (R) is 6371000 meters.
brng is the direction you are travelling in degrees (0 = north).
Then use this function to add markers to the map
function setMarkers(map, locations) {
// Add markers to the map
// Marker sizes are expressed as a Size of X,Y
// where the origin of the image (0,0) is located
// in the top left of the image.
// Origins, anchor positions and coordinates of the marker
// increase in the X direction to the right and in
// the Y direction down.
var image = {
url: 'images/beachflag.png',
// This marker is 20 pixels wide by 32 pixels tall.
size: new google.maps.Size(20, 32),
// The origin for this image is 0,0.
origin: new google.maps.Point(0,0),
// The anchor for this image is the base of the flagpole at 0,32.
anchor: new google.maps.Point(0, 32)
};
var shadow = {
url: 'images/beachflag_shadow.png',
// The shadow image is larger in the horizontal dimension
// while the position and offset are the same as for the main image.
size: new google.maps.Size(37, 32),
origin: new google.maps.Point(0,0),
anchor: new google.maps.Point(0, 32)
};
// Shapes define the clickable region of the icon.
// The type defines an HTML <area> element 'poly' which
// traces out a polygon as a series of X,Y points. The final
// coordinate closes the poly by connecting to the first
// coordinate.
var shape = {
coord: [1, 1, 1, 20, 18, 20, 18 , 1],
type: 'poly'
};
for (var i = 0; i < locations.length; i++) {
var beach = locations[i];
var myLatLng = new google.maps.LatLng(beach[1], beach[2]);
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
shadow: shadow,
icon: image,
shape: shape,
title: beach[0],
zIndex: beach[3]
});
}
}
source:
https://developers.google.com/maps/documentation/javascript/overlays
Edit that function to have the proper marker icons and call it for each marker you want to place.
Related
I need to display different polylines from A to B. So, these lines should be distinguishable from each other. I haved tried to set polylines using pushpoint function with altitude parameter. However it is still on the ground level. And the last polyline I inserted overwrites the previous one.
Altitude value works on markers but I want to apply it on polyline.
I changed the sample code here markers with altitude as below. You can see the orange line is just on top of the gray line when you change the code with the below one. I would like both lines to be displayed like the markers you see above them.
/**
* Calculate the bicycle route.
* #param {H.service.Platform} platform A stub class to access HERE services
*/
function calculateRouteFromAtoB (platform) {
var router = platform.getRoutingService(),
routeRequestParams = {
mode: 'fastest;bicycle',
representation: 'display',
routeattributes : 'shape',
waypoint0: '-16.1647142,-67.7229166',
waypoint1: '-16.3705847,-68.0452683',
// explicitly request altitude values
returnElevation: true
};
router.calculateRoute(
routeRequestParams,
onSuccess,
onError
);
}
/**
* Process the routing response and visualise the descent with the help of the
* H.map.Marker
*/
function onSuccess(result) {
var lineString = new H.geo.LineString(),
lineString2 = new H.geo.LineString(),
routeShape = result.response.route[0].shape,
group = new H.map.Group(),
dict = {},
polyline,
polyline2;
routeShape.forEach(function(point) {
var parts = point.split(',');
var pp= new H.geo.Point(parts[0],parts[1],4000,"SL");
console.log(parts[2]);
lineString.pushLatLngAlt(parts[0], parts[1]);
lineString2.pushPoint(pp);
// normalize the altitude values for the color range
var p = (parts[2] - 1000) / (4700 - 1000);
var r = Math.round(255 * p);
var b = Math.round(255 - 255 * p);
// create or re-use icon
var icon;
if (dict[r + '_' + b]) {
icon = dict[r + '_' + b];
} else {
var canvas = document.createElement('canvas');
canvas.width = 4;
canvas.height = 4;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(' + r + ', 0, ' + b + ')';
ctx.fillRect(0, 0, 4, 4);
icon = new H.map.Icon(canvas);
// cache the icon for the future reuse
dict[r + '_' + b] = icon;
}
// the marker is placed at the provided altitude
var marker = new H.map.Marker({
lat: parts[0], lng: parts[1], alt: parts[2]
}, {icon: icon});
var marker2 = new H.map.Marker({
lat: parts[0], lng: parts[1], alt: parts[2]-800
}, {icon: icon});
group.addObject(marker);
group.addObject(marker2);
});
polyline = new H.map.Polyline(lineString, {
style: {
lineWidth: 6,
strokeColor: '#555555'
}
});
polyline2 = new H.map.Polyline(lineString2, {
style: {
lineWidth: 3,
strokeColor: '#FF5733'
}
});
// Add the polyline to the map
map.addObject(polyline);
map.addObject(polyline2);
// Add markers to the map
map.addObject(group);
// Zoom to its bounding rectangle
map.getViewModel().setLookAtData({
bounds: polyline.getBoundingBox(),
tilt: 60
});
}
/**
* This function will be called if a communication error occurs during the JSON-P request
* #param {Object} error The error message received.
*/
function onError(error) {
alert('Can\'t reach the remote server');
}
/**
* Boilerplate map initialization code starts below:
*/
// set up containers for the map + panel
var mapContainer = document.getElementById('map'),
routeInstructionsContainer = document.getElementById('panel');
//Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
//Step 2: initialize a map - this map is centered over Berlin
var map = new H.Map(mapContainer,
defaultLayers.vector.normal.map,{
center: {lat:52.5160, lng:13.3779},
zoom: 13,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Create the default UI components
var ui = H.ui.UI.createDefault(map, defaultLayers);
// Now use the map as required...
calculateRouteFromAtoB (platform);
Unfortunately, for now only markers support altitudes.
Polylines should follow in near future.
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
I wanted to make a map using openlayers but center it a unique way. For example I have a z/x/y coordinate of 12/2045/-1362, how do I convert it to longitude/latitude? It's quite the polar opposite of this: How to get X Y Z coordinates of tile by click on Leaflet map
It's quite hard for me to get the logic of the above link and invert it. I hope someone here has an experience or a ready-made formula for this. Thanks
Later I'll this in rendering the center of my map like this:
var z = 12;
var x = 2045;
var y = -1362;
function convertXYZtoCoor(z, x, y) {
// code here
return [lng, lat];
}
var coor = convertXYZtoCoor(z, x, y);
var view = new ol.View({
center: ol.proj.transform(
[coor[0], coor[1]], 'EPSG:4326', 'EPSG:3857'),
zoom: z
});
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
view: view
});
Hope my question is understood more thanks.
Edit: Added code
var tileExtent = function(tileCoord){
var z = tileCoord[0];
var x = tileCoord[1];
var y = tileCoord[2];
var tileGridOrigin = tileGrid.getOrigin(z);
var tileSizeAtResolution = tileGrid.getTileSize(z) * tileGrid.getResolution(z);
return [
tileGridOrigin[0] + tileSizeAtResolution * x,
tileGridOrigin[1] + tileSizeAtResolution * y,
tileGridOrigin[0] + tileSizeAtResolution * (x + 1),
tileGridOrigin[1] + tileSizeAtResolution * (y + 1)
];
}
You can test/verify at http://jsfiddle.net/eurx57s7/
Note (stolen from the ol3 example, but it applies here to):
The tile coordinates are ol3 normalized tile coordinates (origin bottom left), not OSM tile coordinates (origin top left)
I have five rectangles placed at different points along a circle like this - http://imgur.com/uVYkwl7.
Upon clicking any rectangle i want the circle to move to the left of the screen, gradually scaling down it's radius until the circle's center reaches x=0. I'd like the five rectangles to move along with the circle while its being scaled down and also adjust their own positions and scale on the circle so that they are within the view's bounds, like this - http://imgur.com/acDG0Aw
I'd appreciate any help on how to go about doing this. Heres my code for getting to the 1st image and animating the circle:
var radius = 300;
var center = view.center;
var circle = new Path.Circle({
center: view.center,
radius: radius,
strokeColor: 'black',
name: 'circle'
});
var path = new Path.Rectangle({
size: [230, 100],
fillColor: '#1565C0'
});
var rectText = ['Text 1',
'Text 2',
'Text 3',
'Text 4',
'Text 5'
];
var symbol = new Symbol(path);
var corners = [
new Point(center.x, center.y - radius),
new Point(center.x - radius, center.y - radius / 2),
new Point(center.x + radius, center.y - radius / 2),
new Point(center.x - radius, center.y + radius / 2),
new Point(center.x + radius, center.y + radius / 2)
];
var rectClicked = false;
var clickedRect = null;
var rectClick = function(event) {
rectClicked = true;
clickedRect = this;
};
function onFrame(event) {
// Your animation code goes in here
if (rectClicked) {
for (var i = 0; i < 1; i++) {
var item = project.activeLayer.children[i];
if (item.name == 'circle') {
if (item.position.x < 0) {
rectClicked = false;
} else {
item.position.x -= 10;
item.scale(1/1.01);
}
}
}
}
}
// Place the instances of the symbol:
for (var i = 0; i < corners.length; i++) {
var placedSymbol = symbol.place(corners[i]);
placedSymbol.onMouseDown = rectClick;
var rText = new PointText({
point: placedSymbol.bounds.topLeft + 20,
content: rectText[i],
fontSize: '20',
fillColor: 'white'
});
}
Paper.js provides rotations around a pivot out of the box.
var pivotPoint = new Point(10, 5);
circle.rotate(30,pivotPoint);
Here is the docs reference for this behaviour and here is a very basic Sketch example to illustrate this
The above snippet will rotate a circle(you can change this to rectangle in your case) by 30 degrees around a pivot point at coordinates 10,5 on the x/y axis.
Thus what you describe is certainly doable as long as the path that your elements will follow is always circular.
Bear in mind that in order for the pivot rotation to work the way you want them to you need to update the pivotPoint and reinitiate the rotation again.
Note: In case you want to move along an arbitrary shape instead of circular path, you should search for Paper.js animation-along-a-path which is something that I've seen been done before without much difficulty - e.g this simple Sketch by the creator of Paper.js himself.
The sketch I provided above is a basic example of rotation around a pivot point.
I'm dumping the Sketch code here in case the link goes dead:
//Create a center point
var centerCircle = new Path.Circle(paper.view.center, 100);
centerCircle.strokeColor = 'black';
centerCircle.dashArray = [10, 12];
//Create the circles
var circle1Radius = 30;
var circle1 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle1Radius, circle1Radius);
circle1.fillColor = '#2196F3';
var circle2Radius = 40;
var circle2 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle2Radius, circle2Radius);
circle2.fillColor = '#E91E63';
var circle3Radius = 40;
var circle3 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle2Radius, circle2Radius);
circle3.fillColor = '#009688';
var i=0;
var animationGap = 125; //how long to move before animating the next circle
var rotationSpeed = 2;
function onFrame(event) {
circle1.rotate(rotationSpeed,centerCircle.position);
if(i>animationGap)
circle2.rotate(rotationSpeed,centerCircle.position);
if(i>animationGap*2)
circle3.rotate(rotationSpeed,centerCircle.position);
i++;
}