You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
561 lines
16 KiB
JavaScript
561 lines
16 KiB
JavaScript
import AssociativeArray from "../Core/AssociativeArray.js";
|
|
import buildModuleUrl from "../Core/buildModuleUrl.js";
|
|
import Check from "../Core/Check.js";
|
|
import Credit from "../Core/Credit.js";
|
|
import defaultValue from "../Core/defaultValue.js";
|
|
import defined from "../Core/defined.js";
|
|
import destroyObject from "../Core/destroyObject.js";
|
|
import Uri from "../ThirdParty/Uri.js";
|
|
|
|
var mobileWidth = 576;
|
|
var lightboxHeight = 100;
|
|
var textColor = "#ffffff";
|
|
var highlightColor = "#48b";
|
|
|
|
function contains(credits, credit) {
|
|
var len = credits.length;
|
|
for (var i = 0; i < len; i++) {
|
|
var existingCredit = credits[i];
|
|
if (Credit.equals(existingCredit, credit)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function swapCesiumCredit(creditDisplay) {
|
|
// We don't want to clutter the screen with the Cesium logo and the Cesium ion
|
|
// logo at the same time. Since the ion logo is required, we just replace the
|
|
// Cesium logo or add the logo if the Cesium one was removed.
|
|
var previousCredit = creditDisplay._previousCesiumCredit;
|
|
var currentCredit = creditDisplay._currentCesiumCredit;
|
|
if (Credit.equals(currentCredit, previousCredit)) {
|
|
return;
|
|
}
|
|
|
|
if (defined(previousCredit)) {
|
|
creditDisplay._cesiumCreditContainer.removeChild(previousCredit.element);
|
|
}
|
|
if (defined(currentCredit)) {
|
|
creditDisplay._cesiumCreditContainer.appendChild(currentCredit.element);
|
|
}
|
|
|
|
creditDisplay._previousCesiumCredit = currentCredit;
|
|
}
|
|
|
|
var delimiterClassName = "cesium-credit-delimiter";
|
|
|
|
function createDelimiterElement(delimiter) {
|
|
var delimiterElement = document.createElement("span");
|
|
delimiterElement.textContent = delimiter;
|
|
delimiterElement.className = delimiterClassName;
|
|
return delimiterElement;
|
|
}
|
|
|
|
function createCreditElement(element, elementWrapperTagName) {
|
|
// may need to wrap the credit in another element
|
|
if (defined(elementWrapperTagName)) {
|
|
var wrapper = document.createElement(elementWrapperTagName);
|
|
wrapper._creditId = element._creditId;
|
|
wrapper.appendChild(element);
|
|
element = wrapper;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
function displayCredits(container, credits, delimiter, elementWrapperTagName) {
|
|
var childNodes = container.childNodes;
|
|
var domIndex = -1;
|
|
for (var creditIndex = 0; creditIndex < credits.length; ++creditIndex) {
|
|
var credit = credits[creditIndex];
|
|
if (defined(credit)) {
|
|
domIndex = creditIndex;
|
|
if (defined(delimiter)) {
|
|
// credits may be separated by delimiters
|
|
domIndex *= 2;
|
|
if (creditIndex > 0) {
|
|
var delimiterDomIndex = domIndex - 1;
|
|
if (childNodes.length <= delimiterDomIndex) {
|
|
container.appendChild(createDelimiterElement(delimiter));
|
|
} else {
|
|
var existingDelimiter = childNodes[delimiterDomIndex];
|
|
if (existingDelimiter.className !== delimiterClassName) {
|
|
container.replaceChild(
|
|
createDelimiterElement(delimiter),
|
|
existingDelimiter
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var element = credit.element;
|
|
|
|
// check to see if the correct credit is in the right place
|
|
if (childNodes.length <= domIndex) {
|
|
container.appendChild(
|
|
createCreditElement(element, elementWrapperTagName)
|
|
);
|
|
} else {
|
|
var existingElement = childNodes[domIndex];
|
|
if (existingElement._creditId !== credit._id) {
|
|
// not the right credit, swap it in
|
|
container.replaceChild(
|
|
createCreditElement(element, elementWrapperTagName),
|
|
existingElement
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// any remaining nodes in the container are unnecessary
|
|
++domIndex;
|
|
while (domIndex < childNodes.length) {
|
|
container.removeChild(childNodes[domIndex]);
|
|
}
|
|
}
|
|
|
|
function styleLightboxContainer(that) {
|
|
var lightboxCredits = that._lightboxCredits;
|
|
var width = that.viewport.clientWidth;
|
|
var height = that.viewport.clientHeight;
|
|
if (width !== that._lastViewportWidth) {
|
|
if (width < mobileWidth) {
|
|
lightboxCredits.className =
|
|
"cesium-credit-lightbox cesium-credit-lightbox-mobile";
|
|
lightboxCredits.style.marginTop = "0";
|
|
} else {
|
|
lightboxCredits.className =
|
|
"cesium-credit-lightbox cesium-credit-lightbox-expanded";
|
|
lightboxCredits.style.marginTop =
|
|
Math.floor((height - lightboxCredits.clientHeight) * 0.5) + "px";
|
|
}
|
|
that._lastViewportWidth = width;
|
|
}
|
|
|
|
if (width >= mobileWidth && height !== that._lastViewportHeight) {
|
|
lightboxCredits.style.marginTop =
|
|
Math.floor((height - lightboxCredits.clientHeight) * 0.5) + "px";
|
|
that._lastViewportHeight = height;
|
|
}
|
|
}
|
|
|
|
function addStyle(selector, styles) {
|
|
var style = selector + " {";
|
|
for (var attribute in styles) {
|
|
if (styles.hasOwnProperty(attribute)) {
|
|
style += attribute + ": " + styles[attribute] + "; ";
|
|
}
|
|
}
|
|
style += " }\n";
|
|
return style;
|
|
}
|
|
|
|
function appendCss() {
|
|
var style = "";
|
|
style += addStyle(".cesium-credit-lightbox-overlay", {
|
|
display: "none",
|
|
"z-index": "1", //must be at least 1 to draw over top other Cesium widgets
|
|
position: "absolute",
|
|
top: "0",
|
|
left: "0",
|
|
width: "100%",
|
|
height: "100%",
|
|
"background-color": "rgba(80, 80, 80, 0.8)",
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox", {
|
|
"background-color": "#303336",
|
|
color: textColor,
|
|
position: "relative",
|
|
"min-height": lightboxHeight + "px",
|
|
margin: "auto",
|
|
});
|
|
|
|
style += addStyle(
|
|
".cesium-credit-lightbox > ul > li a, .cesium-credit-lightbox > ul > li a:visited",
|
|
{
|
|
color: textColor,
|
|
}
|
|
);
|
|
|
|
style += addStyle(".cesium-credit-lightbox > ul > li a:hover", {
|
|
color: highlightColor,
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox.cesium-credit-lightbox-expanded", {
|
|
border: "1px solid #444",
|
|
"border-radius": "5px",
|
|
"max-width": "370px",
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox.cesium-credit-lightbox-mobile", {
|
|
height: "100%",
|
|
width: "100%",
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox-title", {
|
|
padding: "20px 20px 0 20px",
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox-close", {
|
|
"font-size": "18pt",
|
|
cursor: "pointer",
|
|
position: "absolute",
|
|
top: "0",
|
|
right: "6px",
|
|
color: textColor,
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox-close:hover", {
|
|
color: highlightColor,
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox > ul", {
|
|
margin: "0",
|
|
padding: "12px 20px 12px 40px",
|
|
"font-size": "13px",
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox > ul > li", {
|
|
"padding-bottom": "6px",
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-lightbox > ul > li *", {
|
|
padding: "0",
|
|
margin: "0",
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-expand-link", {
|
|
"padding-left": "5px",
|
|
cursor: "pointer",
|
|
"text-decoration": "underline",
|
|
color: textColor,
|
|
});
|
|
style += addStyle(".cesium-credit-expand-link:hover", {
|
|
color: highlightColor,
|
|
});
|
|
|
|
style += addStyle(".cesium-credit-text", {
|
|
color: textColor,
|
|
});
|
|
|
|
style += addStyle(
|
|
".cesium-credit-textContainer *, .cesium-credit-logoContainer *",
|
|
{
|
|
display: "inline",
|
|
}
|
|
);
|
|
|
|
var head = document.head;
|
|
var css = document.createElement("style");
|
|
css.innerHTML = style;
|
|
head.insertBefore(css, head.firstChild);
|
|
}
|
|
|
|
/**
|
|
* The credit display is responsible for displaying credits on screen.
|
|
*
|
|
* @param {HTMLElement} container The HTML element where credits will be displayed
|
|
* @param {String} [delimiter= ' • '] The string to separate text credits
|
|
* @param {HTMLElement} [viewport=document.body] The HTML element that will contain the credits popup
|
|
*
|
|
* @alias CreditDisplay
|
|
* @constructor
|
|
*
|
|
* @example
|
|
* var creditDisplay = new Cesium.CreditDisplay(creditContainer);
|
|
*/
|
|
function CreditDisplay(container, delimiter, viewport) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.defined("container", container);
|
|
//>>includeEnd('debug');
|
|
var that = this;
|
|
|
|
viewport = defaultValue(viewport, document.body);
|
|
|
|
var lightbox = document.createElement("div");
|
|
lightbox.className = "cesium-credit-lightbox-overlay";
|
|
viewport.appendChild(lightbox);
|
|
|
|
var lightboxCredits = document.createElement("div");
|
|
lightboxCredits.className = "cesium-credit-lightbox";
|
|
lightbox.appendChild(lightboxCredits);
|
|
|
|
function hideLightbox(event) {
|
|
if (lightboxCredits.contains(event.target)) {
|
|
return;
|
|
}
|
|
that.hideLightbox();
|
|
}
|
|
lightbox.addEventListener("click", hideLightbox, false);
|
|
|
|
var title = document.createElement("div");
|
|
title.className = "cesium-credit-lightbox-title";
|
|
title.textContent = "Data provided by:";
|
|
lightboxCredits.appendChild(title);
|
|
|
|
var closeButton = document.createElement("a");
|
|
closeButton.onclick = this.hideLightbox.bind(this);
|
|
closeButton.innerHTML = "×";
|
|
closeButton.className = "cesium-credit-lightbox-close";
|
|
lightboxCredits.appendChild(closeButton);
|
|
|
|
var creditList = document.createElement("ul");
|
|
lightboxCredits.appendChild(creditList);
|
|
|
|
var cesiumCreditContainer = document.createElement("div");
|
|
cesiumCreditContainer.className = "cesium-credit-logoContainer";
|
|
cesiumCreditContainer.style.display = "inline";
|
|
container.appendChild(cesiumCreditContainer);
|
|
|
|
var screenContainer = document.createElement("div");
|
|
screenContainer.className = "cesium-credit-textContainer";
|
|
screenContainer.style.display = "inline";
|
|
container.appendChild(screenContainer);
|
|
|
|
var expandLink = document.createElement("a");
|
|
expandLink.className = "cesium-credit-expand-link";
|
|
expandLink.onclick = this.showLightbox.bind(this);
|
|
expandLink.textContent = "Data attribution";
|
|
container.appendChild(expandLink);
|
|
|
|
appendCss();
|
|
var cesiumCredit = Credit.clone(CreditDisplay.cesiumCredit);
|
|
|
|
this._delimiter = defaultValue(delimiter, " • ");
|
|
this._screenContainer = screenContainer;
|
|
this._cesiumCreditContainer = cesiumCreditContainer;
|
|
this._lastViewportHeight = undefined;
|
|
this._lastViewportWidth = undefined;
|
|
this._lightboxCredits = lightboxCredits;
|
|
this._creditList = creditList;
|
|
this._lightbox = lightbox;
|
|
this._hideLightbox = hideLightbox;
|
|
this._expandLink = expandLink;
|
|
this._expanded = false;
|
|
this._defaultCredits = [];
|
|
this._cesiumCredit = cesiumCredit;
|
|
this._previousCesiumCredit = undefined;
|
|
this._currentCesiumCredit = cesiumCredit;
|
|
this._currentFrameCredits = {
|
|
screenCredits: new AssociativeArray(),
|
|
lightboxCredits: new AssociativeArray(),
|
|
};
|
|
this._defaultCredit = undefined;
|
|
|
|
this.viewport = viewport;
|
|
|
|
/**
|
|
* The HTML element where credits will be displayed.
|
|
* @type {HTMLElement}
|
|
*/
|
|
this.container = container;
|
|
}
|
|
|
|
/**
|
|
* Adds a credit to the list of current credits to be displayed in the credit container
|
|
*
|
|
* @param {Credit} credit The credit to display
|
|
*/
|
|
CreditDisplay.prototype.addCredit = function (credit) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.defined("credit", credit);
|
|
//>>includeEnd('debug');
|
|
|
|
if (credit._isIon) {
|
|
// If this is the an ion logo credit from the ion server
|
|
// Juse use the default credit (which is identical) to avoid blinking
|
|
if (!defined(this._defaultCredit)) {
|
|
this._defaultCredit = Credit.clone(getDefaultCredit());
|
|
}
|
|
this._currentCesiumCredit = this._defaultCredit;
|
|
return;
|
|
}
|
|
|
|
if (!credit.showOnScreen) {
|
|
this._currentFrameCredits.lightboxCredits.set(credit.id, credit);
|
|
} else {
|
|
this._currentFrameCredits.screenCredits.set(credit.id, credit);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Adds credits that will persist until they are removed
|
|
*
|
|
* @param {Credit} credit The credit to added to defaults
|
|
*/
|
|
CreditDisplay.prototype.addDefaultCredit = function (credit) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.defined("credit", credit);
|
|
//>>includeEnd('debug');
|
|
|
|
var defaultCredits = this._defaultCredits;
|
|
if (!contains(defaultCredits, credit)) {
|
|
defaultCredits.push(credit);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Removes a default credit
|
|
*
|
|
* @param {Credit} credit The credit to be removed from defaults
|
|
*/
|
|
CreditDisplay.prototype.removeDefaultCredit = function (credit) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.defined("credit", credit);
|
|
//>>includeEnd('debug');
|
|
|
|
var defaultCredits = this._defaultCredits;
|
|
var index = defaultCredits.indexOf(credit);
|
|
if (index !== -1) {
|
|
defaultCredits.splice(index, 1);
|
|
}
|
|
};
|
|
|
|
CreditDisplay.prototype.showLightbox = function () {
|
|
this._lightbox.style.display = "block";
|
|
this._expanded = true;
|
|
};
|
|
|
|
CreditDisplay.prototype.hideLightbox = function () {
|
|
this._lightbox.style.display = "none";
|
|
this._expanded = false;
|
|
};
|
|
|
|
/**
|
|
* Updates the credit display before a new frame is rendered.
|
|
*/
|
|
CreditDisplay.prototype.update = function () {
|
|
if (this._expanded) {
|
|
styleLightboxContainer(this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Resets the credit display to a beginning of frame state, clearing out current credits.
|
|
*/
|
|
CreditDisplay.prototype.beginFrame = function () {
|
|
var currentFrameCredits = this._currentFrameCredits;
|
|
|
|
var screenCredits = currentFrameCredits.screenCredits;
|
|
screenCredits.removeAll();
|
|
var defaultCredits = this._defaultCredits;
|
|
for (var i = 0; i < defaultCredits.length; ++i) {
|
|
var defaultCredit = defaultCredits[i];
|
|
screenCredits.set(defaultCredit.id, defaultCredit);
|
|
}
|
|
|
|
currentFrameCredits.lightboxCredits.removeAll();
|
|
|
|
if (!Credit.equals(CreditDisplay.cesiumCredit, this._cesiumCredit)) {
|
|
this._cesiumCredit = Credit.clone(CreditDisplay.cesiumCredit);
|
|
}
|
|
this._currentCesiumCredit = this._cesiumCredit;
|
|
};
|
|
|
|
/**
|
|
* Sets the credit display to the end of frame state, displaying credits from the last frame in the credit container.
|
|
*/
|
|
CreditDisplay.prototype.endFrame = function () {
|
|
var screenCredits = this._currentFrameCredits.screenCredits.values;
|
|
displayCredits(
|
|
this._screenContainer,
|
|
screenCredits,
|
|
this._delimiter,
|
|
undefined
|
|
);
|
|
|
|
var lightboxCredits = this._currentFrameCredits.lightboxCredits.values;
|
|
this._expandLink.style.display =
|
|
lightboxCredits.length > 0 ? "inline" : "none";
|
|
displayCredits(this._creditList, lightboxCredits, undefined, "li");
|
|
|
|
swapCesiumCredit(this);
|
|
};
|
|
|
|
/**
|
|
* Destroys the resources held by this object. Destroying an object allows for deterministic
|
|
* release of resources, instead of relying on the garbage collector to destroy this object.
|
|
* <br /><br />
|
|
* Once an object is destroyed, it should not be used; calling any function other than
|
|
* <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
|
|
* assign the return value (<code>undefined</code>) to the object as done in the example.
|
|
*
|
|
* @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
|
|
*/
|
|
CreditDisplay.prototype.destroy = function () {
|
|
this._lightbox.removeEventListener("click", this._hideLightbox, false);
|
|
|
|
this.container.removeChild(this._cesiumCreditContainer);
|
|
this.container.removeChild(this._screenContainer);
|
|
this.container.removeChild(this._expandLink);
|
|
this.viewport.removeChild(this._lightbox);
|
|
|
|
return destroyObject(this);
|
|
};
|
|
|
|
/**
|
|
* Returns true if this object was destroyed; otherwise, false.
|
|
* <br /><br />
|
|
*
|
|
* @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
|
|
*/
|
|
CreditDisplay.prototype.isDestroyed = function () {
|
|
return false;
|
|
};
|
|
|
|
CreditDisplay._cesiumCredit = undefined;
|
|
CreditDisplay._cesiumCreditInitialized = false;
|
|
|
|
var defaultCredit;
|
|
function getDefaultCredit() {
|
|
if (!defined(defaultCredit)) {
|
|
var logo = buildModuleUrl("Assets/Images/ion-credit.png");
|
|
|
|
// When hosting in a WebView, the base URL scheme is file:// or ms-appx-web://
|
|
// which is stripped out from the Credit's <img> tag; use the full path instead
|
|
if (
|
|
logo.indexOf("http://") !== 0 &&
|
|
logo.indexOf("https://") !== 0 &&
|
|
logo.indexOf("data:") !== 0
|
|
) {
|
|
var logoUrl = new Uri(logo);
|
|
logo = logoUrl.getPath();
|
|
}
|
|
|
|
defaultCredit = new Credit(
|
|
'<a href="https://cesium.com/" target="_blank"><img src="' +
|
|
logo +
|
|
'" title="Cesium ion"/></a>',
|
|
true
|
|
);
|
|
}
|
|
|
|
if (!CreditDisplay._cesiumCreditInitialized) {
|
|
CreditDisplay._cesiumCredit = defaultCredit;
|
|
CreditDisplay._cesiumCreditInitialized = true;
|
|
}
|
|
return defaultCredit;
|
|
}
|
|
|
|
Object.defineProperties(CreditDisplay, {
|
|
/**
|
|
* Gets or sets the Cesium logo credit.
|
|
* @memberof CreditDisplay
|
|
* @type {Credit}
|
|
*/
|
|
cesiumCredit: {
|
|
get: function () {
|
|
getDefaultCredit();
|
|
return CreditDisplay._cesiumCredit;
|
|
},
|
|
set: function (value) {
|
|
CreditDisplay._cesiumCredit = value;
|
|
CreditDisplay._cesiumCreditInitialized = true;
|
|
},
|
|
},
|
|
});
|
|
export default CreditDisplay;
|