Im polling data from my web api to populate a map with markers. The markers has positions, and Im saving the markers in the following way
allMarkers: Map<Number, Leaflet.Marker> = new Map();
At the moment I am refreshing the markers each time I poll my data, which is every 10 seconds. What I would like to do is to only refresh the markers who's position has actually changed. Is there any effecient way I can do that? I tried to use a "oldAllMarkers" and "newAllMarkers" but it didn't do much.
See my code below and please let me know if there is anything I should add to make things for clear.
// ngOnInit with a bunch of things. Here is where I set up my map and poll
// my data with the use of my subscribeToData function.
ngOnInit() {
// Init map
this.map = new Leaflet.Map('mapid', {}).setView([this.lng, this.lat], 10);
this.tiles = new Leaflet.TileLayer(
,
{
attribution: `Map data © OpenStreetMap contributors,
CC-BY-SA,
Imagery © Mapbox`,
maxZoom: 18,
minZoom: 1,
id: 'mapbox.streets',
accessToken:
}
).addTo(this.map);
// init vehicles details
this.store.select(fromStore.getAllVehicleDetails).subscribe(data => {
this.vehicleDetails = data;
this.setMarkers(this.selected);
// set the selected vehicle
this.vehicleDetail = this.getVehicleDetail(this.selected);
// set/refresh the markers
this.setMarkers(this.selected);
});
this.store.dispatch(new fromStore.LoadVehicleDetails());
this.subscribeToData();
}
setMarkers(id: number) {
for (let i = 0; i < this.vehicleDetails.length; i++) {
// Refresh markers
if (this.allMarkers.get(this.vehicleDetails[i].id)) {
const tempMarker = this.allMarkers.get(this.vehicleDetails[i].id);
this.allMarkers.delete(this.vehicleDetails[i].id);
if (tempMarker) {
this.map.removeLayer(tempMarker);
console.log('refresh map marker');
}
}
// Creating the markers
this.getIcon(this.vehicleDetails[i], status);
// set markers to our hashpmap.
if (this.markers) {
this.allMarkers.set(this.markers.options.vehicleId, this.markers);
}
}
// hide progress bar
this.loading = false;
}
}
Related
i need to display multi marker in leaflet map using vuejs. and i also need to chcnge marker image i have given code below only for single maker.
mounted () {
// L.Icon.Default.imagePath = 'assets/vendor/leaflet' TODO: make it work with webpack
Leaflet.Icon.Default.imagePath = 'https://unpkg.com/leaflet#1.0.3/dist/images'
let map = Leaflet.map(this.$refs['mapElement']).setView([51.505, -0.09], 13)
Leaflet.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
}).addTo(map)
Leaflet.marker([51.5, -0.09]).addTo(map)
.openPopup()
},
below is my api output data
[[51.4, -0.03],[53.5, -0.39],[52.5, -0.39]]
I believe you can use the solution here with your API output.
var res = [[51.4, -0.03],[53.5, -0.39],[52.5, -0.39]];
for (var i = 0; i < res.length; i++) {
marker = new L.marker(res[i])
.addTo(map);
}
Hope that answers your question.
So as the title says, I'm using React and trying to implement Google Maps with list of places fetched from Foursquare and display their markers. I'm not using any packages such as react-google-maps etc, just vanilla JS. The map loads just fine, the places are fetched BUT the markers show every now and then. When they do load, they point to correct location but they load rarely. I'm not sure what's wrong with my createMarkers function here:
// Initialize map
initMap = () => {
let map = new window.google.maps.Map(document.getElementById("map"), {
zoom: 14,
center: {lat: 45.5616873, lng: 18.6770196 }
});
this.createMarkers(map);
}
// The following function uses the places array to create an array of markers on initialize.
createMarkers = (map) => {
for (let i = 0; i < this.state.places.length; i++) {
// Get the position from the location array
let position = this.state.places[i].location;
let name = this.state.places[i].name;
let venueID = this.state.places[i].venueID;
// Create a marker per location, and put into markers array.
let marker = new window.google.maps.Marker({
position: position,
name: name,
animation: window.google.maps.Animation.DROP,
icon: this.state.defaultIcon,
venueID: venueID,
map: map
});
// Set state to save the marker to our array of markers.
this.setState((state) => ({
markers: [...state.markers, marker]
}))
}
}
// Create default marker icon
makeMarkerIcon(markerColor) {
const markerImage = new window.google.maps.Icon(
'http://chart.googleapis.com/chart?chst=d_map_spin&chld=1.15|0|'+ markerColor +
'|40|_|%E2%80%A2',
new window.google.maps.Size(21, 34),
new window.google.maps.Point(0, 0),
new window.google.maps.Point(10, 34),
new window.google.maps.Size(21,34)
);
return markerImage;
};
Any help would be much appreciated, as I'm still new to React and prone to beginner's mistakes.
I want to track driver vehicles so that i am using pubnub service
Library : https://github.com/pubnub/eon-map (suggested by pubnub support team)
I set one socket to get latitude and longitude from drivers mobile devices every 30 seconds and using that values i showing markers on my admin dashboard map.
Here is my code:
// socket connection code is write here and socket is connected successfully
var pn = new PubNub({
publishKey: 'pub-adsasdasd',
subscribeKey: 'sub-asdasdadasdas'
});
var channel = 'eon-maps-geolocation-input';
var map = eon.map({
pubnub: pn,
id: 'map',
mbId: 'ianjennings.l896mh2e',
mbToken: 'pk.eyJ1IjoiaWFuamVubmluZ3MiLCJhIjoiZExwb0p5WSJ9.XLi48h-NOyJOCJuu1-h-Jg',
channels:[channel],
options: {
center: new L.LatLng(31.0461,34.8516),
zoom: 8
},
provider: 'google',
googleKey: 'AIzaSyBYcy2l0Yf4lDADZ_i6dy0M6pFZyPQA',
connect: connect
}
});
function connect() {
socket.on('showrows', function(locations) {
// console.log(locations);
var arr = [];
locations.forEach(function(i, v) {
if (i[2] != null) {
var obj = {};
obj['latlng'] = [i[2], i[3]];
arr.push(obj);
}
});
var new_torchys = JSON.parse(JSON.stringify(arr));
for (var i = 0; i < new_torchys.length; i++) {
new_torchys[i] = {
marker: new_torchys[i].marker,
latlng: [
new_torchys[i].latlng[0],
new_torchys[i].latlng[1]
],
}
}
pn.publish({
channel: channel,
message: new_torchys
});
});
}
Above code displays marker successfully but i am not able to set info window while click on marker.
I write this code in for loop
var marker = L.marker([new_torchys[i].latlng[0], new_torchys[i].latlng[1]]).addTo(map);
marker.bindPopup("<b>Hello world!</b><br>I am a popup.");
But marker layer is overlay and map looks very bad.
I also want real time location while driver moving.
Please help me how to do this???
There is a callback function that can be passed to eon.map called marker. Within this function, create an instance of a mapbox icon, bind a popup to it, and then return it.
var channel = 'eon-maps-geolocation-input';
eon.map({
pubnub: pubnub,
id: 'map',
mbToken: 'pk.eyJ1IjoiaWFuamVubmluZ3MiLCJhIjoiZExwb0p5WSJ9.XLi48h-NOyJOCJuu1-h-Jg',
mbId: 'ianjennings.l896mh2e',
channels: [channel],
connect: connect,
options: {
zoomAnimation: false,
},
marker: function (latlng, data) {
var marker = new L.marker(latlng, {
icon: L.mapbox.marker.icon()
})
.bindPopup('<button class="trigger">Say hi</button>');
return marker;
}
});
If you are sending the geolocation from the device every 30 seconds, the map will automatically update as soon as the location is PubNub published on your specified channel eon-maps-geolocation-input
pn.publish({
channel: channel,
message: new_torchys
});
For Mapbox icon help refer to their docs https://www.mapbox.com/mapbox.js/example/v1.0.0/clicks-in-popups/
For an in depth guide for location tracking with EON, check out this https://github.com/pubnub/eon-workshop/tree/master/lesson3
Was wondering if anyone has any experience or could help with the logic, to track a user (car) with Bing maps
As the user travels a line should be drawn of their journey, but snap to roads, the way I have things set at the moment, lines will be drawn through buildings.
Because whenever there is an update to the position, 2 points are calculated and a line is added to the map
(At the moment am using watchPosition but in future will get position every 30 seconds)
watchPos() {
let options = { timeout: 60000 }
this.watchId = navigator.geolocation.watchPosition((position) => {
this.lat = position.coords.latitude;
this.lng = position.coords.longitude;
this.setMap()
console.log(this.lat, this.lng)
}, this.errorHandler, options);
}
setMap() {
this.loc = new Microsoft.Maps.Location(this.lat, this.lng);
if (!this.initialised) {
this.oldLoc = this.loc;
this.initialised = true
this.map = new Microsoft.Maps.Map(this.driveMap.nativeElement, {
credentials: CONFIG.BING_API_KEY,
center: this.loc,
mapTypeId: Microsoft.Maps.MapTypeId.road,
navigationBarMode: 2,
zoom: this.zoom
});
this.user = new Microsoft.Maps.Pushpin(this.loc, { icon: '../images/icon.svg' });
this.map.entities.push(this.user);
// console.log(loc)
} else {
// Draw line
// from this.oldLoc to this.loc
let lineVertices = new Array(this.oldLoc, this.loc);
let line = new Microsoft.Maps.Polyline(lineVertices);
// Then set oldLoc to new loc
this.oldLoc = this.loc
this.map.entities.push(line);
this.map.setView({
center: this.loc
});
this.user.setLocation(this.loc);
}
}
Bing Maps has a snap to road API coming out near the end of next week which is specifically designed for this. You pass in your GPS coordinates and it will snap it to the roads, additionally, if you pass in an array of points you can also have it return a logical path that passes through the snapped points. Watch the Bing Maps blog for the announcement: https://blogs.bing.com/maps
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.