diff --git a/CHANGES.md b/CHANGES.md index 34607c3ed702..160633f2149f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ Change Log * Fix flicker when adding, removing, or modifiying entities. [#3945](https://github.com/AnalyticalGraphicsInc/cesium/issues/3945) ##### Additions :tada: * Improved `MapboxImageryProvider` performance by 300% via `tiles.mapbox.com` subdomain switching. [#6426](https://github.com/AnalyticalGraphicsInc/cesium/issues/6426) +* Added ability to invoke `sampleTerrain` from node.js to enable offline terrain sampling ### 1.44 - 2018-04-02 diff --git a/Source/Core/FeatureDetection.js b/Source/Core/FeatureDetection.js index 1d9ee2a17224..ec217f9b3f5a 100644 --- a/Source/Core/FeatureDetection.js +++ b/Source/Core/FeatureDetection.js @@ -163,6 +163,14 @@ define([ return isFirefox() && firefoxVersionResult; } + var isNodeJsResult; + function isNodeJs() { + if (!defined(isNodeJsResult)) { + isNodeJsResult = typeof process === 'object' && Object.prototype.toString.call(process) === '[object process]'; // eslint-disable-line + } + return isNodeJsResult; + } + var hasPointerEvents; function supportsPointerEvents() { if (!defined(hasPointerEvents)) { @@ -230,6 +238,7 @@ define([ isFirefox : isFirefox, firefoxVersion : firefoxVersion, isWindows : isWindows, + isNodeJs: isNodeJs, hardwareConcurrency : defaultValue(theNavigator.hardwareConcurrency, 3), supportsPointerEvents : supportsPointerEvents, supportsImageRenderingPixelated: supportsImageRenderingPixelated, diff --git a/Source/Core/Resource.js b/Source/Core/Resource.js index a45f34af8a00..f504941b354a 100644 --- a/Source/Core/Resource.js +++ b/Source/Core/Resource.js @@ -10,6 +10,7 @@ define([ './defineProperties', './deprecationWarning', './DeveloperError', + './FeatureDetection', './freezeObject', './getAbsoluteUri', './getBaseUri', @@ -37,6 +38,7 @@ define([ defineProperties, deprecationWarning, DeveloperError, + FeatureDetection, freezeObject, getAbsoluteUri, getBaseUri, @@ -1772,6 +1774,63 @@ define([ image.src = url; }; + function decodeResponse(loadWithHttpResponse, responseType) { + switch (responseType) { + case 'text': + return loadWithHttpResponse.toString('utf8'); + case 'json': + return JSON.parse(loadWithHttpResponse.toString('utf8')); + default: + return new Uint8Array(loadWithHttpResponse).buffer; + } + } + + function loadWithHttpRequest(url, responseType, method, data, headers, deferred, overrideMimeType) { + // Note: only the 'json' and 'text' responseTypes transforms the loaded buffer + var URL = require('url').parse(url); + var http = URL.protocol === 'https:' ? require('https') : require('http'); + var zlib = require('zlib'); + var options = { + protocol : URL.protocol, + hostname : URL.hostname, + port : URL.port, + path : URL.path, + query : URL.query, + method : method, + headers : headers + }; + + http.request(options) + .on('response', function(res) { + if (res.statusCode < 200 || res.statusCode >= 300) { + deferred.reject(new RequestErrorEvent(res.statusCode, res, res.headers)); + return; + } + + var chunkArray = []; + res.on('data', function(chunk) { + chunkArray.push(chunk); + }); + + res.on('end', function() { + var result = Buffer.concat(chunkArray); // eslint-disable-line + if (res.headers['content-encoding'] === 'gzip') { + zlib.gunzip(result, function(error, resultUnzipped) { + if (error) { + deferred.reject(new RuntimeError('Error decompressing response.')); + } else { + deferred.resolve(decodeResponse(resultUnzipped, responseType)); + } + }); + } else { + deferred.resolve(decodeResponse(result, responseType)); + } + }); + }).on('error', function(e) { + deferred.reject(new RequestErrorEvent()); + }).end(); + } + Resource._Implementations.loadWithXhr = function(url, responseType, method, data, headers, deferred, overrideMimeType) { var dataUriRegexResult = dataUriRegex.exec(url); if (dataUriRegexResult !== null) { @@ -1779,6 +1838,11 @@ define([ return; } + if (FeatureDetection.isNodeJs()) { + loadWithHttpRequest(url, responseType, method, data, headers, deferred, overrideMimeType); + return; + } + var xhr = new XMLHttpRequest(); if (TrustedServers.contains(url)) { diff --git a/Source/Core/getAbsoluteUri.js b/Source/Core/getAbsoluteUri.js index 89aa26ffd266..36dab6f1b1d8 100644 --- a/Source/Core/getAbsoluteUri.js +++ b/Source/Core/getAbsoluteUri.js @@ -23,7 +23,12 @@ define([ * var absoluteUri = Cesium.getAbsoluteUri('awesome.png', 'https://test.com'); */ function getAbsoluteUri(relative, base) { - return getAbsoluteUri._implementation(relative, base, document); + var documentObject; + if (typeof document !== 'undefined') { + documentObject = document; + } + + return getAbsoluteUri._implementation(relative, base, documentObject); } getAbsoluteUri._implementation = function(relative, base, documentObject) { @@ -32,7 +37,14 @@ define([ throw new DeveloperError('relative uri is required.'); } //>>includeEnd('debug'); - base = defaultValue(base, defaultValue(documentObject.baseURI, documentObject.location.href)); + + if (!defined(base)) { + if (typeof documentObject === 'undefined') { + return relative; + } + base = defaultValue(documentObject.baseURI, documentObject.location.href); + } + var baseUri = new Uri(base); var relativeUri = new Uri(relative); return relativeUri.resolve(baseUri).toString(); diff --git a/Specs/Core/FeatureDetectionSpec.js b/Specs/Core/FeatureDetectionSpec.js index f043252950f8..ab29081a6d64 100644 --- a/Specs/Core/FeatureDetectionSpec.js +++ b/Specs/Core/FeatureDetectionSpec.js @@ -110,4 +110,8 @@ defineSuite([ expect(FeatureDetection.imageRenderingValue()).not.toBeDefined(); } }); + + it('detects Node.js', function() { + expect(FeatureDetection.isNodeJs()).toBe(false); + }); });