OpenLayers 2 has these layer events "loadstart & loadend."

What is equivalent to them in OpenLayers 3?

While a vector layer loads and is rendered, I need to show a loading icon.


Assuming you use an ol.layer.Vector with an ol.source.GeoJSON you can use something like this:

var vectorSource = new ol.source.GeoJSON({
  projection : 'EPSG:3857',
  url: 'http://examples.org/fearures.json'

var vectorLayer = new ol.layer.Vector({
  source: vectorSource


// show loading icon
// ...

var listenerKey = vectorSource.on('change', function(e) {
  if (vectorSource.getState() == 'ready') {
    // hide loading icon
    // ...
    // and unregister the "change" listener 
    // or vectorSource.unByKey(listenerKey) if
    // you don't use the current master branch
    // of ol3

This shows how to get a notification when the vector source is loaded. It only works with sources inheriting from ol.source.StaticVector. Examples include ol.source.GeoJSON and ol.source.KML .

Also, note that this code may no longer work in the future when ol3 will provide a consistent way to know if/when a source is loaded.

  • Great! I was looking for this too. Wondering why OL3 does not include it yet. – Germán Carrillo Feb 8 '15 at 16:40
  • Why not vectorSource.once('change', function(e){...}? – Jonatas Walker Jun 15 '15 at 13:11

In ol3 version 3.10.0 things have changed. So is more clear than older versions but still more complicated than ol2.

So for TILE (ol.layer.Tile) layers your code snip should look like:

//declare the layer
var osmLayer =  new ol.layer.Tile({
  source: new ol.source.OSM()
//asign the listeners on the source of tile layer
osmLayer.getSource().on('tileloadstart', function(event) {
//replace with your custom action
document.getElementById('tilesloaderindicatorimg').src = 'css/images/tree_loading.gif';

osmLayer.getSource().on('tileloadend', function(event) {
//replace with your custom action
document.getElementById('tilesloaderindicatorimg').src = 'css/images/ok.png';
osmLayer.getSource().on('tileloaderror', function(event) {
//replace with your custom action        
document.getElementById('tilesloaderindicatorimg').src = 'css/images/no.png';

while for WMS layers the approach is a bit different:

//declare the layer
var wmsLayer =   new ol.layer.Image({
source: new ol.source.ImageWMS({
  attributions: [new ol.Attribution({
    html: '© ' +
        '<a href="http://www.geo.admin.ch/internet/geoportal/' +
        'en/home.html">' +
        'National parks / geo.admin.ch</a>'
  crossOrigin: 'anonymous',
  params: {'LAYERS': 'ch.bafu.schutzgebiete-paerke_nationaler_bedeutung'},
  serverType: 'mapserver',
  url: 'http://wms.geo.admin.ch/'

//and now asign the listeners on the source of it
var lyrSource = wmsLayer.getSource();
  lyrSource.on('imageloadstart', function(event) {
  console.log('imageloadstart event',event);
  //replace with your custom action
  var elemId = event.target.params_.ELEMENTID;
  document.getElementById(elemId).src = 'css/images/tree_loading.gif'; 

  lyrSource.on('imageloadend', function(event) {
   console.log('imageloadend event',event);
  //replace with your custom action
  var elemId = event.target.params_.ELEMENTID;
  document.getElementById(elemId).src = 'css/images/ok.png'; 

  lyrSource.on('imageloaderror', function(event) {
   console.log('imageloaderror event',event);
  //replace with your custom action
  var elemId = event.target.params_.ELEMENTID;
  document.getElementById(elemId).src = 'css/images/no.png'; 

For WFS Vector layers things are even more complicated:

//declare the vector source
sourceVector = new ol.source.Vector({
    loader: function (extent) {
        //place here any actions on start loading layer
        document.getElementById('laodingcont').innerHTML = "<font color='orange'>start loading.....</font>";
        $.ajax('http://demo.opengeo.org/geoserver/wfs', {
            type: 'GET',
            data: {
                service: 'WFS',
                version: '1.1.0',
                request: 'GetFeature',
                typename: 'water_areas',
                srsname: 'EPSG:3857',
                bbox: extent.join(',') + ',EPSG:3857'
            .fail(function () {
            //FAIL LOADING
            //place here any actions on fail loading layer
            document.getElementById('laodingcont').innerHTML = "<font color='red'>error loading vector layer.</font>";
    strategy: ol.loadingstrategy.bbox

//once we have a success responce, we need to parse it and add fetaures on map
function loadFeatures(response) {
formatWFS = new ol.format.WFS(),
document.getElementById('laodingcont').innerHTML = "<font color='green'>finish loading vector layer.</font>";

check this post. it has all the above + a fiddle for the WFS vector layers

  • 1
    Welcome to GIS.SE! Can you please expand your answer and provide a short synopsis of the article you linked to and what part is relevant to the answer of this question. This way the answer will be able to help people on this site, even after the link dies. – Kersten Oct 13 '15 at 10:38
  • sorry newby. done!!!!!!!! – pavlos Oct 13 '15 at 10:56
  • to check which layer type you have, here is how you van do it for OL3 gis.stackexchange.com/a/140852/63141 – Daniël Tulp May 20 '16 at 9:00
  • This should be the top answer! – joaorodr84 Aug 2 '16 at 1:33
  • 1
    Please OL guys.... KISS man...KISS.... – Magno C Jan 24 '17 at 11:32

I have not found the class ol.source.GeoJSON, and could not find a case where vectorSource.getState() != 'ready'. So I ended up doing something like this:

    function spin(active) {
        if (active) {
            // start spinning the spinner
        } else {
            // stop spinning the spinner

    // Toggle spinner on layer loading
    layer.on('change', function() {
    layer.getSource().on('change', function() {
  • please also post the spin function, it looks like you are just spinning them and not stopping the spinning on finish loading the layer – Daniël Tulp May 20 '16 at 8:59

you can also use the getState() function

if (source instanceof ol.source.Vector) {
        source.on("change", function () {
            //console.log("Vector change, state: " + source.getState());
            switch (source.getState()) {
                case "loading":
  • I am using ol-v4.2.0. source.getState() always returns 'ready' – himyata Oct 26 '17 at 8:09

On OL 4.5.0, for vector layers I haven't found a way to deal with the source, instead I use the following on the layer events:

if (layer instanceof ol.layer.Vector) {
    layer.on("precompose", function () {
    layer.on("render", function () {

Hope it can help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.