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 defineProperties from '../Core/defineProperties.js'; import destroyObject from '../Core/destroyObject.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. *

* Once an object is destroyed, it should not be used; calling any function other than * isDestroyed will result in a {@link DeveloperError} exception. Therefore, * assign the return value (undefined) 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. *

* * @returns {Boolean} true if this object was destroyed; otherwise, false. */ 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'); defaultCredit = new Credit('', true); } if (!CreditDisplay._cesiumCreditInitialized) { CreditDisplay._cesiumCredit = defaultCredit; CreditDisplay._cesiumCreditInitialized = true; } return defaultCredit; } 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;