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)
});
}
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 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();
}
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.
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)
Using the Google Maps JavaScript v3 API, is it possible to draw multiple separate polygons on the same map? And include a message box that appears after drawing each shape with an alert: 'Click rest to draw another'?
Yes, you are able to draw multiple polygons on the Map; check out the Drawing Library. If you want to display a message after completing one shape, you will want to define a listener function against the DrawingManager that listens for one of several possible completion event notifications:
google.maps.event.addListener(drawingMgr, 'overlaycomplete', function( event ){
var shape = event.overlay;
var path = shape.getPath(); //returns an MVCArray of LatLng instances
for ( var i = 0; i < path.length; i++ ) {
var lat = path.getAt(i).lat(); //Corrected as per MVCArray
var lng = path.getAt(i).lng(); //Corrected as per MVCArray
//do something with the data...
}
//put your message display code here
});
Within the function callback, you have access to the shape that was just completed. So in the code above, event.overlay will provide you with a direct reference to the shape. If we assume that the shape is a Polygon, you would then be able to access the shape's members directly, as shown above. The full set of Polygon members is documented here.
I put the whole code as worked for me :
enter code here
google.maps.event.addListener(drawingMgr, 'overlaycomplete', function( event ){
var shape = event.overlay;
var path = shape.getPath(); //returns an Array of LatLng
for ( var i = 0; i < path.length; i++ ) {
var lat = path.getAt(i).lat();
var lng = path.getAt(i).lng();
//do something with the data...
}
//put your message display code here
});