diff --git a/Apps/Sandcastle/gallery/Custom DataSource.html b/Apps/Sandcastle/gallery/Custom DataSource.html
index 357c1856f104..af2defb2d817 100644
--- a/Apps/Sandcastle/gallery/Custom DataSource.html
+++ b/Apps/Sandcastle/gallery/Custom DataSource.html
@@ -156,14 +156,14 @@
set : function(value) {
this._seriesToDisplay = value;
- //Iterate over all polylines and set their show property
+ //Iterate over all entities and set their show property
//to true only if they are part of the current series.
var collection = this._entityCollection;
var entities = collection.values;
collection.suspendEvents();
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
- entity.polyline.show.setValue(value === entity.seriesName);
+ entity.show = value === entity.seriesName;
}
collection.resumeEvents();
}
@@ -287,7 +287,6 @@
//WebGL Globe only contains lines, so that's the only graphics we create.
var polyline = new Cesium.PolylineGraphics();
- polyline.show = new Cesium.ConstantProperty(show);
polyline.material = new Cesium.ColorMaterialProperty(color);
polyline.width = new Cesium.ConstantProperty(2);
polyline.followSurface = new Cesium.ConstantProperty(false);
@@ -296,6 +295,7 @@
//The polyline instance itself needs to be on an entity.
var entity = new Cesium.Entity({
id : seriesName + ' index ' + i.toString(),
+ show : show,
polyline : polyline,
seriesName : seriesName //Custom property to indicate series name
});
diff --git a/Apps/Sandcastle/gallery/Show or Hide Entities.html b/Apps/Sandcastle/gallery/Show or Hide Entities.html
new file mode 100644
index 000000000000..632b227a4e77
--- /dev/null
+++ b/Apps/Sandcastle/gallery/Show or Hide Entities.html
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+ Cesium Demo
+
+
+
+
+
+
+
+Loading...
+
+
+
+
diff --git a/Apps/Sandcastle/gallery/Show or Hide Entities.jpg b/Apps/Sandcastle/gallery/Show or Hide Entities.jpg
new file mode 100644
index 000000000000..55907638f8a9
Binary files /dev/null and b/Apps/Sandcastle/gallery/Show or Hide Entities.jpg differ
diff --git a/CHANGES.md b/CHANGES.md
index ece02cdc48f1..b41af10c9af6 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -9,7 +9,11 @@ Change Log
* Removed `Camera.transform`, which was deprecated in Cesium 1.6. Use `Camera.lookAtTransform`.
* Removed the `direction` and `up` options to `Camera.flyTo`, which were deprecated in Cesium 1.6. Use the `orientation` option.
* Removed `Camera.flyToRectangle`, which was deprecated in Cesium 1.6. Use `Camera.flyTo`.
+* Added `Entity.show` which is a boolean for easily hiding or showing an entity and its children.
+* Added `Entity.isShowing` which is a read-only property that indicates if an entity is currently being drawn.
+* Added support for the KML `visibility` element.
* Added `PolylineArrowMaterialProperty` to allow entities materials to use polyline arrows.
+* Improved `viewer.zoomTo` and `viewer.flyTo` so they are now "best effort" and work even if some entities being zoomed to are not currently in the scene.
* Fixed `PointerEvent` detection so that it works with older implementations of the specification. This also fixes lack of mouse handling when detection failed, such as when using Cesium in the Windows `WebBrowser` control.
* Fixed an issue with transparency. [#2572](https://github.com/AnalyticalGraphicsInc/cesium/issues/2572)
* Fixed improper handling of null values when loading `GeoJSON` data.
diff --git a/Source/Core/AssociativeArray.js b/Source/Core/AssociativeArray.js
index 60bb46e2f971..006f801539b8 100644
--- a/Source/Core/AssociativeArray.js
+++ b/Source/Core/AssociativeArray.js
@@ -126,8 +126,11 @@ define([
* Clears the collection.
*/
AssociativeArray.prototype.removeAll = function() {
- this._hash = {};
- this._array.length = 0;
+ var array = this._array;
+ if (array.length > 0) {
+ this._hash = {};
+ array.length = 0;
+ }
};
return AssociativeArray;
diff --git a/Source/DataSources/BillboardVisualizer.js b/Source/DataSources/BillboardVisualizer.js
index bfe6aba20056..50ec0c5a2548 100644
--- a/Source/DataSources/BillboardVisualizer.js
+++ b/Source/DataSources/BillboardVisualizer.js
@@ -105,7 +105,7 @@ define([
var billboardGraphics = entity._billboard;
var textureValue;
var billboard = item.billboard;
- var show = entity.isAvailable(time) && Property.getValueOrDefault(billboardGraphics._show, time, true);
+ var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(billboardGraphics._show, time, true);
if (show) {
position = Property.getValueOrUndefined(entity._position, time, position);
diff --git a/Source/DataSources/BoxGeometryUpdater.js b/Source/DataSources/BoxGeometryUpdater.js
index 3df3b7bc9387..14f4628e5691 100644
--- a/Source/DataSources/BoxGeometryUpdater.js
+++ b/Source/DataSources/BoxGeometryUpdater.js
@@ -509,7 +509,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var box = entity.box;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(box.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(box.show, time, true)) {
return;
}
diff --git a/Source/DataSources/CorridorGeometryUpdater.js b/Source/DataSources/CorridorGeometryUpdater.js
index fd69e0545208..43e08de143b8 100644
--- a/Source/DataSources/CorridorGeometryUpdater.js
+++ b/Source/DataSources/CorridorGeometryUpdater.js
@@ -529,7 +529,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var corridor = entity.corridor;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(corridor.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(corridor.show, time, true)) {
return;
}
diff --git a/Source/DataSources/CylinderGeometryUpdater.js b/Source/DataSources/CylinderGeometryUpdater.js
index 924f2887e39c..ab66c94360e6 100644
--- a/Source/DataSources/CylinderGeometryUpdater.js
+++ b/Source/DataSources/CylinderGeometryUpdater.js
@@ -529,7 +529,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var cylinder = entity.cylinder;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(cylinder.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(cylinder.show, time, true)) {
return;
}
diff --git a/Source/DataSources/EllipseGeometryUpdater.js b/Source/DataSources/EllipseGeometryUpdater.js
index 6ccbf208e6be..754a052ba329 100644
--- a/Source/DataSources/EllipseGeometryUpdater.js
+++ b/Source/DataSources/EllipseGeometryUpdater.js
@@ -541,7 +541,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var ellipse = entity.ellipse;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(ellipse.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(ellipse.show, time, true)) {
return;
}
diff --git a/Source/DataSources/EllipsoidGeometryUpdater.js b/Source/DataSources/EllipsoidGeometryUpdater.js
index 858669ef58a9..fd030e46069c 100644
--- a/Source/DataSources/EllipsoidGeometryUpdater.js
+++ b/Source/DataSources/EllipsoidGeometryUpdater.js
@@ -535,7 +535,7 @@ define([
var entity = this._entity;
var ellipsoid = entity.ellipsoid;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(ellipsoid.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(ellipsoid.show, time, true)) {
if (defined(this._primitive)) {
this._primitive.show = false;
}
diff --git a/Source/DataSources/Entity.js b/Source/DataSources/Entity.js
index 269ee647870c..20b00c590ddd 100644
--- a/Source/DataSources/Entity.js
+++ b/Source/DataSources/Entity.js
@@ -92,6 +92,7 @@ define([
* @param {Object} [options] Object with the following properties:
* @param {String} [options.id] A unique identifier for this object. If none is provided, a GUID is generated.
* @param {String} [options.name] A human readable name to display to users. It does not have to be unique.
+ * @param {Boolean} [options.show] A boolean value indicating if the entity and its children are displayed.
* @param {Property} [options.description] A string Property specifying an HTML description for this entity.
* @param {PositionProperty} [options.position] A Property specifying the entity position.
* @param {Property} [options.orientation] A Property specifying the entity orientation.
@@ -132,8 +133,9 @@ define([
this._availability = undefined;
this._id = id;
this._definitionChanged = new Event();
- this._name = undefined;
- this._parent = options.parent;
+ this._name = options.name;
+ this._show = defaultValue(options.show, true);
+ this._parent = undefined;
this._propertyNames = ['billboard', 'box', 'corridor', 'cylinder', 'description', 'ellipse', //
'ellipsoid', 'label', 'model', 'orientation', 'path', 'point', 'polygon', //
'polyline', 'polylineVolume', 'position', 'rectangle', 'viewFrom', 'wall'];
@@ -176,10 +178,27 @@ define([
this._viewFromSubscription = undefined;
this._wall = undefined;
this._wallSubscription = undefined;
+ this._children = [];
- this.merge(defaultValue(options, defaultValue.EMPTY_OBJECT));
+ this.parent = options.parent;
+ this.merge(options);
};
+ function updateShow(entity, isShowing) {
+ var children = entity._children;
+ var length = children.length;
+ for (var i = 0; i < length; i++) {
+ var child = children[i];
+ var childShow = child._show;
+ var oldValue = !isShowing && childShow;
+ var newValue = isShowing && childShow;
+ if (oldValue !== newValue) {
+ child._definitionChanged.raiseEvent(child, 'isShowing', newValue, oldValue);
+ }
+ }
+ entity._definitionChanged.raiseEvent(entity, 'isShowing', isShowing, !isShowing);
+ }
+
defineProperties(Entity.prototype, {
/**
* The availability, if any, associated with this object.
@@ -219,17 +238,48 @@ define([
* @memberof Entity.prototype
* @type {String}
*/
- name : {
- configurable : false,
+ name : createRawPropertyDescriptor('name'),
+ /**
+ * Gets or sets whether this entity should be displayed. When set to true,
+ * the entity is only displayed if the parent entity's show property is also true.
+ * @memberof Entity.prototype
+ * @type {Boolean}
+ */
+ show : {
get : function() {
- return this._name;
+ return this._show;
},
set : function(value) {
- var oldValue = this._name;
- if (oldValue !== value) {
- this._name = value;
- this._definitionChanged.raiseEvent(this, 'name', value, oldValue);
+ //>>includeStart('debug', pragmas.debug);
+ if (!defined(value)) {
+ throw new DeveloperError('value is required.');
+ }
+ //>>includeEnd('debug');
+
+ if (value === this._show) {
+ return;
}
+
+ var wasShowing = this.isShowing;
+ this._show = value;
+ var isShowing = this.isShowing;
+
+ if (wasShowing !== isShowing) {
+ updateShow(this, isShowing);
+ }
+
+ this._definitionChanged.raiseEvent(this, 'show', value, !value);
+ }
+ },
+ /**
+ * Gets whether this entity is being displayed, taking into account
+ * the visibility of any ancestor entities.
+ * @memberof Entity.prototype
+ * @type {Boolean}
+ */
+ isShowing : {
+ get : function() {
+ return this._show && (!defined(this._parent) || this._parent._show);
}
},
/**
@@ -237,7 +287,35 @@ define([
* @memberof Entity.prototype
* @type {Entity}
*/
- parent : createRawPropertyDescriptor('parent'),
+ parent : {
+ get : function() {
+ return this._parent;
+ },
+ set : function(value) {
+ var oldValue = this._parent;
+
+ if (oldValue === value) {
+ return;
+ }
+
+ var wasShowing = this.isShowing;
+ if (defined(oldValue)) {
+ var index = oldValue._children.indexOf(this);
+ oldValue._children.splice(index, 1);
+ }
+
+ this._parent = value;
+ value._children.push(this);
+
+ var isShowing = this.isShowing;
+
+ if (wasShowing !== isShowing) {
+ updateShow(this, isShowing);
+ }
+
+ this._definitionChanged.raiseEvent(this, 'parent', value, oldValue);
+ }
+ },
/**
* Gets the names of all properties registered on this instance.
* @memberof Entity.prototype
@@ -448,7 +526,8 @@ define([
}
//>>includeEnd('debug');
- //Name and availability are not Property objects and are currently handled differently.
+ //Name, show, and availability are not Property objects and are currently handled differently.
+ //source.show is intentionally ignored because this.show always has a value.
this.name = defaultValue(this.name, source.name);
this.availability = defaultValue(source.availability, this.availability);
diff --git a/Source/DataSources/KmlDataSource.js b/Source/DataSources/KmlDataSource.js
index c2feb8089684..a4759abcc3fc 100644
--- a/Source/DataSources/KmlDataSource.js
+++ b/Source/DataSources/KmlDataSource.js
@@ -1299,8 +1299,8 @@ define([
}
entity.availability = availability;
- //var visibility = queryBooleanValue(featureNode, 'visibility', namespaces.kml);
- //entity.uiShow = defaultValue(visibility, true);
+ var visibility = queryBooleanValue(featureNode, 'visibility', namespaces.kml);
+ entity.show = defaultValue(visibility, true);
//var open = queryBooleanValue(featureNode, 'open', namespaces.kml);
var authorNode = queryFirstNode(featureNode, 'author', namespaces.atom);
diff --git a/Source/DataSources/LabelVisualizer.js b/Source/DataSources/LabelVisualizer.js
index 1ea368210912..83b334942a7d 100644
--- a/Source/DataSources/LabelVisualizer.js
+++ b/Source/DataSources/LabelVisualizer.js
@@ -108,7 +108,7 @@ define([
var labelGraphics = entity._label;
var text;
var label = item.label;
- var show = entity.isAvailable(time) && Property.getValueOrDefault(labelGraphics._show, time, true);
+ var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(labelGraphics._show, time, true);
if (show) {
position = Property.getValueOrUndefined(entity._position, time, position);
diff --git a/Source/DataSources/ModelVisualizer.js b/Source/DataSources/ModelVisualizer.js
index c2a6d92bab1e..cd40d0761c8e 100644
--- a/Source/DataSources/ModelVisualizer.js
+++ b/Source/DataSources/ModelVisualizer.js
@@ -84,7 +84,7 @@ define([
var uri;
var modelData = modelHash[entity.id];
- var show = entity.isAvailable(time) && Property.getValueOrDefault(modelGraphics._show, time, true);
+ var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(modelGraphics._show, time, true);
var modelMatrix;
if (show) {
diff --git a/Source/DataSources/PathVisualizer.js b/Source/DataSources/PathVisualizer.js
index eefd2e564000..718c17610901 100644
--- a/Source/DataSources/PathVisualizer.js
+++ b/Source/DataSources/PathVisualizer.js
@@ -293,7 +293,7 @@ define([
var sampleStop;
var showProperty = pathGraphics._show;
var polyline = item.polyline;
- var show = !defined(showProperty) || showProperty.getValue(time);
+ var show = entity.isShowing && (!defined(showProperty) || showProperty.getValue(time));
//While we want to show the path, there may not actually be anything to show
//depending on lead/trail settings. Compute the interval of the path to
diff --git a/Source/DataSources/PointVisualizer.js b/Source/DataSources/PointVisualizer.js
index 919edaf69232..ff86978db82a 100644
--- a/Source/DataSources/PointVisualizer.js
+++ b/Source/DataSources/PointVisualizer.js
@@ -91,7 +91,7 @@ define([
var entity = item.entity;
var pointGraphics = entity._point;
var billboard = item.billboard;
- var show = entity.isAvailable(time) && Property.getValueOrDefault(pointGraphics._show, time, true);
+ var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(pointGraphics._show, time, true);
if (show) {
position = Property.getValueOrUndefined(entity._position, time, position);
show = defined(position);
diff --git a/Source/DataSources/PolygonGeometryUpdater.js b/Source/DataSources/PolygonGeometryUpdater.js
index ea0739b3e025..f9ab20c0e8b4 100644
--- a/Source/DataSources/PolygonGeometryUpdater.js
+++ b/Source/DataSources/PolygonGeometryUpdater.js
@@ -542,7 +542,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var polygon = entity.polygon;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(polygon.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(polygon.show, time, true)) {
return;
}
diff --git a/Source/DataSources/PolylineGeometryUpdater.js b/Source/DataSources/PolylineGeometryUpdater.js
index 54ea6adffaa0..3793cbdffb16 100644
--- a/Source/DataSources/PolylineGeometryUpdater.js
+++ b/Source/DataSources/PolylineGeometryUpdater.js
@@ -460,7 +460,7 @@ define([
var polyline = entity.polyline;
var line = this._line;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(polyline._show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(polyline._show, time, true)) {
line.show = false;
return;
}
diff --git a/Source/DataSources/PolylineVolumeGeometryUpdater.js b/Source/DataSources/PolylineVolumeGeometryUpdater.js
index 48d5d8df37b2..03b28c993446 100644
--- a/Source/DataSources/PolylineVolumeGeometryUpdater.js
+++ b/Source/DataSources/PolylineVolumeGeometryUpdater.js
@@ -516,7 +516,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var polylineVolume = entity.polylineVolume;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(polylineVolume.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(polylineVolume.show, time, true)) {
return;
}
diff --git a/Source/DataSources/RectangleGeometryUpdater.js b/Source/DataSources/RectangleGeometryUpdater.js
index 2781f1c4fd9a..2e608b033427 100644
--- a/Source/DataSources/RectangleGeometryUpdater.js
+++ b/Source/DataSources/RectangleGeometryUpdater.js
@@ -537,7 +537,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var rectangle = entity.rectangle;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(rectangle.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(rectangle.show, time, true)) {
return;
}
diff --git a/Source/DataSources/StaticGeometryColorBatch.js b/Source/DataSources/StaticGeometryColorBatch.js
index ee34a12c8e89..900fdc81d448 100644
--- a/Source/DataSources/StaticGeometryColorBatch.js
+++ b/Source/DataSources/StaticGeometryColorBatch.js
@@ -31,6 +31,8 @@ define([
this.updaters = new AssociativeArray();
this.updatersWithAttributes = new AssociativeArray();
this.attributes = new AssociativeArray();
+ this.subscriptions = new AssociativeArray();
+ this.showsUpdated = new AssociativeArray();
this.itemsToRemove = [];
};
@@ -41,14 +43,27 @@ define([
this.updaters.set(id, updater);
if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant) {
this.updatersWithAttributes.set(id, updater);
+ } else {
+ var that = this;
+ this.subscriptions.set(id, updater.entity.definitionChanged.addEventListener(function(entity, propertyName, newValue, oldValue) {
+ if (propertyName === 'isShowing') {
+ that.showsUpdated.set(entity.id, updater);
+ }
+ }));
}
};
Batch.prototype.remove = function(updater) {
var id = updater.entity.id;
this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
- this.updaters.remove(id);
- this.updatersWithAttributes.remove(id);
+ if (this.updaters.remove(id)) {
+ this.updatersWithAttributes.remove(id);
+ var unsubscribe = this.subscriptions.get(id);
+ if (defined(unsubscribe)) {
+ unsubscribe();
+ this.subscriptions.remove(id);
+ }
+ }
};
Batch.prototype.update = function(time) {
@@ -110,13 +125,15 @@ define([
}
if (!updater.hasConstantFill) {
- var show = updater.isFilled(time);
+ var show = updater.entity.isShowing && updater.isFilled(time);
var currentShow = attributes.show[0] === 1;
if (show !== currentShow) {
attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
}
}
}
+
+ this.updateShows(primitive);
} else if (defined(primitive) && !primitive.ready) {
isUpdated = false;
}
@@ -124,6 +141,28 @@ define([
return isUpdated;
};
+ Batch.prototype.updateShows = function(primitive) {
+ var showsUpdated = this.showsUpdated.values;
+ var length = showsUpdated.length;
+ for (var i = 0; i < length; i++) {
+ var updater = showsUpdated[i];
+ var instance = this.geometry.get(updater.entity.id);
+
+ var attributes = this.attributes.get(instance.id.id);
+ if (!defined(attributes)) {
+ attributes = primitive.getGeometryInstanceAttributes(instance.id);
+ this.attributes.set(instance.id.id, attributes);
+ }
+
+ var show = updater.entity.isShowing;
+ var currentShow = attributes.show[0] === 1;
+ if (show !== currentShow) {
+ attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
+ }
+ }
+ this.showsUpdated.removeAll();
+ };
+
Batch.prototype.contains = function(entity) {
return this.updaters.contains(entity.id);
};
diff --git a/Source/DataSources/StaticGeometryPerMaterialBatch.js b/Source/DataSources/StaticGeometryPerMaterialBatch.js
index 9bbac9f6c6d5..2f13bb54c524 100644
--- a/Source/DataSources/StaticGeometryPerMaterialBatch.js
+++ b/Source/DataSources/StaticGeometryPerMaterialBatch.js
@@ -30,6 +30,8 @@ define([
this.attributes = new AssociativeArray();
this.invalidated = false;
this.removeMaterialSubscription = materialProperty.definitionChanged.addEventListener(Batch.prototype.onMaterialChanged, this);
+ this.subscriptions = new AssociativeArray();
+ this.showsUpdated = new AssociativeArray();
};
Batch.prototype.onMaterialChanged = function() {
@@ -54,16 +56,32 @@ define([
this.geometry.set(id, updater.createFillGeometryInstance(time));
if (!updater.hasConstantFill || !updater.fillMaterialProperty.isConstant) {
this.updatersWithAttributes.set(id, updater);
+ } else {
+ var that = this;
+ this.subscriptions.set(id, updater.entity.definitionChanged.addEventListener(function(entity, propertyName, newValue, oldValue) {
+ if (propertyName === 'isShowing') {
+ that.showsUpdated.set(entity.id, updater);
+ }
+ }));
}
this.createPrimitive = true;
};
Batch.prototype.remove = function(updater) {
var id = updater.entity.id;
- this.createPrimitive = this.updaters.remove(id);
- this.geometry.remove(id);
- this.updatersWithAttributes.remove(id);
- return this.createPrimitive;
+ var createPrimitive = this.updaters.remove(id);
+
+ if (createPrimitive) {
+ this.geometry.remove(id);
+ this.updatersWithAttributes.remove(id);
+ var unsubscribe = this.subscriptions.get(id);
+ if (defined(unsubscribe)) {
+ unsubscribe();
+ this.subscriptions.remove(id);
+ }
+ }
+ this.createPrimitive = createPrimitive;
+ return createPrimitive;
};
Batch.prototype.update = function(time) {
@@ -109,7 +127,8 @@ define([
var length = updatersWithAttributes.length;
for (var i = 0; i < length; i++) {
var updater = updatersWithAttributes[i];
- var instance = this.geometry.get(updater.entity.id);
+ var entity = updater.entity;
+ var instance = this.geometry.get(entity.id);
var attributes = this.attributes.get(instance.id.id);
if (!defined(attributes)) {
@@ -118,19 +137,44 @@ define([
}
if (!updater.hasConstantFill) {
- var show = updater.isFilled(time);
+ var show = entity.isShowing && updater.isFilled(time);
var currentShow = attributes.show[0] === 1;
if (show !== currentShow) {
attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
}
}
}
+
+ this.updateShows(primitive);
} else if (defined(primitive) && !primitive.ready) {
isUpdated = false;
}
return isUpdated;
};
+ Batch.prototype.updateShows = function(primitive) {
+ var showsUpdated = this.showsUpdated.values;
+ var length = showsUpdated.length;
+ for (var i = 0; i < length; i++) {
+ var updater = showsUpdated[i];
+ var entity = updater.entity;
+ var instance = this.geometry.get(entity.id);
+
+ var attributes = this.attributes.get(instance.id.id);
+ if (!defined(attributes)) {
+ attributes = primitive.getGeometryInstanceAttributes(instance.id);
+ this.attributes.set(instance.id.id, attributes);
+ }
+
+ var show = entity.isShowing;
+ var currentShow = attributes.show[0] === 1;
+ if (show !== currentShow) {
+ attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
+ }
+ }
+ this.showsUpdated.removeAll();
+ };
+
Batch.prototype.contains = function(entity) {
return this.updaters.contains(entity.id);
};
diff --git a/Source/DataSources/StaticOutlineGeometryBatch.js b/Source/DataSources/StaticOutlineGeometryBatch.js
index 13c6baa6abd2..6b1f0715d419 100644
--- a/Source/DataSources/StaticOutlineGeometryBatch.js
+++ b/Source/DataSources/StaticOutlineGeometryBatch.js
@@ -31,6 +31,8 @@ define([
this.attributes = new AssociativeArray();
this.itemsToRemove = [];
this.width = width;
+ this.subscriptions = new AssociativeArray();
+ this.showsUpdated = new AssociativeArray();
};
Batch.prototype.add = function(updater, instance) {
@@ -40,14 +42,27 @@ define([
this.updaters.set(id, updater);
if (!updater.hasConstantOutline || !updater.outlineColorProperty.isConstant) {
this.updatersWithAttributes.set(id, updater);
+ } else {
+ var that = this;
+ this.subscriptions.set(id, updater.entity.definitionChanged.addEventListener(function(entity, propertyName, newValue, oldValue) {
+ if (propertyName === 'isShowing') {
+ that.showsUpdated.set(entity.id, updater);
+ }
+ }));
}
};
Batch.prototype.remove = function(updater) {
var id = updater.entity.id;
this.createPrimitive = this.geometry.remove(id) || this.createPrimitive;
- this.updaters.remove(id);
- this.updatersWithAttributes.remove(id);
+ if (this.updaters.remove(id)) {
+ this.updatersWithAttributes.remove(id);
+ var unsubscribe = this.subscriptions.get(id);
+ if (defined(unsubscribe)) {
+ unsubscribe();
+ this.subscriptions.remove(id);
+ }
+ }
};
var colorScratch = new Color();
@@ -115,13 +130,15 @@ define([
}
if (!updater.hasConstantOutline) {
- var show = updater.isOutlineVisible(time);
+ var show = updater.entity.isShowing && updater.isOutlineVisible(time);
var currentShow = attributes.show[0] === 1;
if (show !== currentShow) {
attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
}
}
}
+
+ this.updateShows(primitive);
} else if (defined(primitive) && !primitive.ready) {
isUpdated = false;
}
@@ -130,6 +147,28 @@ define([
return isUpdated;
};
+ Batch.prototype.updateShows = function(primitive) {
+ var showsUpdated = this.showsUpdated.values;
+ var length = showsUpdated.length;
+ for (var i = 0; i < length; i++) {
+ var updater = showsUpdated[i];
+ var instance = this.geometry.get(updater.entity.id);
+
+ var attributes = this.attributes.get(instance.id.id);
+ if (!defined(attributes)) {
+ attributes = primitive.getGeometryInstanceAttributes(instance.id);
+ this.attributes.set(instance.id.id, attributes);
+ }
+
+ var show = updater.entity.isShowing;
+ var currentShow = attributes.show[0] === 1;
+ if (show !== currentShow) {
+ attributes.show = ShowGeometryInstanceAttribute.toValue(show, attributes.show);
+ }
+ }
+ this.showsUpdated.removeAll();
+ };
+
Batch.prototype.contains = function(entity) {
return this.updaters.contains(entity.id);
};
diff --git a/Source/DataSources/WallGeometryUpdater.js b/Source/DataSources/WallGeometryUpdater.js
index 3dafe16ab952..68997bc9f415 100644
--- a/Source/DataSources/WallGeometryUpdater.js
+++ b/Source/DataSources/WallGeometryUpdater.js
@@ -519,7 +519,7 @@ define([
var geometryUpdater = this._geometryUpdater;
var entity = geometryUpdater._entity;
var wall = entity.wall;
- if (!entity.isAvailable(time) || !Property.getValueOrDefault(wall.show, time, true)) {
+ if (!entity.isShowing || !entity.isAvailable(time) || !Property.getValueOrDefault(wall.show, time, true)) {
return;
}
diff --git a/Source/Widgets/Viewer/Viewer.js b/Source/Widgets/Viewer/Viewer.js
index aeed8016fe45..f189352be69f 100644
--- a/Source/Widgets/Viewer/Viewer.js
+++ b/Source/Widgets/Viewer/Viewer.js
@@ -1298,7 +1298,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to
var selectedEntity = this.selectedEntity;
var showSelection = defined(selectedEntity) && this._enableInfoOrSelection;
- if (showSelection && selectedEntity.isAvailable(time)) {
+ if (showSelection && selectedEntity.isShowing && selectedEntity.isAvailable(time)) {
var state = this._dataSourceDisplay.getBoundingSphere(selectedEntity, true, boundingSphereScratch);
if (state !== BoundingSphereState.FAILED) {
position = boundingSphereScratch.center;
@@ -1561,12 +1561,9 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to
if (state === BoundingSphereState.PENDING) {
return;
- } else if (state === BoundingSphereState.FAILED) {
- cancelZoom(viewer);
- return;
+ } else if (state !== BoundingSphereState.FAILED) {
+ boundingSpheres.push(BoundingSphere.clone(boundingSphereScratch));
}
-
- boundingSpheres.push(BoundingSphere.clone(boundingSphereScratch));
}
if (boundingSpheres.length === 0) {
diff --git a/Specs/DataSources/BoxGeometryUpdaterSpec.js b/Specs/DataSources/BoxGeometryUpdaterSpec.js
index 7e87e2c16935..a8115a85217d 100644
--- a/Specs/DataSources/BoxGeometryUpdaterSpec.js
+++ b/Specs/DataSources/BoxGeometryUpdaterSpec.js
@@ -298,6 +298,11 @@ defineSuite([
expect(dynamicUpdater._options.id).toBe(entity);
expect(dynamicUpdater._options.dimensions).toEqual(box.dimensions.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
box.show.setValue(false);
dynamicUpdater.update(JulianDate.now());
expect(primitives.length).toBe(0);
diff --git a/Specs/DataSources/CorridorGeometryUpdaterSpec.js b/Specs/DataSources/CorridorGeometryUpdaterSpec.js
index bb04911a2525..a0441bfb3a9e 100644
--- a/Specs/DataSources/CorridorGeometryUpdaterSpec.js
+++ b/Specs/DataSources/CorridorGeometryUpdaterSpec.js
@@ -400,6 +400,11 @@ defineSuite([
expect(options.granularity).toEqual(corridor.granularity.getValue());
expect(options.cornerType).toEqual(corridor.cornerType.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
//If a dynamic show returns false, the primitive should go away.
corridor.show.setValue(false);
dynamicUpdater.update(time);
diff --git a/Specs/DataSources/CylinderGeometryUpdaterSpec.js b/Specs/DataSources/CylinderGeometryUpdaterSpec.js
index 5bfbd3e7a47e..52a5825b72b4 100644
--- a/Specs/DataSources/CylinderGeometryUpdaterSpec.js
+++ b/Specs/DataSources/CylinderGeometryUpdaterSpec.js
@@ -384,6 +384,11 @@ defineSuite([
expect(dynamicUpdater._options.topRadius).toEqual(cylinder.topRadius.getValue());
expect(dynamicUpdater._options.bottomRadius).toEqual(cylinder.bottomRadius.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
cylinder.show.setValue(false);
dynamicUpdater.update(JulianDate.now());
expect(primitives.length).toBe(0);
diff --git a/Specs/DataSources/EllipseGeometryUpdaterSpec.js b/Specs/DataSources/EllipseGeometryUpdaterSpec.js
index 72a5e0689b5a..5f5fa040df80 100644
--- a/Specs/DataSources/EllipseGeometryUpdaterSpec.js
+++ b/Specs/DataSources/EllipseGeometryUpdaterSpec.js
@@ -436,6 +436,11 @@ defineSuite([
expect(dynamicUpdater._options.semiMajorAxis).toEqual(ellipse.semiMajorAxis.getValue());
expect(dynamicUpdater._options.semiMinorAxis).toEqual(ellipse.semiMinorAxis.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
ellipse.show.setValue(false);
dynamicUpdater.update(JulianDate.now());
expect(primitives.length).toBe(0);
diff --git a/Specs/DataSources/EntitySpec.js b/Specs/DataSources/EntitySpec.js
index c606b856c5f3..57e5a5e5facb 100644
--- a/Specs/DataSources/EntitySpec.js
+++ b/Specs/DataSources/EntitySpec.js
@@ -83,6 +83,7 @@ defineSuite([
var options = {
id : 'someId',
name : 'bob',
+ show : false,
availability : new TimeIntervalCollection(),
parent : new Entity(),
customProperty : {},
@@ -110,6 +111,7 @@ defineSuite([
entity = new Entity(options);
expect(entity.id).toEqual(options.id);
expect(entity.name).toEqual(options.name);
+ expect(entity.show).toBe(options.show);
expect(entity.availability).toBe(options.availability);
expect(entity.parent).toBe(options.parent);
expect(entity.customProperty).toBe(options.customProperty);
@@ -357,4 +359,91 @@ defineSuite([
entity.removeProperty('name');
}).toThrowDeveloperError();
});
+
+ it('isShowing works without parent.', function() {
+ var entity = new Entity({
+ show : false
+ });
+ expect(entity.isShowing).toBe(false);
+
+ var listener = jasmine.createSpy('listener');
+ entity.definitionChanged.addEventListener(listener);
+
+ entity.show = true;
+ expect(listener.calls.count()).toBe(2);
+ expect(listener.calls.argsFor(0)).toEqual([entity, 'isShowing', true, false]);
+ expect(listener.calls.argsFor(1)).toEqual([entity, 'show', true, false]);
+ expect(entity.isShowing).toBe(true);
+
+ listener.calls.reset();
+
+ entity.show = false;
+ expect(listener.calls.count()).toBe(2);
+ expect(listener.calls.argsFor(0)).toEqual([entity, 'isShowing', false, true]);
+ expect(listener.calls.argsFor(1)).toEqual([entity, 'show', false, true]);
+ expect(entity.isShowing).toBe(false);
+ });
+
+ it('isShowing works with parent.', function() {
+ var entity = new Entity();
+ entity.parent = new Entity();
+
+ var listener = jasmine.createSpy('listener');
+ entity.definitionChanged.addEventListener(listener);
+
+ entity.parent.show = false;
+
+ //Setting entity.parent show to false causes entity to raise
+ //its own isShowing event, but not the show event.
+ expect(listener.calls.count()).toBe(1);
+ expect(listener.calls.argsFor(0)).toEqual([entity, 'isShowing', false, true]);
+ expect(entity.show).toBe(true);
+ expect(entity.isShowing).toBe(false);
+
+ listener.calls.reset();
+
+ //Since isShowing is already false, setting show to false causes the show event
+ //but not the isShowing event to be raised
+ entity.show = false;
+ expect(entity.show).toBe(false);
+ expect(listener.calls.count()).toBe(1);
+ expect(listener.calls.argsFor(0)).toEqual([entity, 'show', false, true]);
+
+ listener.calls.reset();
+
+ //Setting parent show to true does not trigger the entity.isShowing event
+ //because entity.show is false;
+ entity.parent.show = true;
+ expect(entity.show).toBe(false);
+ expect(entity.isShowing).toBe(false);
+ expect(listener.calls.count()).toBe(0);
+
+ listener.calls.reset();
+
+ //Setting entity.show to try now causes both events to be raised
+ //because the parent is also showing.
+ entity.show = true;
+ expect(listener.calls.count()).toBe(2);
+ expect(listener.calls.argsFor(0)).toEqual([entity, 'isShowing', true, false]);
+ expect(listener.calls.argsFor(1)).toEqual([entity, 'show', true, false]);
+ expect(entity.show).toBe(true);
+ expect(entity.isShowing).toBe(true);
+ });
+
+ it('isShowing works when replacing parent.', function() {
+ var entity = new Entity();
+ entity.parent = new Entity();
+
+ var listener = jasmine.createSpy('listener');
+ entity.definitionChanged.addEventListener(listener);
+
+ entity.parent = new Entity({
+ show : false
+ });
+
+ expect(listener.calls.count()).toBe(2);
+ expect(listener.calls.argsFor(0)).toEqual([entity, 'isShowing', false, true]);
+ expect(entity.show).toBe(true);
+ expect(entity.isShowing).toBe(false);
+ });
});
\ No newline at end of file
diff --git a/Specs/DataSources/KmlDataSourceSpec.js b/Specs/DataSources/KmlDataSourceSpec.js
index e0334d374827..7d16b0f754a7 100644
--- a/Specs/DataSources/KmlDataSourceSpec.js
+++ b/Specs/DataSources/KmlDataSourceSpec.js
@@ -527,6 +527,18 @@ defineSuite([
});
});
+ it('Feature: visibility works', function() {
+ var kml = '\
+ \
+ 0\
+ ';
+
+ return KmlDataSource.load(parser.parseFromString(kml, "text/xml")).then(function(dataSource) {
+ var entity = dataSource.entities.values[0];
+ expect(entity.show).toBe(false);
+ });
+ });
+
it('Feature: TimeStamp gracefully handles empty fields', function() {
var kml = '\
\
diff --git a/Specs/DataSources/PolygonGeometryUpdaterSpec.js b/Specs/DataSources/PolygonGeometryUpdaterSpec.js
index 5832d353fd23..6e57d843ff59 100644
--- a/Specs/DataSources/PolygonGeometryUpdaterSpec.js
+++ b/Specs/DataSources/PolygonGeometryUpdaterSpec.js
@@ -395,6 +395,11 @@ defineSuite([
expect(options.granularity).toEqual(polygon.granularity.getValue());
expect(options.stRotation).toEqual(polygon.stRotation.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
//If a dynamic show returns false, the primitive should go away.
polygon.show.setValue(false);
dynamicUpdater.update(time);
diff --git a/Specs/DataSources/PolylineVolumeGeometryUpdaterSpec.js b/Specs/DataSources/PolylineVolumeGeometryUpdaterSpec.js
index 9d146a243b08..a66bacd65dfe 100644
--- a/Specs/DataSources/PolylineVolumeGeometryUpdaterSpec.js
+++ b/Specs/DataSources/PolylineVolumeGeometryUpdaterSpec.js
@@ -354,6 +354,11 @@ defineSuite([
expect(options.granularity).toEqual(polylineVolume.granularity.getValue());
expect(options.cornerType).toEqual(polylineVolume.cornerType.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
//If a dynamic show returns false, the primitive should go away.
polylineVolume.show.setValue(false);
dynamicUpdater.update(time);
diff --git a/Specs/DataSources/RectangleGeometryUpdaterSpec.js b/Specs/DataSources/RectangleGeometryUpdaterSpec.js
index 4091609e1193..150c3e62a511 100644
--- a/Specs/DataSources/RectangleGeometryUpdaterSpec.js
+++ b/Specs/DataSources/RectangleGeometryUpdaterSpec.js
@@ -399,6 +399,11 @@ defineSuite([
expect(options.granularity).toEqual(rectangle.granularity.getValue());
expect(options.stRotation).toEqual(rectangle.stRotation.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
//If a dynamic show returns false, the primitive should go away.
rectangle.show.setValue(false);
dynamicUpdater.update(time);
diff --git a/Specs/DataSources/WallGeometryUpdaterSpec.js b/Specs/DataSources/WallGeometryUpdaterSpec.js
index 981026b529ea..7f4201ede4d2 100644
--- a/Specs/DataSources/WallGeometryUpdaterSpec.js
+++ b/Specs/DataSources/WallGeometryUpdaterSpec.js
@@ -361,6 +361,11 @@ defineSuite([
expect(options.maximumHeights).toEqual(wall.maximumHeights.getValue());
expect(options.granularity).toEqual(wall.granularity.getValue());
+ entity.show = false;
+ dynamicUpdater.update(JulianDate.now());
+ expect(primitives.length).toBe(0);
+ entity.show = true;
+
//If a dynamic show returns false, the primitive should go away.
wall.show.setValue(false);
dynamicUpdater.update(time);