First of all, I must confess, that there are dozens of similar questions here at stackoverflow (this, this and myriads of others), but all of them are nicely solved with the help of a callback function or simply putting a code inside this image.onload
event:
image.onload = function () {
//do other stuff that should be done right after image is loaded
}
But this is not my case. This is a signature of my function that is responsible for loading images:
function patternBuilder (index) {
var pattern, image, ...
...
image = new Image();
image.id = "_" + index + "_";
image.src = "images/_" + index + "_.png";
image.onload = function () {
pattern = ctx.createPattern(image, "repeat");
}
return pattern; // !!!! may return undefined if image is not yet loaded
}
So, I need to return! I must do it and I have no other chance. The reason I must follow this signature is that, this pattern is used by some external library function which looks like so:
style: function (feature) {
var pattern = patternBuilder(feature.get("index"));
var style = new ol.style.Style({
fill: new ol.style.Fill({
color: pattern
})
});
return style;
}
So, even if I can change the logic of my patternBuilder
function, I still can not change the external library function. This external function uses patternBuilder
and returns a style variable itself. So, there is no room for callbacks.
Here how this could work with promises
a simple wrapper to return image promises:
//takes an url and returns a promise of a (loaded) Image.
function getImage(url){
return new Promise(function(){
var image = new Image();
image.onload = function(){ resolve(image); };
image.onerror = reject; //TODO: resolve that to sth. better
image.src = url;
});
}
and your patternBuilder
function patternBuilder (index) {
//returns now a pattern-promise
return getImage( "images/_" + index + "_.png" ).then(function(image){
//image.id = "_" + index + "_"; //what exactly is this ID for?
return ctx.createPattern(image, "repeat");
});
}
//you may want to add some caching
var patternCache = Object.create(null);
function patternBuilder(index) {
if(!patternCache[index]){
patternCache[index] = getImage( "images/_" + index + "_.png" ).then(image => ctx.createPattern(image, "repeat"));
}
//still returns pattern-promise, but some may have been resolved a "long time" ago.
return patternCache[index];
}
and the function you use the pattern:
style: function(feature) {
//returns a style-promise
return patternBuilder(feature.get("index")).then(function(pattern){
return new ol.style.Style({
fill: new ol.style.Fill({
color: pattern
})
})
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With