diff --git a/CHANGES.md b/CHANGES.md index 6e765d955ffb..c2d04162ecdd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,8 +9,8 @@ Change Log * Fixed a bug where picking clusters would return undefined instead of a list of the clustered entities. [#5286](https://github.com/AnalyticalGraphicsInc/cesium/issues/5286) * Reduced the amount of Sun bloom post-process effect near the horizon. [#5381](https://github.com/AnalyticalGraphicsInc/cesium/issues/5381) * Added Sandcastle demo for ArcticDEM data. [#5224](https://github.com/AnalyticalGraphicsInc/cesium/issues/5224) +* `CzmlDataSource` and `KmlDataSource` load functions now take an optional `query` object, which will append query parameters to all network requests. [#5419](https://github.com/AnalyticalGraphicsInc/cesium/pull/5419), [#5434](https://github.com/AnalyticalGraphicsInc/cesium/pull/5434) * Fixed geocoder bug so geocoder can accurately handle NSEW inputs [#5407] (https://github.com/AnalyticalGraphicsInc/cesium/pull/5407) -* `CzmlDataSource` load functions now take an optional `query` object, which will append query parameters to all network requests. [#5419](https://github.com/AnalyticalGraphicsInc/cesium/pull/5419) ### 1.34 - 2017-06-01 diff --git a/Source/DataSources/KmlDataSource.js b/Source/DataSources/KmlDataSource.js index 87f00c7f7a35..766674a9e4e0 100644 --- a/Source/DataSources/KmlDataSource.js +++ b/Source/DataSources/KmlDataSource.js @@ -25,6 +25,7 @@ define([ '../Core/loadXML', '../Core/Math', '../Core/NearFarScalar', + '../Core/objectToQuery', '../Core/PinBuilder', '../Core/PolygonHierarchy', '../Core/Rectangle', @@ -84,6 +85,7 @@ define([ loadXML, CesiumMath, NearFarScalar, + objectToQuery, PinBuilder, PolygonHierarchy, Rectangle, @@ -272,22 +274,25 @@ define([ } } - function applyBasePath(div, elementType, attributeName, proxy, sourceUri) { + function applyBasePath(div, elementType, attributeName, proxy, sourceUri, query) { var elements = div.querySelectorAll(elementType); for (var i = 0; i < elements.length; i++) { var element = elements[i]; var value = element.getAttribute(attributeName); - var uri = resolveHref(value, proxy, sourceUri); + var uri = resolveHref(value, proxy, sourceUri, query); element.setAttribute(attributeName, uri); } } - function proxyUrl(url, proxy) { + function proxyUrl(url, proxy, query) { if (defined(proxy)) { if (new Uri(url).isAbsolute()) { url = proxy.getURL(url); } } + if (defined(query)) { + url = joinUrls(url, '?' + query, false); + } return url; } @@ -467,7 +472,7 @@ define([ return undefined; } - function resolveHref(href, proxy, sourceUri, uriResolver) { + function resolveHref(href, proxy, sourceUri, uriResolver, query) { if (!defined(href)) { return undefined; } @@ -487,9 +492,11 @@ define([ } } } - if (!hrefResolved && defined(sourceUri)) { - href = getAbsoluteUri(href, getAbsoluteUri(sourceUri)); - href = proxyUrl(href, proxy); + if (!hrefResolved) { + if (defined(sourceUri)) { + href = getAbsoluteUri(href, getAbsoluteUri(sourceUri)); + } + href = proxyUrl(href, proxy, query); } return href; } @@ -630,7 +637,7 @@ define([ return label; } - function getIconHref(iconNode, dataSource, sourceUri, uriResolver, canRefresh) { + function getIconHref(iconNode, dataSource, sourceUri, uriResolver, canRefresh, query) { var href = queryStringValue(iconNode, 'href', namespaces.kml); if (!defined(href) || (href.length === 0)) { return undefined; @@ -649,7 +656,7 @@ define([ href = 'https://maps.google.com/mapfiles/kml/pal' + palette + '/icon' + iconNum + '.png'; } - href = resolveHref(href, dataSource._proxy, sourceUri, uriResolver); + href = resolveHref(href, dataSource._proxy, sourceUri, uriResolver, query); if (canRefresh) { var refreshMode = queryStringValue(iconNode, 'refreshMode', namespaces.kml); @@ -673,13 +680,13 @@ define([ return href; } - function processBillboardIcon(dataSource, node, targetEntity, sourceUri, uriResolver) { + function processBillboardIcon(dataSource, node, targetEntity, sourceUri, uriResolver, query) { var scale = queryNumericValue(node, 'scale', namespaces.kml); var heading = queryNumericValue(node, 'heading', namespaces.kml); var color = queryColorValue(node, 'color', namespaces.kml); var iconNode = queryFirstNode(node, 'Icon', namespaces.kml); - var icon = getIconHref(iconNode, dataSource, sourceUri, uriResolver, false); + var icon = getIconHref(iconNode, dataSource, sourceUri, uriResolver, false, query); var x = queryNumericValue(iconNode, 'x', namespaces.gx); var y = queryNumericValue(iconNode, 'y', namespaces.gx); var w = queryNumericValue(iconNode, 'w', namespaces.gx); @@ -748,11 +755,11 @@ define([ } } - function applyStyle(dataSource, styleNode, targetEntity, sourceUri, uriResolver) { + function applyStyle(dataSource, styleNode, targetEntity, sourceUri, uriResolver, query) { for (var i = 0, len = styleNode.childNodes.length; i < len; i++) { var node = styleNode.childNodes.item(i); if (node.localName === 'IconStyle') { - processBillboardIcon(dataSource, node, targetEntity, sourceUri, uriResolver); + processBillboardIcon(dataSource, node, targetEntity, sourceUri, uriResolver, query); } else if (node.localName === 'LabelStyle') { var label = targetEntity.label; if (!defined(label)) { @@ -814,7 +821,7 @@ define([ } //Processes and merges any inline styles for the provided node into the provided entity. - function computeFinalStyle(entity, dataSource, placeMark, styleCollection, sourceUri, uriResolver) { + function computeFinalStyle(entity, dataSource, placeMark, styleCollection, sourceUri, uriResolver, query) { var result = new Entity(); var styleEntity; @@ -832,7 +839,7 @@ define([ if (styleIndex !== -1) { var inlineStyleNode = childNodes[styleIndex]; if (inlineStyleNode.localName === 'Style') { - applyStyle(dataSource, inlineStyleNode, result, sourceUri, uriResolver); + applyStyle(dataSource, inlineStyleNode, result, sourceUri, uriResolver, query); } else { // StyleMap var pairs = queryChildNodes(inlineStyleNode, 'Pair', namespaces.kml); for (var p = 0; p < pairs.length; p++) { @@ -850,7 +857,7 @@ define([ } } else { var node = queryFirstNode(pair, 'Style', namespaces.kml); - applyStyle(dataSource, node, result, sourceUri, uriResolver); + applyStyle(dataSource, node, result, sourceUri, uriResolver, query); } } else { console.log('KML - Unsupported StyleMap key: ' + key); @@ -885,8 +892,8 @@ define([ } //Asynchronously processes an external style file. - function processExternalStyles(dataSource, uri, styleCollection) { - return loadXML(proxyUrl(uri, dataSource._proxy)).then(function(styleKml) { + function processExternalStyles(dataSource, uri, styleCollection, query) { + return loadXML(proxyUrl(uri, dataSource._proxy, query)).then(function(styleKml) { return processStyles(dataSource, styleKml, styleCollection, uri, true); }); } @@ -895,7 +902,7 @@ define([ //their id into the provided styleCollection. //Returns an array of promises that will resolve when //each style is loaded. - function processStyles(dataSource, kml, styleCollection, sourceUri, isExternal, uriResolver) { + function processStyles(dataSource, kml, styleCollection, sourceUri, isExternal, uriResolver, query) { var i; var id; var styleEntity; @@ -917,7 +924,7 @@ define([ id : id }); styleCollection.add(styleEntity); - applyStyle(dataSource, node, styleEntity, sourceUri, uriResolver); + applyStyle(dataSource, node, styleEntity, sourceUri, uriResolver, query); } } } @@ -958,7 +965,7 @@ define([ } } else { node = queryFirstNode(pair, 'Style', namespaces.kml); - applyStyle(dataSource, node, styleEntity, sourceUri, uriResolver); + applyStyle(dataSource, node, styleEntity, sourceUri, uriResolver, query); } } } else { @@ -987,7 +994,7 @@ define([ if (defined(sourceUri)) { uri = getAbsoluteUri(uri, getAbsoluteUri(sourceUri)); } - promises.push(processExternalStyles(dataSource, uri, styleCollection, sourceUri)); + promises.push(processExternalStyles(dataSource, uri, styleCollection, query)); } } } @@ -1547,10 +1554,10 @@ define([ entity.description = tmp; } - function processFeature(dataSource, parent, featureNode, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) { + function processFeature(dataSource, parent, featureNode, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query) { var entity = createEntity(featureNode, entityCollection, context); var kmlData = entity.kml; - var styleEntity = computeFinalStyle(entity, dataSource, featureNode, styleCollection, sourceUri, uriResolver); + var styleEntity = computeFinalStyle(entity, dataSource, featureNode, styleCollection, sourceUri, uriResolver, query); var name = queryStringValue(featureNode, 'name', namespaces.kml); entity.name = name; @@ -1625,7 +1632,7 @@ define([ Model : processUnsupportedGeometry }; - function processDocument(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) { + function processDocument(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query) { var featureTypeNames = Object.keys(featureTypes); var featureTypeNamesLength = featureTypeNames.length; @@ -1639,19 +1646,19 @@ define([ var child = childNodes[q]; if (child.localName === featureName && ((namespaces.kml.indexOf(child.namespaceURI) !== -1) || (namespaces.gx.indexOf(child.namespaceURI) !== -1))) { - processFeatureNode(dataSource, parent, child, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); + processFeatureNode(dataSource, parent, child, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); } } } } - function processFolder(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) { - var r = processFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); - processDocument(dataSource, r.entity, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); + function processFolder(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query) { + var r = processFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); + processDocument(dataSource, r.entity, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); } - function processPlacemark(dataSource, parent, placemark, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) { - var r = processFeature(dataSource, parent, placemark, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); + function processPlacemark(dataSource, parent, placemark, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query) { + var r = processFeature(dataSource, parent, placemark, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); var entity = r.entity; var styleEntity = r.styleEntity; @@ -1674,8 +1681,8 @@ define([ } } - function processGroundOverlay(dataSource, parent, groundOverlay, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) { - var r = processFeature(dataSource, parent, groundOverlay, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); + function processGroundOverlay(dataSource, parent, groundOverlay, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query) { + var r = processFeature(dataSource, parent, groundOverlay, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); var entity = r.entity; var geometry; @@ -1720,7 +1727,7 @@ define([ } var iconNode = queryFirstNode(groundOverlay, 'Icon', namespaces.kml); - var href = getIconHref(iconNode, dataSource, sourceUri, uriResolver, true); + var href = getIconHref(iconNode, dataSource, sourceUri, uriResolver, true, query); if (defined(href)) { if (isLatLonQuad) { console.log('KML - gx:LatLonQuad Icon does not support texture projection.'); @@ -1932,8 +1939,8 @@ define([ return queryString; } - function processNetworkLink(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) { - var r = processFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); + function processNetworkLink(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query) { + var r = processFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); var networkEntity = r.entity; var link = queryFirstNode(node, 'Link', namespaces.kml); @@ -1945,7 +1952,7 @@ define([ var href = queryStringValue(link, 'href', namespaces.kml); if (defined(href)) { var newSourceUri = href; - href = resolveHref(href, undefined, sourceUri, uriResolver); + href = resolveHref(href, undefined, sourceUri, uriResolver, query); var linkUrl; // We need to pass in the original path if resolveHref returns a data uri because the network link @@ -2079,16 +2086,16 @@ define([ Tour : processUnsupportedFeature }; - function processFeatureNode(dataSource, node, parent, entityCollection, styleCollection, sourceUri, uriResolver, promises, context) { + function processFeatureNode(dataSource, node, parent, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query) { var featureProcessor = featureTypes[node.localName]; if (defined(featureProcessor)) { - featureProcessor(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); + featureProcessor(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); } else { processUnsupportedFeature(dataSource, parent, node, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); } } - function loadKml(dataSource, entityCollection, kml, sourceUri, uriResolver, context) { + function loadKml(dataSource, entityCollection, kml, sourceUri, uriResolver, context, query) { entityCollection.removeAll(); var promises = []; @@ -2105,7 +2112,7 @@ define([ } var styleCollection = new EntityCollection(dataSource); - return when.all(processStyles(dataSource, kml, styleCollection, sourceUri, false, uriResolver, context)).then(function() { + return when.all(processStyles(dataSource, kml, styleCollection, sourceUri, false, uriResolver, query)).then(function() { var element = kml.documentElement; if (element.localName === 'kml') { var childNodes = element.childNodes; @@ -2118,7 +2125,7 @@ define([ } } entityCollection.suspendEvents(); - processFeatureNode(dataSource, element, undefined, entityCollection, styleCollection, sourceUri, uriResolver, promises, context); + processFeatureNode(dataSource, element, undefined, entityCollection, styleCollection, sourceUri, uriResolver, promises, context, query); entityCollection.resumeEvents(); return when.all(promises).then(function() { @@ -2187,10 +2194,11 @@ define([ var sourceUri = options.sourceUri; var uriResolver = options.uriResolver; var context = options.context; + var query = defined(options.query) ? objectToQuery(options.query) : undefined; var promise = data; if (typeof data === 'string') { - promise = loadBlob(proxyUrl(data, dataSource._proxy)); + promise = loadBlob(proxyUrl(data, dataSource._proxy, query)); sourceUri = defaultValue(sourceUri, data); } @@ -2228,11 +2236,11 @@ define([ //Return the error throw new RuntimeError(msg); } - return loadKml(dataSource, entityCollection, kml, sourceUri, uriResolver, context); + return loadKml(dataSource, entityCollection, kml, sourceUri, uriResolver, context, query); }); }); } else { - return loadKml(dataSource, entityCollection, dataToLoad, sourceUri, uriResolver, context); + return loadKml(dataSource, entityCollection, dataToLoad, sourceUri, uriResolver, context, query); } }) .otherwise(function(error) { @@ -2327,6 +2335,7 @@ define([ * @param {DefaultProxy} [options.proxy] A proxy to be used for loading external data. * @param {String} [options.sourceUri] Overrides the url to use for resolving relative links and other KML network features. * @param {Boolean} [options.clampToGround=false] true if we want the geometry features (Polygons, LineStrings and LinearRings) clamped to the ground. If true, lines will use corridors so use Entity.corridor instead of Entity.polyline. + * @param {Object} [options.query] Key-value pairs which are appended to all URIs in the CZML. * * @returns {Promise.} A promise that will resolve to a new KmlDataSource instance once the KML is loaded. */ @@ -2473,6 +2482,7 @@ define([ * @param {Number} [options.sourceUri] Overrides the url to use for resolving relative links and other KML network features. * @returns {Promise.} A promise that will resolve to this instances once the KML is loaded. * @param {Boolean} [options.clampToGround=false] true if we want the geometry features (Polygons, LineStrings and LinearRings) clamped to the ground. If true, lines will use corridors so use Entity.corridor instead of Entity.polyline. + * @param {Object} [options.query] Key-value pairs which are appended to all URIs in the CZML. */ KmlDataSource.prototype.load = function(data, options) { //>>includeStart('debug', pragmas.debug); diff --git a/Specs/DataSources/KmlDataSourceSpec.js b/Specs/DataSources/KmlDataSourceSpec.js index 350d5f57b74d..130ad93a6e0c 100644 --- a/Specs/DataSources/KmlDataSourceSpec.js +++ b/Specs/DataSources/KmlDataSourceSpec.js @@ -1555,6 +1555,32 @@ defineSuite([ }); }); + it('IconStyle: Sets billboard image with query', function() { + var kml = '\ + \ + \ + '; + + return KmlDataSource.load(parser.parseFromString(kml, "text/xml"), { + camera : options.camera, + canvas : options.canvas, + sourceUri : 'http://test.invalid', + query : { + "test": true + } + }).then(function(dataSource) { + var entities = dataSource.entities.values; + var billboard = entities[0].billboard; + expect(billboard.image.getValue()).toEqual('http://test.invalid/image.png?test=true'); + }); + }); + it('IconStyle: Sets billboard image with subregion', function() { var kml = '\