I'm currently trying to create a map application, so far the map loads and the custom information and icons work flawlessly. I'd, however, like to show the user how far away (distance) to the marker on the map.
This code is working, but I'd like the "from" variable to be the users current position instead of a predetermined position.
var onePlace = L.marker([63, 20], {icon: thisIcon}).bindPopup('My text'),
theOtherPlace = L.marker([65, 20], {icon: thatIcon}).bindPopup('My text');
var to = onePlace.getLatLng();
var from = theOtherPlace.getLatLng();
var distance = from.distanceTo(to);
To set the users position on the map I use the code from their quickstart guide whick looks something like this
primaryMap.locate({
});
primaryMap.on('locationfound', positionFound);
primaryMap.on('locationerror', positionNotFound);
function positionFound(e) {
var myPosition = L.marker(e.latlng, {
}).addTo(primaryMap);
}
function positionNotFound(e) {
alert(e.message);
}
But how to get the position that I set here in a later stage is what I'm struggling with.
Basically, what I want is this
var myPos = [??].getLatLng();
var to = onePlace.getLatLng();
var distance = myPos.distanceTo(to);
Sorry for the strange formatting on some of the code, first time posting.
Anyway, if someone could help me out here I'd be incredibly thankful. Been stuck on this one problem for forever and can't seem to find anything helpful in the documentation (probably just don't quite understand it as I'm rather new to this).
Thanks in advance!
UPDATE:
jsfiddle: https://jsfiddle.net/xcyniic/98sy6zxb/27/
Maybe this can help shed some light on what I'm doing / have done wrong.
You get the latlng from the locationfound event.
primaryMap.on('locationfound', positionFound);
function positionFound(e) {
var myPos = e.latlng;
var to = onePlace.getLatLng();
var distance = myPos.distanceTo(to);
}
Update
To get the pos value outside you have to create the variable outside and test if it is not null;
var myPos = null;
primaryMap.on('locationfound', positionFound);
function positionFound(e) {
myPos = e.latlng;
calcDistances();
}
function calcDistances(){
if(myPos){
var to = onePlace.getLatLng();
var distance = myPos.distanceTo(to); +
var to2 = twoPlace.getLatLng();
var distance = myPos.distanceTo(to2);
//...
}
}
I think that you are thinking wrong. The locationfound event is not called immediately, it is a async service. So you have to calc the distance after the event is called and the user position is found.
Related
I'm migrating from Google Maps API to Apple MapKit JS for the simple reason I have a developer account with them and they offer more free hits.
Anyway, actual examples of MapKit JS are a bit thin (or at least Google isn't finding them - draw what conspiracy theories you will), so although I've got the basics going of displaying an embeded map, I can't seem to do the next step which is route between two points (Apple's documentation also seems impenetrable as they don't show examples).
Here's my script for a basic map:
<script>
mapkit.init({
authorizationCallback: function(done) {
done('[MY-TOKEN]');
}
});
var MarkerAnnotation = mapkit.MarkerAnnotation
var myMarker = new mapkit.Coordinate(55.9496320, -3.1866360)
var myRegion = new mapkit.CoordinateRegion(
new mapkit.Coordinate(55.9496320, -3.1866360),
new mapkit.CoordinateSpan(0.003, 0.003)
);
var map = new mapkit.Map("map");
var myAnnotation = new MarkerAnnotation(myMarker, { color: "#9b6bcc", title: "theSpace On The Mile"});
map.showItems([myAnnotation]);
map.region = myRegion;
</script>
Now I want to:
• Show a walking route between two points
• Include waypoints on the route
Could someone show the code that would achieve this? Once I can see an example I know I'll get it ;-)
Ok, so I've found a solution to this so sharing it here for the benefit of others.
Let's start by saying Apple's MapKit JS doesn't appear to have a waypoints option as offered by Google Maps API - so the way around that is to create a map that stores the markers in an array and then routes from one to the next. The code stores the location of the last waypoint in a variable, and doesn't bother to draw a route to the last waypoint if this is the first one in the array (obviously).
<script>
// Initiallise MapKit - you'll need your own long-lived token for this
mapkit.init({
authorizationCallback: function(done) {
done('[MY-TOKEN]');
}
});
// Function to draw the route once MapKit has returned a response
function directionHandler(error, data) {
data["routes"].forEach(function(route, routeIdx) {
if (routeIdx !== 0) { return; }
overlays = [];
route['path'].forEach(function(path) {
// This styles the line drawn on the map
let overlayStyle = new mapkit.Style({
lineWidth: 3,
strokeColor: "#9b6bcc"
});
let overlay = new mapkit.PolylineOverlay(path, {
style: overlayStyle
});
overlays.push(overlay);
});
map.addOverlays(overlays);
});
}
// This asks MapKit for directions and when it gets a response sends it to directionHandler
function computeDirections(origin,destination) {
let directionsOptions = {
origin: origin,
destination: destination,
transportType: mapkit.Directions.Transport.Walking
};
directions.route(directionsOptions, directionHandler);
}
// This sets the initial region, but is overridden when all points have been potted to automatically set the bounds
var myRegion = new mapkit.CoordinateRegion(
new mapkit.Coordinate(55.9496320, -3.1866360),
new mapkit.CoordinateSpan(0.05, 0.05)
);
var map = new mapkit.Map("map");
map.region = myRegion;
var myAnnotations = [];
// lastWaypoint variable is 'unset' initially so the map doesn't try and find a route to the lastWaypoint for the first point of the route
var lastWaypoint = "unset";
var directions = new mapkit.Directions();
// Array of co-ordinates and label for marker
waypoints = [
{name:'Sofi’s Bar',lat:55.9746308,lon:-3.1722282},
{name:'TThe Roseleaf Cafe',lat:55.975992,lon:-3.173474},
{name:'Hemingway’s',lat:55.9763631,lon:-3.1706564},
{name:'Teuchter’s Landing',lat:55.9774693,lon:-3.1713826},
{name:'The King’s Wark',lat:55.9761425,lon:-3.1695419},
{name:'Malt and Hops',lat:55.975885,lon:-3.1698957},
{name:'The Carrier’s Quarters',lat:55.9760813,lon:-3.1685323},
{name:'Noble’s',lat:55.974905,lon:-3.16714},
{name:'The Fly Half',lat:55.9747906,lon:-3.1674496},
{name:'Port O’ Leith',lat:55.974596,lon:-3.167525}
];
// Loop through the array and create marker for each
waypoints.forEach(function(data) {
var myAnnotation = new mapkit.MarkerAnnotation(new mapkit.Coordinate(data['lat'],data['lon']), {
color: "#9b6bcc",
title: data['name']
});
myAnnotations.push(myAnnotation);
// As long as this isn't the first point on the route, draw a route back to the last point
if(lastWaypoint!="unset") {
computeDirections(lastWaypoint,new mapkit.Coordinate(data['lat'],data['lon']));
}
lastWaypoint = new mapkit.Coordinate(data['lat'],data['lon']);
});
map.showItems(myAnnotations);
</script>
This map is for a pub crawl around Leith, so the trasportType is 'Walking', but change that to 'Automobile' if you so wish.
With credit to Vasile whose MapKit JS Demo (https://github.com/vasile/mapkit-js-demo) helped me understand a lot more about the options.
I am sending points to a cesium map and trying to make the points move from one location to the other. I am trying to clear the map before adding my points but what I have does not work. What is the best way to clear the map of points,etc.
It seems like it would work but the only way I can sometimes see the correct points is to do browser refresh . Thanks
var viewer = new Cesium.Viewer('cesiumContainer', { infoBox : false });
var scene = viewer.scene;
var points = scene.primitives.add(new Cesium.PointPrimitiveCollection());
var entities = viewer.entities;
var entity = "";
...
entities.removeAll();
points.removeAll();
I was experimenting with Cesium and here is how it works for me -
(Note:Below is not the complete code but a sample for reference)
Am calling loadData at an interval of 10 secs and each time I am doing a viewer.entities.removeAll();
Sample Ref code :
function plotGeoPoints(){
Cesium.loadJson(APIURL).then(function(data) {
pdata = data;
for ( var i = 0; i < pdata.length; i++){
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(pdata[i].longitude, pdata[i].latitude),
point : {
pixelSize : 5,
color : CESIUM.Color.RED,
outlineWidth:0
}
});
}
}
}
function loadData(){
viewer.entities.removeAll();
plotGeoPoints();
}
}
loadData();
intervalId = setInterval(loadData,10000);
I am using Mapbox.js with browserify. I want to create a module that creates a map if it does not already exist, but updates it if it does.
I have got almost all the way there, but I'm having problems with updating the custom legend. I only seem to be able to append to it, and can't clear it.
This is my code:
var analyseMap = {
setUpMap: function(options) {
var _this = this;
L.mapbox.accessToken = 'mytoken';
if (typeof this.map === 'undefined') {
this.map = L.mapbox.map('map', 'mapbox.streets').setView([53.1, -2.2], 6);
this.layerGroup = L.layerGroup().addTo(this.map);
} else {
this.layerGroup.clearLayers();
}
var geojson_url = "/api/1.0/myurlbasedonoptions";
$.getJSON(geojson_url, function(boundaries) {
var orgLayer = L.geoJson(boundariesWithData, { style: getStyle });
_this.layerGroup.addLayer(orgLayer);
_this.map.fitBounds(orgLayer.getBounds());
var popup = new L.Popup({ autoPan: false });
var legendHtml = _this.getLegendHTML(options);
_this.map.legendControl.removeLegend();
_this.map.legendControl.addLegend(legendHtml);
Then I call it from another module like this:
// on initialise and update
map.setUpMap(someOptions);
This works just great the first time I call it. However, on update, the map updates and the layers update nicely, but I end up with two legends.
How can I clear the existing legend before adding the new one?
The documentation suggests that I need to know the value of the legend HTML in order to remove it, which seems strange.
OK, I fixed it by doing this:
if (typeof _this.legendHtml !== 'undefined') {
_this.map.legendControl.removeLegend(_this.legendHtml);
}
_this.legendHtml = _this.getLegendHTML(_this.quintiles, options);
_this.map.legendControl.addLegend(_this.legendHtml);
Would still be interested to see if anyone has a more elegant solution though!
Here is my function that I use to draw a Leaflet map in my website:
function drawTweetMap(points) {
if (tweetMap != null)
tweetMap.remove();
var london = [51.505, -0.09];
tweetMap = L.map('tweetMap').setView(london, 5);
var cloudmadeUrl = 'http://{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg';
var subDomains = ['otile1','otile2','otile3','otile4'];
var cloudmadeAttrib = 'Data, imagery and map information provided by MapQuest, OpenStreetMap and contributors, CC-BY-SA';
L.tileLayer(cloudmadeUrl,
{attribution: cloudmadeAttrib,
maxZoom: 18,
subdomains: subDomains})
.addTo(tweetMap);
var markers = L.markerClusterGroup();
var points_rand = L.geoJson(points, {onEachFeature: onEachFeature});
markers.addLayer(points_rand);
tweetMap.addLayer(markers);
tweetMap.fitBounds(markers.getBounds());
}
This function is called periodically:
mapWatch = setInterval(function() {
retrieveCurrentTweetPositions()},
numMinutes*60*1000);
in this function:
function retrieveCurrentTweetPositions() {
var points = retrieveCurrentPositions();
var mapInput = translatePointsInMapFormat(points);
drawTweetMap(mapInput);
}
Unfortunately, if the map is drawn in this way, the result is the following:
In other questions I found that it is possible to invalidate the size of the map to fix this problem, so it was suggested to call on startup this function:
function updateTweetMapPosition() {
setTimeout(function(){
tweetMap.invalidateSize(true);}
,500)
}
I did so, and this solves the problem during the first map drawing. However, when I try to redraw the map for a second time, the result is as follows:
Has anyone experienced this problem? How can I redraw the map with a full loading of its content?
Thanks.
EDIT
Here is the jsFiddle: http://jsfiddle.net/qzpwvqzk/
I solved the problem as follows
setTimeout(function(){map.invalidateSize(true);},500);
Use https://leafletjs.com/reference-1.7.1.html#map-invalidatesize
tweetMap.invalidateSize()
Take a look at the redraw() method.
a) the real joke first:
Finally buying Microsoft stuff over the years paid off..
Trying to debug using Chrome, my map was showing just one marker. It was on the correct latlng for the period of the setTimeout, blinks for a small fraction of second, back to same position.
At a certain time, shot code to Explorer by mistake....... voila... code iterates through the database, but does not use the setTimeout for each marker. At Explorer, setTime out (Ex, 5 seconds), means all the markers will show up, with the right infowindow, but it's 5 seconds for all markers. The longer the time, the longer it will stay in one of them (alwyas the same one), going really fast on the other markers. At chrome, the iteration was so fast I could not see the iteration thru the other latlng's. It was just a blink.
b) I guess the problem is that the getJson (or Ajax), using either for loop or $.each (I used all sorts of combinations.....) is combined with the other loop inside the function changeMarker. So there are two loops going on at the same time. However, I don't know how to fix it. If I close the Ajax (or getJson) right after the $.each or for loop, the rest of the code doesn't get the values. Nothing happens (just my alert, which is for debugging purposes).
No, I don't fully understand closures. Yes, I read a bunch of stuff, the main one here, but also here and here and there. but still didn't figure it out to :/
c) Not easy being a newbie, trying to solve a problem for days... and not getting it solved.
Any help will be greatly appreciated!
Here is the code - omitted a long section where map gets personal options.
var BERLIN = new google.maps.LatLng(-32.517683, -46.394393);
var map = null;
var marker = null;
var index = 0;
var infoWindow = null;
var latlng ;
var MY_MAPTYPE_ID = 'custom_style';
function initialize() {
//personal options not included here.
var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);
map.mapTypes.set(MY_MAPTYPE_ID, customMapType);
$.getJSON('php/locationsJson.php',function(json){
$.each( json, function(i, item) {
var lat = this.lat;
var lng = this.lng;
var location = new google.maps.LatLng(json[i].lat,json[i].lng);
alert( json[i].lat +','+json[i].lng );
function dropMarker (map, pos){
return new google.maps.Marker({
map: map,
position: location,
draggable: false,
}); // return
}
function changeMarker() {
if (marker) {
infoWindow.close();
marker.setMap(null);
}
var pos = location[index];
marker = dropMarker(map,pos);
var contentString = ('lat: ' + location.lat() + '<br />' + 'lng: ' + location.lng())
infoWindow.setContent(contentString);
setTimeout(function () {
infoWindow.open(map, marker);
}, 100);
index = (index + 1) % json.length;
setTimeout(function () {
changeMarker();
}, 4000);
}
var customMapType = new google.maps.StyledMapType(featureOpts, styledMapOptions);
infoWindow = new google.maps.InfoWindow()
changeMarker();
}); //$.each
}); //end of getjson
} //end of initialized
Here is fiddle (thanks for the help to get to that point) for the code BEFORE the AJAX. I tried to add the json file in the fiddle, but it's too complex to add json inside the fiddle.
Thank you again for your time.
As your approach in the fiddle works fine, you don't need much modifications to
achieve it via ajax.
Instead of starting the timeouts inside the loop use the loop only to populate the NEIGBORHOODS-array, and after the loop call changeMarker()
The success-callback for $.getJSON:
function(json){
NEIGBORHOODS=[];
$.each(json,
function(){
NEIGBORHOODS.push(new google.maps.LatLng(this.lat,this.lng));
});
changeMarker();
}
The rest of the code may stay as it is in the fiddle.
Working fiddle with ajax-request: http://jsfiddle.net/doktormolle/CVECG/
(Note: In the fiddle I've used $.post() because jsfiddle requires post-requests for JSON, you can use $.getJSON in your application)