Leaflet: Force a map redraw from Layer extension - javascript

I am currently developing an extension to the L.TileLayer class, and from within the initialize method I would like to call a redraw on the map. My code looks like this:
L.TileLayer.NewLayerType = L.TypeLayer.extend({
_newLayerType: null,
initialize: function(file, options) {
var foo = new Foo(file, this, function(scope) {
...
scope.redraw();
});
L.Utils.setOptions(this, options);
},
...
});
The problem is, the scope.redraw() call does not work, nor does any other way of refreshing the map work outside of calling scope._map.zoomIn() and scope._map.zoomOut() immediately after. Is the redraw not working because the scope is a layer extension? What is the best way to do this?
Thanks

Related

Setting mapZoom programatically in highcharts doesn't work

I'm trying to create custom zoom in/out buttons and I've got it working except for the most important part, the zooming..
I've created a map chart like this:
$scope.chart = new Highcharts.Map(config);
Then I have two functions which run whenever you click on zoom in or out:
highcharts.zoomIn = function() {
$scope.chart.mapZoom(0.5);
};
highcharts.zoomOut = function() {
$scope.chart.mapZoom(2);
};
Setting the mapZoom of the chart doesn't give me an error nor does it do anything. I tried calling $scope.chart.redraw() afterwards but it didn't help either. Also saw that it already calls the redraw function in the source code of the mapZoom function.
I can't find any information on how to do this so what exactly am I doing wrong here?

HERE Maps API event delays

When panning a map with the HERE maps API, the 'mapviewchangeend' event is triggered a short time after the animation completes. This means that is difficult to synchronise, say, a Leaflet overlay without the overlaid objects lagging behind.
var map = new H.Map(document.getElementById('mapContainer'),
defaultLayers.normal.map, ...
var lMap = L.map('mapContainer', {zoomControl: false});
...
function onMapViewChange() {
lMap.setView(map.getCenter(), map.getZoom(), {animation: false});
}
map.addEventListener('mapviewchange', function () {
onMapViewChange();
});
map.addEventListener('mapviewchangeend', function () {
onMapViewChange();
});
Is there a way to remove this delay? I have experimented with different kinetic settings for H.mapevents.Behavior but so far without success.
I think you can hook into the sync events being fired by the the view model and the viewport. I seem to recall that these events fire synchronously when the map renders...
After some digging, I found the example showing something very similar on github:
maps-api-for-javascript-examples/ground-overlay

Leaflet - Event on tiles loading

I am currently developing a map-based application and need a way to get notified when Leaflet is pulling tiles from the TileProvider (which, in my case, is MapBox). I read the Leaflet documentation, especially the part with the TileLayer. Currently, I am using the following code to attach a tileload handler:
map.eachLayer(function (layer) {
layer.on('tileload', function(e) {
console.log(e);
});
});
Is there a better way to get the TileLayer of the current map? One problem with this approach is that I hook the handler to all layers (although only TileLayers will raise events, it is unclean to hook it too all layers). Or can I attach the handler directly to the map instance somehow?
Update
I initialize the map with the following MapBox code snippet:
map = L.mapbox.map( element, '...', mapOptions );
This automatically creates a TileLayer (and several other layers), attaches them to the map object and returns this object for later use.
Why not use tileload event directly on the tile layer, like this:
//create a variable to store the tilelayer
var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
//add the tileload event directly to that variable
osm.on('tileload', function (e) {
console.log(e);
});
If you've got a lot of L.mapbox.TileLayer instances and you don't want to add the eventhandler manually to each instance like Alexandru Pufan suggests in his answer you could still use a loop and Object's instanceof method:
map.eachLayer(function (layer) {
if (layer instanceof L.mapbox.TileLayer) {
layer.on('tileload', function(e) {
console.log(e);
});
}
});
After reading your comment on Alexandru's answer i'm guessing you only have one layer, then it would be best to add it manually to the instance, which is possible with L.mapbox.TileLayer like this:
var layer = L.mapbox.tileLayer(YOUR MAP ID);
layer.on('tileload', function(e) {
console.log(e);
});
var map = L.mapbox.map('mapbox', null, {
'center': [0, 0],
'zoom': 0,
'layers': [layer]
});

Google Maps inside Ember.js

I've successfully managed to get Google Maps rendering on my main page. I'm using the same technique for one of my inner pages.
var MapView = Ember.View.extend({
layoutName: 'pagelayout',
didInsertElement : function(){
var mapOptions = {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(this.$("#map").get(0),mapOptions);
this.set('map',map);
},
redrawMap : function(){
var newLoc = new google.maps.LatLng(this.get('latitude'), this.get('longitude'));
this.get('map').setCenter(newLoc)
}.observes('latitude','longitude')
});
However, it doesn't render. If I change it like so, it works but takes over the base html element.
this.$().get(0) /**from this.$('#map').get(0)**/
I'm quite stumped. Thinking that the problem might be that didInsertElement was being trigger way too early (I've understood it that the entire DOM for this View will be available when this event fires), I've tried setting up a afterRender listener and triggered the map load but that fails too. I've triple checked that the div exists.
Can someone please help me with this?
I ran the Google Maps init code from my console and found that the map did load so it seems to be an issue with how didInsertElement works with my setup. My understanding what that didInsertElement was called when the View was in the DOM but perhaps because I'm using layouts , it works differently.
I solved it by calling a separate view from within the div itself
{{#view "map"}}
and by creating a new View for the map.
var MapView = Ember.View.extend({
/**
Same as before
**/
});
This is just my solution that may be useful to others facing the same problem. If someone has a better solution, please add it so that I can verify and upvote it.
The this.$() might not be available as the view might not have rendered yet. Try wrapping it in a Ember.run.next call to delay the execution in the next run loop cycle:
didInsertElement: function() {
Ember.run.next(this, function() {
// your code
});
});

Edit existing Google Maps element

For a website I'm using Google Maps to add polylines to a map to display a route. Some routes consist of multiple legs (stages) and I'm trying to add the polylines 'on request'. So only if a user chooses to show a leg, it will draw the polyline. Also the user might choose a completely different route and this new set of polylines should be drawn on the map as well.
My problem is that I can't seem to figure out or find how to select an existing map. I start out by creating a map using the following code:
qMap = new google.maps.Map(document.getElementById(mP.target), mapOptions);
mP.target contains a string with the canvas id and mapOptions is just a object with some options, nothing special.
So I do all kind of stuff with qMap, like adding markers, drawing polylines etc. And this shouldn't just be done at map initiation, but also when the user wants to add something. qMap isn't a global variable and I rather not have it being a global either.
I've tried qMap = google.maps.Map(document.getElementById(mP.target)) and other similar methods. With no success. I'm hoping you can help me out finding a way to this without global variables! Thanks!
There are a couple of things you could try.
1) Wrap your code in an immediately invoked function. This way any variables are contained within the function's scope and don't escape to pollute the global variable space which I guess is your main concern.
(function () {
var mapGlobal = new google.maps.Map(target, options);
function thatDoesSomething(){
// do something with mapGlobal
}
}());
2) Use a static object which might be handy for organising your code.
var Map = {
map: new google.maps.Map(target, options),
thatDoesSomething: function () {
// do something with this.map
}
};
3) Or combine them.
(function () {
var Map = {
map: new google.maps.Map(target, options),
thatDoesSomething: function () {
// do something with this.map
}
};
}());

Categories