How to switch KML layers using Knockout.js without having to recreate the map?

I created a knockout binding to be able to switch KML layers using Google Maps, but the solution seems a little slow and flickering. How can I avoid re-creating the map and layers every time I switch?

The demo works here

var ViewModel = function () { var self = this; self.mapOptions = { center: new google.maps.LatLng(60.390791, 5.306396), zoom: 2 }; self.levels = [{ text: "Type 1", countries: ko.observableArray([ 'https://dl.dropbox.com/u/2873968/countries-kml/afghanistan.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/algeria.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/bahrain.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/burundi.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/ca_republic.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/cameroon.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/chad.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/colombia.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/dr_congo.kml']), isVisible: ko.observable(false) }, { text: "Type 2", countries: ko.observableArray([ 'https://dl.dropbox.com/u/2873968/countries-kml/russia.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/sudan.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/syria.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/thailand.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/venezuela.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/yemen.kml', 'https://dl.dropbox.com/u/2873968/countries-kml/zimbabwe.kml']), isVisible: ko.observable(true) }]; }; ko.bindingHandlers.KML = { update: function (element, valueAccessor) { var data = ko.utils.unwrapObservable(valueAccessor()), mapOptions = ko.utils.unwrapObservable(data.mapOptions) || {}, levels = ko.utils.unwrapObservable(data.levels) || [], map = new google.maps.Map(element, mapOptions); for (var i = 0; i < levels.length; i++) { var level = levels[i], isVisible = level.isVisible(), text = level.text, countries = ko.utils.unwrapObservable(level.countries) || []; for (var y = 0; y < countries.length; y++) { var country = countries[y], layer = new google.maps.KmlLayer(country, { map: map, preserveViewport: true }); if (isVisible) { layer.setMap(map); } else { layer.setMap(null); } } } } }; ko.applyBindings(new ViewModel()); 
+7
javascript polygon google-maps kml
source share
1 answer

The first thing to do is at least use the init callback.

 ko.bindingHandlers.KML = { init: function (element, valueAccessor) { var data = ko.utils.unwrapObservable(valueAccessor()), mapOptions = ko.utils.unwrapObservable(data.mapOptions) || {}, levels = ko.utils.unwrapObservable(data.levels) || [], map = new google.maps.Map(element, mapOptions); // now that the map is created, create layers for each level in each country // set the layers visibility } } 

Then in the update callback you only need to update the visibility of the layers

 ko.bindingHandlers.KML = { init: function (element, valueAccessor) { }, update: function(element, valueAccessor){ // get data from valueAccessor // for each level, set visibility } } 

But now we do not have a map to use in the update callback. Fortunately, we can create our own objects inside our bindHanlder, so we will do this:

 ko.bindingHandlers.KML = { config : { map: {} }, init: function (element, valueAccessor) { var map = new google.maps.Map(element, mapOptions); // now we can store our map; ko.bindingHandlers.KML.config.map = map; }, update: function(element, valueAccessor){ // and use it in the update var map ko.bindingHandlers.KML.config.map; } } 

It also means that we can also define a model for our layer and allow this model to control visibility through the observable.

All this leads to the following jsFiddle example

+1
source share

All Articles