OpenLayers 2 trigger event when baselayer changes - event-handling

I want my application to do something when the base layer has changed.
Is it possible to handle/catch that event in OpenLayers 2?

Yes, it is possible:
map.events.register("changebaselayer", this, function (obj) {
if (obj.layer.name == 'layer_name') {
//do something if new base layer is equal to layer_name
....
}
});
You can see all the possible events you can hook into in the source for OpenLayers/Map.js although the actual event will be triggered by the LayerSwitcher.

Related

Does there exist a function to tell if the current tileLayer is **already** loaded?

I want to programmatically flyTo to a new location, then once arriving at the new location and the tiles in the new location are loaded, I would like to do the next step.
Using the load event does not work if the new location is very close to the origin, since they are already loaded, so no new load event would be fired. Nevertheless, the code still needs to handle whether the visible tiles are loaded, since it is possible that the new location is quite far from the origin.
How do I tell if the current tile layer is already loaded? Something like map.whenReady, which is fired immediately if the map is already ready, unlike tileLayer.on("load"), which won't be fired if the tile layer is already loaded.
Sample code that doesn't work:
map.on("moveend zoomend", function(){
baseLayer.on("load", function(){
// do something
});
});
map.flyTo(latlng);
If the tile layer is already loaded, the "load" event won't fire, and do something won't be executed.
What I would like to have:
map.on("moveend zoomend", function(){
baseLayer.whenLoaded(function(){
// do something
});
});
map.flyTo(latlng);
How to achieve this in Leaflet?
As already answered on github, it's easy to implement whenReady in your own code using Leaflet extension methods, like this:
L.GridLayer.include({
whenReady: function (callback, context) {
if (!this._loading) {
callback.call(context || this, {target: this});
} else {
this.on('load', callback, context);
}
return this;
},
});
This is not the most elegant solution, but I think you could solve your problem using TileLayer isLoading() method that returns true if any tile in the grid layer has not finished loading.
map.on("moveend zoomend", function(){
baseLayer.on("load", function(){
doSomething("load: YES");
});
if (!baseLayer.isLoading()) doSomething("load: NO");
});
function doSomething(info) {
alert("do something - " + info);
}

openui5 event Handler for orientationchange

Is there any openui5 event Handler for orientationchange and window resize ?
onInit: function() {
var data;
this.drawChart(data); // working fine
$( window ).resize(function() {
this.drawChart(data); // not working
});
},
drawChart: function(data) {
//code for draw chart
}
OpenUI5 has built-in functionality for detecting orientation change as well as when there is a responsive size change (desktop->tablet for example).
Take a look at sap.ui.Device.orientation's attachHandler event:
Registers the given event handler to orientation change events of the
document's window.
Here is an example of using sap.ui.Device.orientation.attachHandler:
sap.ui.Device.orientation.attachHandler(function(mParams) {
if (mParams.landscape) {
alert('in landscape mode');
} else {
alert('in portrait mode');
}
});
Also of use is sap.ui.Device.media's attachHandler for detecting when the window is resized to a different range-set.
For directly listening to when the window is resized it looks like you already have a solution for that, just make sure you keep track of the correct scope to use:
var self = this;
$( window ).resize(function() {
self.drawChart(data);
});
I found the solution
this.* will not work inside jquery as this has a different meaning wherever its encapsulated...
in openui5 *.view.js this implies the view object
in *.controller.js this implies the controller object...
in jquery this implies the component in which it is placed or whatever it is referring to in that context...
you cannot simply mix "this" wherever you like
sap.ui.controller("oui5mvc.controllerName").drawChart(data);

Having trouble attaching event listener to a kml layer's polygon

Using Google Earth I have a loaded kml layer that displays polygons of every county in the US. On click a balloon pop's up with some relevant info about the state (name, which state, area, etc) When a user clicks the polygon I want the information to also pop up on a DIV element somewhere else.
This is my code so far.
var ge;
google.load("earth", "1");
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
ge.getNavigationControl().setStreetViewEnabled(true);
ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);
//here is where im loading the kml file
google.earth.fetchKml(ge, href, function (kmlObject) {
if (kmlObject) {
// show it on Earth
ge.getFeatures().appendChild(kmlObject);
} else {
setTimeout(function () {
alert('Bad or null KML.');
}, 0);
}
});
function recordEvent(event) {
alert("click");
}
// Listen to the mousemove event on the globe.
google.earth.addEventListener(ge.getGlobe(), 'click', recordEvent);
}
function failureCB(errorCode) {}
google.setOnLoadCallback(init);
My problem is that when I change ge.getGlobe() to kmlObject or ge.getFeatures() it doesn't work.
My first question is what should I change ge.getGlobe() to to be able to get a click listener when a user clicks on a kml layer's polygon?
After that I was planning on using getDescription() or getBalloonHtml() to get the polygons balloons information. Am I even on the right track?
...what should I change ge.getGlobe() to...
You don't need to change the event object from GEGlobe. Indeed it is the best option as you can use it to capture all the events and then check the target object in the handler. This means you only have to set up a single event listener in the API.
The other option would be to somehow parse the KML and attach specific event handlers to specific objects. This means you have to create an event listener for each object.
Am I even on the right track?
So, yes you are on the right track. I would keep the generic GEGlobe event listener but extend your recordEvent method to check for the types of KML object you are interested in. You don't show your KML so it is hard to know how you have structured it (are your <Polygon>s nested in <Placemarks> or ` elements for example).
In the simple case if your Polygons are in Placemarks then you could just do the following. Essentially listening for clicks on all objects, then filtering for all Placmark's (either created via the API or loaded in via KML).
function recordEvent(event) {
var target = event.getTarget();
var type = target.getType();
if(type == "KmlPolygon") {
} else if(type == "KmlPlacemark") {
// get the data you want from the target.
var description = target.getDescription();
var balloon = target.getBalloonHtml();
} else if(type == "KmlLineString") {
//etc...
}
};
google.earth.addEventListener(ge.getGlobe(), 'click', recordEvent);
If you wanted to go for the other option you would iterate over the KML Dom once it has loaded and then add events to specific objects. You can do this using something like kmldomwalk.js. Although I wouldn't really recommend this approach here as you will create a large number of event listeners in the api (one for each Placemark in this case). The up side is that the events are attached to each specific object from the kml file, so if you have other Plaemarks, etc, that shouldn't have the same 'click' behaviour then it can be useful.
function placeMarkClick(event) {
var target = event.getTarget();
// get the data you want from the target.
var description = target.getDescription();
var balloon = target.getBalloonHtml();
}
google.earth.fetchKml(ge, href, function (kml) {
if (kml) {
parseKml(kml);
} else {
setTimeout(function () {
alert('Bad or null KML.');
}, 0);
}
});
function parseKml(kml) {
ge.getFeatures().appendChild(kml);
walkKmlDom(kml, function () {
var type = this.getType();
if (type == 'KmlPlacemark') {
// add event listener to `this`
google.earth.addEventListener(this, 'click', placeMarkClick);
}
});
};
Long time since i have worked with this.. but i can try to help you or to give you some tracks...
About your question on "google.earth.addEventListener(ge.getGlobe(), 'click', recordEvent);"
ge.getGlobe can not be replaced with ge.getFeatures() : if you look in the documentation ( https://developers.google.com/earth/documentation/reference/interface_g_e_feature_container-members) for GEFeatureContainer ( which is the output type of getFeatures() , the click Event is not defined!
ge.getGlobe replaced with kmlObject: waht is kmlObject here??
About using getDescription, can you have a look on the getTarget, getCurrentTarget ...
(https://developers.google.com/earth/documentation/reference/interface_kml_event)
As I told you, i haven't work with this since a long time.. so I'm not sure this can help you but at least, it's a first track on which you can look!
Please keep me informed! :-)

What is the proper way in OpenLayers (OSM) to trigger a popup for a feature?

I have the feature ID, I can grab the marker layer on GeoRSS loadend, but I'm still not sure how to cause the popup to appear programmatically.
I'll create the popup on demand if that's necessary, but it seems as though I should be able to get the id of the marker as drawn on the map and call some event on that. I've tried using jQuery and calling the $(marker-id).click() event on the map elements, but that doesn't seem to be working. What am I missing?
Since I was asked for code, and since I presumed it to be boilerplate, here's where I am so far:
map = new OpenLayers.Map('myMap');
map.addLayer(new OpenLayers.Layer.OSM());
map.addLayer(new OpenLayers.Layer.GeoRSS(name,url));
//I've done some stuff as well in re: projections and centering and
//setting extents, but those really don't pertain to this question.
Elsewhere I've done a bit of jQuery templating and built me a nice list of all the points that are being shown on the map. I know how to do a callback from the layer loadend and get the layer object, I know how to retrieve my layer out of the map manually, I know how to iter over the layers collection and find my layer. So I can grab any of those details about the popup, but I still don't know how to go about using the built-in methods of the DOM or of this API to make it as easy as element.click() which is what I would prefer to do.
You don't have to click the feature to open a popup.
First you need a reference to the feature from the feature id. I would do that in the loadend event of the GeoRSS layer, using the markers property on the layer.
Assuming you have a reference to your feature, I would write a method which handles the automatic popup:
var popups = {}; // to be able to handle them later
function addPopup(feature) {
var text = getHtmlContent(feature); // handle the content in a separate function.
var popupId = evt.xy.x + "," + evt.xy.y;
var popup = popups[popupId];
if (!popup || !popup.map) {
popup = new OpenLayers.Popup.Anchored(
popupId,
feature.lonlat,
null,
" ",
null,
true,
function(evt) {
delete popups[this.id];
this.hide();
OpenLayers.Event.stop(evt);
}
);
popup.autoSize = true;
popup.useInlineStyles = false;
popups[popupId] = popup;
feature.layer.map.addPopup(popup, true);
}
popup.setContentHTML(popup.contentHTML + text);
popup.show();
}
fwiw I finally came back to this and did something entirely different, but his answer was a good one.
//I have a list of boxes that contain the information on the map (think google maps)
$('.paginatedItem').live('mouseenter', onFeatureSelected).live('mouseleave',onFeatureUnselected);
function onFeatureSelected(event) {
// I stuff the lookup attribute (I'm lazy) into a global
// a global, because there can be only one
hoveredItem = $(this).attr('lookup');
/* Do something here to indicate the onhover */
// find the layer pagination id
var feature = findFeatureById(hoveredItem);
if (feature) {
// use the pagination id to find the event, and then trigger the click for that event to show the popup
// also, pass a null event, since we don't necessarily have one.
feature.marker.events.listeners.click[0].func.call(feature, event)
}
}
function onFeatureUnselected(event) {
/* Do something here to indicate the onhover */
// find the layer pagination id
var feature = findFeatureById(hoveredItem);
if (feature) {
// use the pagination id to find the event, and then trigger the click for that event to show the popup
// also, pass a null event, since we don't necessarily have one.
feature.marker.events.listeners.click[0].func.call(feature, event)
}
/* Do something here to stop the indication of the onhover */
hoveredItem = null;
}
function findFeatureById(featureId) {
for (var key in map.layers) {
var layer = map.layers[key];
if (layer.hasOwnProperty('features')) {
for (var key1 in layer.features) {
var feature = layer.features[key1];
if (feature.hasOwnProperty('id') && feature.id == featureId) {
return feature;
}
}
}
}
return null;
}
also note that I keep map as a global so I don't have to reacquire it everytime I want to use it

jQuery live with the ready or load event

I'm using the jQuery Tools tooltip plugin, which is initialized with $('selector').tooltip(). I'd like to call this on any current or future .tooltipper element. I figured that the following would work:
$('.tooltipper').live('ready', function(){
$(this).tooltip()
}
But it was unsuccessful---the ready event did not fire. The same for load. I've read that livequery can produce the result of I'm looking for, but surely there is a way to use jQuery .live() to pull it off, considering the documentation says that it works for all jQuery events, of which I believe ready is one.
Quoted from the jQ API (http://api.jquery.com/live/):
In jQuery 1.3.x only the following JavaScript events (in addition to custom events) could be bound with .live(): click, dblclick, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, and mouseup.
As of jQuery 1.4 the .live() method supports custom events as well as all JavaScript events.
As of jQuery 1.4.1 even focus and blur work with live (mapping to the more appropriate, bubbling, events focusin and focusout).
As of jQuery 1.4.1 the hover event can be specified (mapping to "mouseenter mouseleave").
.live() does not appear to support the ready event.
To add to HurnsMobile's excellent answer; Looking at bindReady(), which is the internal call that jQuery makes to bind to the document load event every time you call $(some_function) or $(document).ready(some_function) we see why we cannot bind to "ready":
bindReady: function() {
if ( readyBound ) {
return;
}
readyBound = true;
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
return jQuery.ready();
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", DOMContentLoaded);
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) { //and silently drop any errors
}
// If the document supports the scroll check and we're not in a frame:
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
}
To sum it up, $(some_function) calls a function which binds to:
DOMContentLoaded
onreadystatechange (DOMContentLoaded)
window.load / onload
Your best bet would be to bind to those actions that might create new .tooltipper elements, rather than trying to listen for the ready event (which happens only once).
HurnsMobile is right. JQuery live does not support the ready-event.
This is why I created a plugin that combines the two. You register your callback once, and then you will need to call the plugin once for content you add manually.
$.liveReady('.tooltipper', function(){
this.tooltip()
});
Then when creating new content:
element.html(somehtml);
element.liveReady();
or
$('<div class="tooltipper">...').appendTo($('body')).liveReady();
A demo is available here: http://cdn.bitbucket.org/larscorneliussen/jquery.liveready/downloads/demo.html
Check out the introductory post here: http://startbigthinksmall.wordpress.com/2011/04/20/announcing-jquery-live-ready-1-0-release/
Also have a look at http://docs.jquery.com/Plugins/livequery, which listenes for changes on the dom.