diff --git a/CHANGES.md b/CHANGES.md index b6c19d82e935..b93f13bdae8b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -31,6 +31,8 @@ Change Log * Fixed a bug in `EllipsoidGeodesic` that caused it to modify the `height` of the positions passed to the constructor or to to `setEndPoints`. * Instead of throwing an exception when there are not enough unique positions to define a geometry, creating a `Primitive` will succeed, but not render. [#2375](https://github.com/AnalyticalGraphicsInc/cesium/issues/2375) * `WebMapTileServiceImageryProvider` now supports RESTful requests (by accepting a tile-URL template). +* When you track an entity by clicking on the track button in the `InfoBox`, you can now stop tracking by clicking the button a second time. +* Setting `viewer.trackedEntity` to `undefined` will now restore the camera controls to their default states. * The object returned by `Primitive.getGeometryInstanceAttributes` now contains the instance's bounding sphere. ### 1.5 - 2015-01-05 diff --git a/Source/Widgets/InfoBox/InfoBox.js b/Source/Widgets/InfoBox/InfoBox.js index 27ddceffd64e..0568fab5eee1 100644 --- a/Source/Widgets/InfoBox/InfoBox.js +++ b/Source/Widgets/InfoBox/InfoBox.js @@ -55,7 +55,7 @@ css: { "cesium-infoBox-visible" : showInfo, "cesium-infoBox-bodyless" : _bodyles cameraElement.className = 'cesium-button cesium-infoBox-camera'; cameraElement.setAttribute('data-bind', '\ attr: { title: "Focus camera on object" },\ -click: function () { cameraClicked.raiseEvent(); },\ +click: function () { cameraClicked.raiseEvent(this); },\ enable: enableCamera,\ cesiumSvgPath: { path: cameraIconPath, width: 32, height: 32 }'); infoElement.appendChild(cameraElement); @@ -64,7 +64,7 @@ cesiumSvgPath: { path: cameraIconPath, width: 32, height: 32 }'); closeElement.type = 'button'; closeElement.className = 'cesium-infoBox-close'; closeElement.setAttribute('data-bind', '\ -click: function () { closeClicked.raiseEvent(); }'); +click: function () { closeClicked.raiseEvent(this); }'); closeElement.innerHTML = '×'; infoElement.appendChild(closeElement); diff --git a/Source/Widgets/InfoBox/InfoBoxViewModel.js b/Source/Widgets/InfoBox/InfoBoxViewModel.js index 9ecc758dc3e8..afef534e1e46 100644 --- a/Source/Widgets/InfoBox/InfoBoxViewModel.js +++ b/Source/Widgets/InfoBox/InfoBoxViewModel.js @@ -118,7 +118,7 @@ define([ this.cameraIconPath = undefined; knockout.defineProperty(this, 'cameraIconPath', { get : function() { - return (this.enableCamera || this.isCameraTracking) ? cameraEnabledPath : cameraDisabledPath; + return (!this.enableCamera || this.isCameraTracking) ? cameraDisabledPath : cameraEnabledPath; } }); diff --git a/Source/Widgets/Viewer/Viewer.js b/Source/Widgets/Viewer/Viewer.js index a45f97df5a17..63fecb4414ba 100644 --- a/Source/Widgets/Viewer/Viewer.js +++ b/Source/Widgets/Viewer/Viewer.js @@ -7,6 +7,7 @@ define([ '../../Core/destroyObject', '../../Core/DeveloperError', '../../Core/EventHelper', + '../../Core/Matrix4', '../../Core/ScreenSpaceEventType', '../../DataSources/ConstantPositionProperty', '../../DataSources/DataSourceCollection', @@ -41,6 +42,7 @@ define([ destroyObject, DeveloperError, EventHelper, + Matrix4, ScreenSpaceEventType, ConstantPositionProperty, DataSourceCollection, @@ -382,8 +384,8 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to infoBox = new InfoBox(infoBoxContainer); var infoBoxViewModel = infoBox.viewModel; - eventHelper.add(infoBoxViewModel.cameraClicked, Viewer.prototype._trackSelectedEntity, this); - eventHelper.add(infoBoxViewModel.closeClicked, Viewer.prototype._clearSelectedEntity, this); + eventHelper.add(infoBoxViewModel.cameraClicked, Viewer.prototype._onInfoBoxCameraClicked, this); + eventHelper.add(infoBoxViewModel.closeClicked, Viewer.prototype._onInfoBoxClockClicked, this); } // Main Toolbar @@ -949,6 +951,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to this._entityView = new EntityView(value, scene, this.scene.globe.ellipsoid); } else { this._entityView = undefined; + this.camera.setTransform(Matrix4.IDENTITY); } } } @@ -1223,7 +1226,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to if (defined(this.trackedEntity)) { if (entityCollection.getById(this.trackedEntity.id) === this.trackedEntity) { - this.homeButton.viewModel.command(); + this.trackedEntity = undefined; } } @@ -1262,7 +1265,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to if (selectedEntity.isAvailable(time)) { if (defined(selectedEntity.position)) { position = selectedEntity.position.getValue(time, oldPosition); - enableCamera = defined(position) && (this.trackedEntity !== this.selectedEntity); + enableCamera = defined(position); } // else "position" is undefined and "enableCamera" is false. } @@ -1302,7 +1305,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to for (var i = 0; i < length; i++) { var removedObject = removed[i]; if (this.trackedEntity === removedObject) { - this.homeButton.viewModel.command(); + this.trackedEntity = undefined; } if (this.selectedEntity === removedObject) { this.selectedEntity = undefined; @@ -1313,8 +1316,12 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to /** * @private */ - Viewer.prototype._trackSelectedEntity = function() { - this.trackedEntity = this.selectedEntity; + Viewer.prototype._onInfoBoxCameraClicked = function(infoBoxViewModel) { + if (infoBoxViewModel.isCameraTracking && (this.trackedEntity === this.selectedEntity)) { + this.trackedEntity = undefined; + } else { + this.trackedEntity = this.selectedEntity; + } }; /** @@ -1327,7 +1334,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to /** * @private */ - Viewer.prototype._clearSelectedEntity = function() { + Viewer.prototype._onInfoBoxClockClicked = function(infoBoxViewModel) { this.selectedEntity = undefined; }; diff --git a/Specs/Widgets/InfoBox/InfoBoxViewModelSpec.js b/Specs/Widgets/InfoBox/InfoBoxViewModelSpec.js index a426c76ccaca..e79c416ea7e5 100644 --- a/Specs/Widgets/InfoBox/InfoBoxViewModelSpec.js +++ b/Specs/Widgets/InfoBox/InfoBoxViewModelSpec.js @@ -84,10 +84,21 @@ defineSuite([ it('camera icon changes when tracking is not available, unless due to active tracking', function() { var viewModel = new InfoBoxViewModel(); viewModel.enableCamera = true; - var enabledCameraPath = viewModel.cameraIconPath; + viewModel.isCameraTracking = false; + var enabledTrackingPath = viewModel.cameraIconPath; + + viewModel.enableCamera = false; + viewModel.isCameraTracking = false; + expect(viewModel.cameraIconPath).not.toBe(enabledTrackingPath); + + var disableTrackingPath = viewModel.cameraIconPath; + + viewModel.enableCamera = true; + viewModel.isCameraTracking = true; + expect(viewModel.cameraIconPath).toBe(disableTrackingPath); + viewModel.enableCamera = false; - expect(viewModel.cameraIconPath).not.toBe(enabledCameraPath); viewModel.isCameraTracking = true; - expect(viewModel.cameraIconPath).toBe(enabledCameraPath); + expect(viewModel.cameraIconPath).toBe(disableTrackingPath); }); }); \ No newline at end of file diff --git a/Specs/Widgets/Viewer/ViewerSpec.js b/Specs/Widgets/Viewer/ViewerSpec.js index 54cdc55e12ac..7cab27af34a9 100644 --- a/Specs/Widgets/Viewer/ViewerSpec.js +++ b/Specs/Widgets/Viewer/ViewerSpec.js @@ -6,6 +6,7 @@ defineSuite([ 'Core/ClockStep', 'Core/EllipsoidTerrainProvider', 'Core/JulianDate', + 'Core/Matrix4', 'Core/WebMercatorProjection', 'DataSources/ConstantPositionProperty', 'DataSources/ConstantProperty', @@ -36,6 +37,7 @@ defineSuite([ ClockStep, EllipsoidTerrainProvider, JulianDate, + Matrix4, WebMercatorProjection, ConstantPositionProperty, ConstantProperty, @@ -770,44 +772,38 @@ defineSuite([ expect(viewer.trackedEntity).toBeUndefined(); }); - it('returns to home when a tracked object is removed', function() { + it('stops tracking when tracked object is removed', function() { viewer = new Viewer(container); - //one data source that is added before mixing in - var preMixinDataSource = new MockDataSource(); - viewer.dataSources.add(preMixinDataSource); - - var beforeEntity = new Entity(); - beforeEntity.position = new ConstantProperty(new Cartesian3(123456, 123456, 123456)); - preMixinDataSource.entities.add(beforeEntity); - - //one data source that is added after mixing in - var postMixinDataSource = new MockDataSource(); - viewer.dataSources.add(postMixinDataSource); - var entity = new Entity(); entity.position = new ConstantProperty(new Cartesian3(123456, 123456, 123456)); - postMixinDataSource.entities.add(entity); + var dataSource = new MockDataSource(); + dataSource.entities.add(entity); + + viewer.dataSources.add(dataSource); viewer.trackedEntity = entity; + expect(viewer.trackedEntity).toBe(entity); + viewer.render(); + expect(Matrix4.getTranslation(viewer.scene.camera.transform, new Cartesian3())).toEqual(entity.position.getValue()); - // spy on the home button's command - Object.defineProperty(viewer.homeButton.viewModel, 'command', { - value : jasmine.createSpy('command') - }); + dataSource.entities.remove(entity); - postMixinDataSource.entities.remove(entity); + expect(viewer.trackedEntity).toBeUndefined(); + expect(viewer.scene.camera.transform).toEqual(Matrix4.IDENTITY); - expect(viewer.homeButton.viewModel.command).toHaveBeenCalled(); + dataSource.entities.add(entity); + viewer.trackedEntity = entity; - // reset the spy before removing the other entity - viewer.homeButton.viewModel.command.reset(); + expect(viewer.trackedEntity).toBe(entity); + viewer.render(); + expect(Matrix4.getTranslation(viewer.scene.camera.transform, new Cartesian3())).toEqual(entity.position.getValue()); - viewer.trackedEntity = beforeEntity; - preMixinDataSource.entities.remove(beforeEntity); + viewer.dataSources.remove(dataSource); - expect(viewer.homeButton.viewModel.command).toHaveBeenCalled(); + expect(viewer.trackedEntity).toBeUndefined(); + expect(viewer.scene.camera.transform).toEqual(Matrix4.IDENTITY); }); it('removes data source listeners when destroyed', function() {