I'm working on an extremely minimal emulation of the GEPlugin API and ran into an issue when trying to load invalid image URLs. This shouldn't happen in normal use, but it was happening due to cross-origin security issues in our development environment. Google Earth Plugin will put up a "red X" in this situation, which is nice because there is something to click on if the name of the entity is not set. This is difficult to work around in the client code since the error is thrown on display by Cesium (rendering?) and not when the image URL is set.
I understand that this might be outside the bounds of what Cesium's goals are. If so, do you have any recommendations for working around this? If not, should I file an issue?
I would probably add a Promise to Billboard that resolves when the image is loaded or rejects if it doesn’t. That will have to be handled in BillboardVisualizer and connected to BillboardGraphics somehow.
I modified the billboard loadImage to handle the rendering of a default canvas image when the original URL fails to load. I added a new promise (imageIndexPromise2 ) as you recommended. The getDefaultIcon() is a custom function in my project that returns the canvas, URL, and offset values. The canvas can be an X image like in GE. This code can be improved, but it does the job of loading the default icon when loading KML in Cesium. The first time when Cesium tries to load a non accessible URL image, the billboard is rendered on the map without the image. Soon after (due to a timeout) the first promise comes back with the failure and then the imageIndexPromise2 kicks in to add the default image.
Thanks,
Alberto
// Integrate the use of a default icon like in GE when the image fails to load
Billboard.prototype._loadImage = function() {
var atlas = this._billboardCollection._textureAtlas;
var imageId = this._imageId;
var image = this._image;
var imageSubRegion = this._imageSubRegion;
var imageIndexPromise;
if (defined(image)) {
imageIndexPromise = atlas.addImage(imageId, image);
}
if (defined(imageSubRegion)) {
imageIndexPromise = atlas.addSubRegion(imageId, imageSubRegion);
}
this._imageIndexPromise = imageIndexPromise;
if (!defined(imageIndexPromise)) {
return;
}
var that = this;
that._id = this._id;
imageIndexPromise.then(function(index) {
if (that._imageId !== imageId || that._image !== image || !BoundingRectangle.equals(that._imageSubRegion, imageSubRegion)) {
// another load occurred before this one finished, ignore the index
return;
}
else if (that._imageId === getProxyUrl() + "?" + getDefaultIcon().iconUrl)
{
return;
}
// fill in imageWidth and imageHeight
var textureCoordinates = atlas.textureCoordinates[index];
that._imageWidth = atlas.texture.width * textureCoordinates.width;
that._imageHeight = atlas.texture.height * textureCoordinates.height;
that._imageIndex = index;
that._ready = true;
that._image = undefined;
that._imageIndexPromise = undefined;
makeDirty(that, IMAGE_INDEX_INDEX);
}).otherwise(function(error) {
/*global console*/
var atlas = that._billboardCollection._textureAtlas;
var imageId = that._imageId;
var image = that._image;
var imageSubRegion = that._imageSubRegion;
var imageIndexPromise2;
//start acevedo edit
//add default icon when Cesium fails to load a billboard icon
if (!(that._imageId === getProxyUrl() + "?" + getDefaultIcon().iconUrl) )
{
that._imageId = empGlobe.getProxyUrl() + "?" + getDefaultIcon().iconUrl;
that._image = empDefaultIconCanvas;// this is the default canvas image. It can be an X image like in GE.
that._imageWidth = getDefaultIcon().offset.width;
that._imageHeight = getDefaultIcon().offset.height;
that.pixelOffset = new Cesium.Cartesian2(isNaN(getDefaultIcon().offset.x, getDefaultIcon().offset.y));
that._alignedAxis = Cesium.Cartesian3.ZERO;
that._verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
that._imageIndexPromise = undefined;
}
if (defined(image)) {
imageIndexPromise2 = atlas.addImage(that._imageId, that.image);
}
if (defined(imageSubRegion)) {
imageIndexPromise2 = atlas.addSubRegion(that._imageId, that._imageSubRegion);
}
that._imageIndexPromise = imageIndexPromise2;
if (!defined(imageIndexPromise2)) {
return;
}
var that2 = that;
that2._id = that._id;
imageIndexPromise2.then(function(index) {
// fill in imageWidth and imageHeight
var textureCoordinates = atlas.textureCoordinates[index];
that2._imageWidth = getDefaultIcon().offset.width;
that2._imageHeight = getDefaultIcon().offset.height;
that2.pixelOffset = new Cesium.Cartesian2(isNaN(getDefaultIcon().offset.x, getDefaultIcon().offset.y));
that2._alignedAxis = Cesium.Cartesian3.ZERO;
that2._verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
that2._imageIndex = index;
that2._ready = true;
that2._image = undefined;
that2._imageIndexPromise = undefined;
makeDirty(that2, IMAGE_INDEX_INDEX);
}).otherwise(function(error) {
/*global console*/
console.error('Error loading image for billboard: ' + error);
that2._imageIndexPromise = undefined;
that2.imageLoaded = false;
});
});
};