Converting JSON values to an array - javascript

I working with leaflet maps and html5 geolocation. I have a view that receives coords from a node.js server and adds markers for each unique id and updates their positions as new coords come in. I'm storing the marker objects in an object, the IDs as the keys, the markers as the values. So the markers object looks like this when tracking two devices:
Object {qwpW9K0L1OtOhsV3CF0G: e, syeQs_oH7s8z8f0UCF0I: e}
Where the e is an actual marker.
The problem I'm working on is that the leaflet api likes to receive arrays of data. For example, I'd like to fit the map view bounds to the markers using a feature group and map.fitBounds(...). So i'm iterating through the object and pushing the markers into a new array and updating the map bounds every time a new marker is created or new coords come in and it seems extremely inefficient and just plain the wrong way to do it.
Complete socket.io code block I'm working on:
socket.on('markerCoords', function(data) {
var markerGroup = [];
if(data.id in markers) {
markers[data.id].setLatLng([data.data.latitude, data.data.longitude]);
$.each(markers, function(i, e) {
markerGroup.push(e);
});
var group = new L.featureGroup(markerGroup);
map.fitBounds(group.getBounds().pad(0.5));
} else {
var marker = L.marker([data.data.latitude, data.data.longitude], {"title": data.id, "draggable": true}).addTo(map);
markers[data.id] = marker;
$.each(markers, function(i, e) {
markerGroup.push(e);
});
var group = new L.featureGroup(markerGroup);
map.fitBounds(group.getBounds().pad(1.0));
}
});

Looks like one possible solution is to simply create the feature group only once and updated it when necessary:
var group = new L.featureGroup();
socket.on('markerCoords', function(data) {
var markerGroup = [];
if(data.id in markers) {
markers[data.id].setLatLng([data.data.latitude, data.data.longitude]);
map.fitBounds(group.getBounds().pad(0.5));
} else {
markers[data.id] = L.marker(
[data.data.latitude, data.data.longitude],
{"title": data.id, "draggable": true}
).addTo(map);
group.addLayer(markers[data.id]);
map.fitBounds(group.getBounds().pad(1.0));
}
});
You could probably also just add the group to the map once on startup, not every marker individually.

Related

Creating MapKit JS with origin, destination and waypoints

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.

How to remove old map markers and update new in Google Maps [duplicate]

This question already has answers here:
Google Map API - Removing Markers
(5 answers)
Closed 3 years ago.
I'm creating an application which gets the real-time location and renders to Google Map. After a specific time interval, I have to remove old markers and need to render the udpated markers.
Below is my code
function initMap(rtl_data) {
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
var latlng = new google.maps.LatLng(24.238162, 45.156379);
var myOptions = {
zoom: 7,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var marker = []
var map = new google.maps.Map(document.getElementById("map"),myOptions);
directionsDisplay.setMap(map);
makeMarkers(rtl_data)
function makeMarkers(rtl_data){
// Drivers Location Markers
deleteMarkers()
features = []
marker = []
drivers_latlng = rtl_data.drivers_latest_location
drivers_latlng.forEach(function(e){
features.push({
position: new google.maps.LatLng(e.lat, e.lng),
type: e.order_id,
title: e.driver_id,
description: e.order_id ? "Ongoing order: "+e.order_id : "No order assigned."
})
})
image = "/files/truck.png"
infoWindow = new google.maps.InfoWindow();
for (i = 0; i < features.length; i++) {
marker = new google.maps.Marker({
position: features[i].position,
map: map,
title: features[i].title,
type: features[i].type,
icon: image,
description: features[i].description
});
//Attach click event to the marker.
(function (marker) {
google.maps.event.addListener(marker, "click", function (e) {
//Wrap the content inside an HTML DIV in order to set height and width of InfoWindow.
infoWindow.setContent("<div style = 'width:200px;min-height:40px'>" + marker.description + "</div>");
infoWindow.open(map, marker);
});
})(marker);
}
// Sets the map on all markers in the array.
function setMapOnAll(map) {
for (var i = 0; i < marker.length; i++) {
marker[i].setMap(map);
}
}
// Removes the markers from the map, but keeps them in the array.
function clearMarkers() {
setMapOnAll(null);
console.log('clearMarkers')
}
// Shows any markers currently in the array.
function showMarkers() {
setMapOnAll(map);
}
// Deletes all markers in the array by removing references to them.
function deleteMarkers() {
console.log('deleteMarkers')
clearMarkers();
marker = [];
}
}
// Fetch Realtime using time interval
setInterval(function() {
frappe.call({ // Simple AJAX Call which returns locations and location realated data.
method: "get_drivers_locations",
async: false,
callback: function(r){
rtl_data = r.message
}
})
makeMarkers(rtl_data)
}, 5000);
I already used Method's which is used in the documentaion by Google Map.
Using ClearMarkers the old markers get cleared. But in my case it is not working.
When I run above code it displaying me both old and upadted markers.
See below screenshot which is repetating markers with updated locations.
You initialize marker as an array:
var marker = []
But later assign a Marker instance:
marker = new google.maps.Marker({...})
I didn't run your example, but I expect, that marker variable will contain not an array of markers, but the last created marker.
Try to do next:
rename marker variable to markers
implement addMarker function. This function should push a new marker to markers array
After reading below thread:
Google Map API - Removing Markers
I found the solution.
I created one array.
gmarkers = []
and pushed all my new markers in it.
gmarkers.push(marker)
To delete the markers I used the following function.
function setMapOnAll(map) {
for (var i = 0; i < gmarkers.length; i++) {
gmarkers[i].setMap(map);
}
}
Your closure bracket for the init function is wrong. If you look at the original documentation the init function is closed before the addmarker function. In your example it is closed just before the setInterval. So your setInterval probably can't even access the makeMarker function because this one is inside another function.

Bing Maps Api clear a layer

I have a page that works well it loads a Bing Map and creates a layer which is then filled with Polygons. I then need to reload the JSON data that makes the polygons and this again works, however the data is then added to another layer so appears over the top. I have tried to delete the layer, clear the layer etc etc but nothing seems to work.
Any idea please.
This is the function that does it all...
function AddData() {
dataLayer = new Microsoft.Maps.Layer();
Microsoft.Maps.loadModule('Microsoft.Maps.GeoJson', function () {
var featureCollection = Microsoft.Maps.GeoJson.read(json, {
polygonOptions: {
strokeColor: 'LightSkyBlue',
strokeThickness: 2
}
});
for (var i = 0; i < featureCollection.length; i++) {
var fillColour = featureCollection[i].metadata.FillColor;
featureCollection[i].setOptions({ fillColor: fillColour });
Microsoft.Maps.Events.addHandler(featureCollection[i], 'click', displayClickBox);
Microsoft.Maps.Events.addHandler(featureCollection[i], 'mouseover', displayMouseOverBox);
Microsoft.Maps.Events.addHandler(featureCollection[i],'mouseout', displayMouseOut);
dataLayer.add(featureCollection[i], 0);
}
map.layers.insert(dataLayer);
});
}
var getJson = function () {
var onContentComplete = function (response) {
//Load the JSON data into the local variable for use latter in the project...
json = response.data;
//load the map now that we have the polygon data...
AddData();
};
var onError = function (reason) {
//An error has occured so display a message to the user...
$scope.error = "Server communication error please try again...";
//Log the error to the console for admin debug...
console.log(reason.data);
};
//Load the JSON for the map polygons into memory ready for display...
$http.get("../JSON/MapData.json")
.then(onContentComplete, onError);
}
As I have said I have tried to clear the layer first using
dataLayer.clear();
But that seems to do nothing.
Help please as I have been working at this for hours now.
Thanks
Cliff.
By the sounds of things you want all data to render in a single layer, but instead it is rendering two or more layers. This happens because you are creating a new instance of dataLayer every time the AddData function is called. Additionally, this overwrites the local variable for dataLayer and thus you lose the reference to the original layer that you are trying to clear/delete. If you want to clear or delete the layer, do that before initializing the new layer. Try adding the following to the top of your AddData function:
if(dataLayer){
map.layers.remove(dataLayer);
}
Alternatively, reuse the layer by clearing it if it exists of or creating it if it doesn't:
if(dataLayer){
dataLayer.clear();
}else{
dataLayer = new Microsoft.Maps.Layer();
}

Google map marker update with AJAX

I had this working when data was coming from static factory. Now data comes in from an AJAX call ($http) from a remote server and for some reason markers dont get put on the map.
Working plunker
Basically if I uncomment $http and replace the static data, it will not show up. It will show variable markers filled with right data, just wont populate the map
Kind of similar issue
i mean setting mode.state to true after the markers are loaded:
$scope.mode.state = false;
$scope.change_type = function(val) {
var markers = [];
$scope.eventMarkers = markers // clear the map of markers, before loading new
Events.venues(val.type).then(function(resp){
var venues = $.map(resp.data, function(value, index){return [value]})
for (var i = 0; i < venues.length; i++) {
event = venues[i]
markers.push(createMarker(i,event))
}
console.log(markers)
$scope.eventMarkers = markers
$scope.mode.state = true;
}, function(errror){
console.debug(error)
});
}

Storing javascript data in global array not working as expected [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
change global variable inside javascript closure
I am having a problem storing data in a javascript global array . I can't figure out why the array is empty even though I have assigned it some elements.
Basically I have two functions: loadMarkers is called whenever a user clicks a button and gets some information from a url in JSON, parses that data and stores it in the global array. The other function is showMarkers that just iterates over the array and show all the markers, but that array is empty!
Thansks in advance.
var markers = [];
function loadMarkers(url) {
markers = [];
$.get(url, function(data) {
var json = jQuery.parseJSON(data);
for (var i = 0; i < json.length; i++) {
// parsing json
var lat = json[i].Latitude;
var lng = json[i].Longitude;
var id = json[i].ID;
console.log(id); // this prints with no problems!
// create new marker
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
title: id,
html: "<p>" + "Info for container " + id + "</p>"
});
// add marker to markers array
markers.push(markers[i]);
// add info window to marker
google.maps.event.addListener(marker, "click", function() {
infoWindow.setContent(this.html);
infoWindow.open(map, this);
});
}
});
}
function showMarkers() {
for (i = 0; i < markers.length; i++)
console.log(markers); // here I get an empty array!
markers[i].setMap(map);
}
It seems like this line:
markers.push(markers[i]);
should instead be:
markers.push(marker);
Maybe its the following code
// add marker to markers array
markers.push(marker); // was markers[i]
Regarding your second question in the comments the $.get() method returns a jQuery deferred object which allows you to execute functions after method has finished.
$.get().done( function( ) {
// your code
});
There's a typo in the code:
markers.push(markers[i]);
should be:
markers.push(marker);
It can be surprisingly hard to spot this kind of typos by just looking at the code (it's like our brains are trained to let us read what we expect to read)... In this case the best approach to find quickly these kind of errors is to add a debugger; instruction in the code, and follow along the execution of the program through the devtools of your choice.

Categories

Resources