Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend BaseLayerPicker to support terrain #1607

Merged
merged 12 commits into from
Apr 11, 2014
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Beta Releases
* `TilingScheme.extentToNativeRectangle` -> `TilingScheme.rectangleToNativeRectangle`
* `TilingScheme.tileXYToNativeExtent` -> `TilingScheme.tileXYToNativeRectangle`
* `TilingScheme.tileXYToExtent` -> `TilingScheme.tileXYToRectangle`
* `BaseLayerPicker` has been extended to support terrain selection. This includes many potential breaking changes, see [#1607](https:/AnalyticalGraphicsInc/cesium/pull/1607) for details.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to briefly list all the breaking changes, just as we've done every other time. Users doing an upgrade may not have direct internet access.

* `TimeIntervalCollection.clear` renamed to `TimeIntervalColection.removeAll`
* `Context` is now private
* Removed `Scene.context`: replaced by adding `drawingBufferWidth`, `drawingBufferHeight`, `maximumAliasedLineWidth` properties and `createTextureAtlas` function to `Scene`.
Expand Down
17 changes: 16 additions & 1 deletion Source/Widgets/BaseLayerPicker/BaseLayerPicker.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
position: absolute;
top: auto;
right: 0;
width: 240px;
width: 320px;
max-height: 500px;
margin-top: 5px;
background-color: rgba(38, 38, 38, 0.75);
Expand All @@ -40,6 +40,21 @@
user-select: none;
}

.cesium-baseLayerPicker-sectionTitle {
display: block;
font-family: sans-serif;
font-size: 16pt;
text-align: left;
color: #edffff;
}

.cesium-baseLayerPicker-choices {
display: block;
position: relative;
top: auto;
right: 0;
}

.cesium-baseLayerPicker-item {
display: inline-block;
vertical-align: top;
Expand Down
124 changes: 83 additions & 41 deletions Source/Widgets/BaseLayerPicker/BaseLayerPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,27 @@ define([
* <br />BaseLayerPicker with its drop-panel open.
* </span>
* <br /><br />
* The BaseLayerPicker is a single button widget that displays a panel of available imagery
* providers. When an item is selected, the corresponding imagery layer is created and inserted
* as the base layer of the imagery collection; removing the existing base. Each item in the
* available providers list contains a name, a representative icon, and a tooltip to display more
* information when hovered. The list is initially empty, and must be configured before use, as
* illustrated in the below example.
* The BaseLayerPicker is a single button widget that displays a panel of available imagery and
* terrain providers. When imagery is selected, the corresponding imagery layer is created and inserted
* as the base layer of the imagery collection; removing the existing base. When terrain is selected,
* it replaces the current terrain provider. Each item in the available providers list contains a name,
* a representative icon, and a tooltip to display more information when hovered. The list is initially
* empty, and must be configured before use, as illustrated in the below example.
*
* @alias BaseLayerPicker
* @constructor
*
* @param {Element} container The parent HTML container node for this widget.
* @param {ImageryLayerCollection} imageryLayers The imagery layer collection to use.
* @param {CentralBody} options.centralBody The CentralBody to use.
* @param {ProviderViewModel[]} [options.imageryProviderViewModels=[]] The array of ProviderViewModel instances to use for imagery.
* @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available base layer is used. This value is only valid if options.baseLayerPicker is set to true.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value is only valid if options.baseLayerPicker is set to true.

In this class, I don't think this comment makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh, my bad.

* @param {ProviderViewModel[]} [options.terrainProviderViewModels=[]] The array of ProviderViewModel instances to use for terrain.
* @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available base layer is used. This value is only valid if options.baseLayerPicker is set to true.
*
* @exception {DeveloperError} Element with id "container" does not exist in the document.
*
* @see TerrainProvider
* @see ImageryProvider
* @see ImageryProviderViewModel
* @see ImageryLayerCollection
*
* @example
Expand All @@ -49,8 +53,8 @@ define([
*
* //Create the list of available providers we would like the user to select from.
* //This example uses 3, OpenStreetMap, The Black Marble, and a single, non-streaming world image.
* var providerViewModels = [];
* providerViewModels.push(new Cesium.ImageryProviderViewModel({
* var imageryViewModels = [];
* imageryViewModels.push(new Cesium.ProviderViewModel({
* name : 'Open\u00adStreet\u00adMap',
* iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/openStreetMap.png'),
* tooltip : 'OpenStreetMap (OSM) is a collaborative project to create a free editable \
Expand All @@ -62,7 +66,7 @@ define([
* }
* }));
*
* providerViewModels.push(new Cesium.ImageryProviderViewModel({
* imageryViewModels.push(new Cesium.ProviderViewModel({
* name : 'Black Marble',
* iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/blackMarble.png'),
* tooltip : 'The lights of cities and villages trace the outlines of civilization \
Expand All @@ -76,7 +80,7 @@ define([
* }
* }));
*
* providerViewModels.push(new Cesium.ImageryProviderViewModel({
* imageryViewModels.push(new Cesium.ProviderViewModel({
* name : 'Natural Earth\u00a0II',
* iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/naturalEarthII.png'),
* tooltip : 'Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/',
Expand All @@ -92,78 +96,116 @@ define([
*
* //Finally, create the baseLayerPicker widget using our view models.
* var layers = cesiumWidget.centralBody.imageryLayers;
* var baseLayerPicker = new Cesium.BaseLayerPicker('baseLayerPickerContainer', layers, providerViewModels);
* var baseLayerPicker = new Cesium.BaseLayerPicker('baseLayerPickerContainer', layers, imageryViewModels);
*
* //Use the first item in the list as the current selection.
* baseLayerPicker.viewModel.selectedItem = providerViewModels[0];
* baseLayerPicker.viewModel.selectedItem = imageryViewModels[0];
*/
var BaseLayerPicker = function(container, imageryLayers, imageryProviderViewModels) {
var BaseLayerPicker = function(container, options) {
//>>includeStart('debug', pragmas.debug);
if (!defined(container)) {
throw new DeveloperError('container is required.');
}
if (!defined(imageryLayers)) {
throw new DeveloperError('imageryLayers is required.');
}
//>>includeEnd('debug');

container = getElement(container);

var viewModel = new BaseLayerPickerViewModel(imageryLayers, imageryProviderViewModels);
var viewModel = new BaseLayerPickerViewModel(options);

var element = document.createElement('button');
element.type = 'button';
element.className = 'cesium-button cesium-toolbar-button';
element.setAttribute('data-bind', '\
attr: { title: selectedName },\
attr: { title: buttonTooltip },\
click: toggleDropDown');
container.appendChild(element);

var imgElement = document.createElement('img');
imgElement.setAttribute('draggable', 'false');
imgElement.className = 'cesium-baseLayerPicker-selected';
imgElement.setAttribute('data-bind', '\
attr: { src: selectedIconUrl }');
attr: { src: buttonImageUrl }');
element.appendChild(imgElement);

var choices = document.createElement('div');
choices.className = 'cesium-baseLayerPicker-dropDown';
choices.setAttribute('data-bind', '\
var dropPanel = document.createElement('div');
dropPanel.className = 'cesium-baseLayerPicker-dropDown';
dropPanel.setAttribute('data-bind', '\
css: { "cesium-baseLayerPicker-visible" : dropDownVisible,\
"cesium-baseLayerPicker-hidden" : !dropDownVisible },\
foreach: imageryProviderViewModels');
container.appendChild(choices);

var provider = document.createElement('div');
provider.className = 'cesium-baseLayerPicker-item';
provider.setAttribute('data-bind', '\
css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedItem },\
"cesium-baseLayerPicker-hidden" : !dropDownVisible }');
container.appendChild(dropPanel);

var imageryTitle = document.createElement('div');
imageryTitle.className = 'cesium-baseLayerPicker-sectionTitle';
imageryTitle.setAttribute('data-bind', 'visible: imageryProviderViewModels.length > 0');
imageryTitle.innerHTML = 'Imagery<hr>';
dropPanel.appendChild(imageryTitle);

var imageryChoices = document.createElement('div');
imageryChoices.className = 'cesium-baseLayerPicker-choices';
imageryChoices.setAttribute('data-bind', 'foreach: imageryProviderViewModels');
dropPanel.appendChild(imageryChoices);

var imageryProvider = document.createElement('div');
imageryProvider.className = 'cesium-baseLayerPicker-item';
imageryProvider.setAttribute('data-bind', '\
css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedImagery },\
attr: { title: tooltip },\
visible: creationCommand.canExecute,\
click: function($data) { $parent.selectedItem = $data; }');
choices.appendChild(provider);
click: function($data) { $parent.selectedImagery = $data; }');
imageryChoices.appendChild(imageryProvider);

var providerIcon = document.createElement('img');
providerIcon.className = 'cesium-baseLayerPicker-itemIcon';
providerIcon.setAttribute('data-bind', 'attr: { src: iconUrl }');
providerIcon.setAttribute('draggable', 'false');
provider.appendChild(providerIcon);
imageryProvider.appendChild(providerIcon);

var providerLabel = document.createElement('div');
providerLabel.className = 'cesium-baseLayerPicker-itemLabel';
providerLabel.setAttribute('data-bind', 'text: name');
provider.appendChild(providerLabel);
imageryProvider.appendChild(providerLabel);

var terrainTitle = document.createElement('div');
terrainTitle.className = 'cesium-baseLayerPicker-sectionTitle';
terrainTitle.setAttribute('data-bind', 'visible: terrainProviderViewModels.length > 0');
terrainTitle.innerHTML = 'Terrain<hr>';
dropPanel.appendChild(terrainTitle);

var terrainChoices = document.createElement('div');
terrainChoices.className = 'cesium-baseLayerPicker-choices';
terrainChoices.setAttribute('data-bind', 'foreach: terrainProviderViewModels');
dropPanel.appendChild(terrainChoices);

var terrainProvider = document.createElement('div');
terrainProvider.className = 'cesium-baseLayerPicker-item';
terrainProvider.setAttribute('data-bind', '\
css: { "cesium-baseLayerPicker-selectedItem" : $data === $parent.selectedTerrain },\
attr: { title: tooltip },\
visible: creationCommand.canExecute,\
click: function($data) { $parent.selectedTerrain = $data; }');
terrainChoices.appendChild(terrainProvider);

var terrainProviderIcon = document.createElement('img');
terrainProviderIcon.className = 'cesium-baseLayerPicker-itemIcon';
terrainProviderIcon.setAttribute('data-bind', 'attr: { src: iconUrl }');
terrainProviderIcon.setAttribute('draggable', 'false');
terrainProvider.appendChild(terrainProviderIcon);

var terrainProviderLabel = document.createElement('div');
terrainProviderLabel.className = 'cesium-baseLayerPicker-itemLabel';
terrainProviderLabel.setAttribute('data-bind', 'text: name');
terrainProvider.appendChild(terrainProviderLabel);

knockout.applyBindings(viewModel, element);
knockout.applyBindings(viewModel, choices);
knockout.applyBindings(viewModel, dropPanel);

this._viewModel = viewModel;
this._container = container;
this._element = element;
this._choices = choices;
this._dropPanel = dropPanel;

this._closeDropDown = function(e) {
if (!(element.contains(e.target) || choices.contains(e.target))) {
if (!(element.contains(e.target) || dropPanel.contains(e.target))) {
viewModel.dropDownVisible = false;
}
};
Expand Down Expand Up @@ -215,9 +257,9 @@ click: function($data) { $parent.selectedItem = $data; }');
document.removeEventListener('mousedown', this._closeDropDown, true);
document.removeEventListener('touchstart', this._closeDropDown, true);
knockout.cleanNode(this._element);
knockout.cleanNode(this._choices);
knockout.cleanNode(this._dropPanel);
this._container.removeChild(this._element);
this._container.removeChild(this._choices);
this._container.removeChild(this._dropPanel);
return destroyObject(this);
};

Expand Down
Loading