TDesjardins / gwt-ol

GWT wrapper for OpenLayers 3+ using JSInterop
Apache License 2.0
70 stars 33 forks source link

undesired flickering effect changing external image on Vector layer #163

Closed Magallo closed 4 years ago

Magallo commented 4 years ago

This is not a real issue, it is more a support request to understand how to properly implement a specific feature.

My need is to use a Vector layer specifying an external graphic image url (a .png image). When I have used GWT-OpenLayers library I implemented this using the setExternalGraphic() method of the Style class. This way:

//refresh the image
VectorFeature[] features = m_VectorLayer.getFeatures();
Style vecStyle = features[0].getStyle();
vecStyle.setExternalGraphic("<the url of the new image to show on the layer>");
m_VectorLayer.redraw();

Using gwt-ol all the classes are different and most of the features are implemented in a different way.

I'm trying to achieve the same goal using the setStyle() method of the ol.layer.Vector class. This way:

StyleOptions styleOptions = new StyleOptions();
IconOptions iconOptions = new IconOptions();
iconOptions.setSrc("<the url of the new image to show on the layer>");
ol.style.Image image = new Icon(iconOptions);
styleOptions.setImage(image);
ol.style.Style theStyle = new Style(styleOptions);
m_VectorLayer.setStyle(theStyle);

This works as expected but unfortunately there is an undesired 'flickering' effect while changing the images. There is a moment where no images are shown and after a very small amount of time the new image appears on screen. This "very small amount of time" produces in any way a bad 'blink' effect.

In another part of my program I use also an ol.layer.Image implementing a very similar thing. In this case I change the image using a different strategy and in this case the flickering effect does not appear. In this case the change of the image is 'smooth' and nice. In this case the code is:

Extent extent = calcExtent();
Size size = calcSize();
ImageStaticOptions iso = new ImageStaticOptions();
iso.setImageExtent(extent);
iso.setUrl("<the url of the new image to show on the layer>");
iso.setImageSize(size);
ImageStatic imageStatic = new ImageStatic(iso);
m_ImgCompositeLayer.setSource(imageStatic);

My questions:

Thanks.

TDesjardins commented 4 years ago

Hello @Magallo ,

Using gwt-ol all the classes are different and most of the features are implemented in a different way.

This is because OpenLayers 3 (and further versions) is a complete rewrite of OpenLayers 2.

My questions:

  • what is the proper strategy to dinamically change the url of the external graphic image of the vector layer? Is the code reported above the right way to do it or is there another, more efficient, way?

The first one of your code snippets is a possible counterpart of your origin OL2 code but there is a more efficient way to do this.

  • is there a way to specify only the url of the external graphic to change without the need to recreate every time a style (which recreates every time a new Image) and setting it to the vector layer?

The API of OpenLayers have no setter for source (src) of Icon but there is a setter for an image at style class, so you don't have to recreate the style then:

IconOptions iconOptions = new IconOptions();
iconOptions.setSrc("<the url of the new image to show on the layer>");
Icon icon = new Icon(iconOptions);

vectorLayer.getStyle().setImage(icon);
vectorLayer.changed();

The changed() method triggers the renderer to refresh the changed style.

  • in the code above I use an Icon object to create the image. Is it the proper way to specify an external .png image to show in the vector layer or there is another, more proper, class to do this?

As far as I know this is the general way when working with vector layers. Your second approach is intended for georeferencing images.

  • more in general, what is the correct way to dinamically change the image of a vector layer having a smooth effect (i.e. avoiding the flickering effect just like in the Image layer case)?

I suppose that the flickering effect is a result of image loading. The image is only loaded when accessing. So the renderer has to wait until the image is loaded. To prevent this you could try preloading the images with load() method of class Icon before setting the icon style. Unfortunatly the image setter on Style and the load() method on Icon aren't wrapped in the current releases of gwt-ol but I already committed the support in the master branch (https://github.com/TDesjardins/gwt-ol/commit/1ad3cca3339166e5382c114523f2e458c4b497e2, https://github.com/TDesjardins/gwt-ol/commit/cde85319543c7ee0182bca3b3157aafe49d9dd2b). I will publish a new release soon with the changes and OpenLayer6 support.

TDesjardins commented 4 years ago

@Magallo New gwt-ol version 8.0.0 is now released which provides the desired enhancements and also with OpenLayers 6 support. Please reopen if something is missing.

Magallo commented 4 years ago

Hi all. I tried and I found a solution. If I simply call the changed() method of the vector layer class, the function style is called and I can set the new Icon there (without recreate the style every time). Using this strategy I can have a smooth transition of the image associated to the vector layer without flickering effect. Thanks.

Magallo commented 3 years ago

Hi all! I'm still here having problems. I noticed the load() method on Icon and the image setter on Style (thank you for your cotinuous support!), howevere I still have problems I don't fully understand. I tried pre-loading all the images (using the load() method) and assigning to the style (in the sylefunction) the pre-load image. In this case the usual 'flicker' effect seems to be mitigated, but I noticed severe performace issues. In any case the solution seems not to be 'stable'. I also noticed that the flickering effect is emphasized or reduced depending on the amount of images being part of the 'movie loop'. In a short or very short movie loop the flicker effect is almost zero while in a long movie loop (more images) the effect is more and more present. My question is: is there a more efficient way to smoothly execute image transitions on vector layers (an alternative of using the Icon/Style method) or the technique is correct but must be implemented in a different way? Last question: I see there is the load() method on Icon class, but is it sync or async? Is there a way to use a 'loaded' callback to be notified when the image is effectively loaded? Thanks.