@carto/api-client 0.2.2-alpha.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api-client.cjs +1382 -12
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.modern.js +1382 -13
- package/build/api-client.modern.js.map +1 -1
- package/build/constants.d.ts +2 -0
- package/package.json +4 -5
- package/src/constants.ts +3 -0
- package/src/global.d.ts +6 -0
- package/src/models/model.ts +0 -1
|
@@ -28,6 +28,8 @@ function setClient(c) {
|
|
|
28
28
|
client = c;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/** Current version of @carto/api-client. */
|
|
32
|
+
const API_CLIENT_VERSION = "0.2.2";
|
|
31
33
|
/**
|
|
32
34
|
* Defines a comparator used when matching a column's values against given filter values.
|
|
33
35
|
*
|
|
@@ -94,7 +96,7 @@ function normalizeObjectKeys(el) {
|
|
|
94
96
|
}, {});
|
|
95
97
|
}
|
|
96
98
|
/** @internalRemarks Source: @carto/react-core */
|
|
97
|
-
function assert(condition, message) {
|
|
99
|
+
function assert$2(condition, message) {
|
|
98
100
|
if (!condition) {
|
|
99
101
|
throw new Error(message);
|
|
100
102
|
}
|
|
@@ -114,7 +116,7 @@ class InvalidColumnError extends Error {
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
InvalidColumnError.NAME = 'InvalidColumnError';
|
|
117
|
-
function isEmptyObject(object) {
|
|
119
|
+
function isEmptyObject$1(object) {
|
|
118
120
|
for (const _ in object) {
|
|
119
121
|
return false;
|
|
120
122
|
}
|
|
@@ -163,7 +165,7 @@ function removeFilter(filters, {
|
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
167
|
}
|
|
166
|
-
if (!owner || isEmptyObject(filter)) {
|
|
168
|
+
if (!owner || isEmptyObject$1(filter)) {
|
|
167
169
|
delete filters[column];
|
|
168
170
|
}
|
|
169
171
|
return filters;
|
|
@@ -464,10 +466,10 @@ const REQUEST_GET_MAX_URL_LENGTH = 2048;
|
|
|
464
466
|
* @internalRemarks Source: @carto/react-api
|
|
465
467
|
*/
|
|
466
468
|
function executeModel(props) {
|
|
467
|
-
assert(props.source, 'executeModel: missing source');
|
|
468
|
-
assert(props.model, 'executeModel: missing model');
|
|
469
|
-
assert(props.params, 'executeModel: missing params');
|
|
470
|
-
assert(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
|
|
469
|
+
assert$2(props.source, 'executeModel: missing source');
|
|
470
|
+
assert$2(props.model, 'executeModel: missing model');
|
|
471
|
+
assert$2(props.params, 'executeModel: missing params');
|
|
472
|
+
assert$2(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
|
|
471
473
|
const {
|
|
472
474
|
model,
|
|
473
475
|
source,
|
|
@@ -482,10 +484,10 @@ function executeModel(props) {
|
|
|
482
484
|
connectionName,
|
|
483
485
|
clientId
|
|
484
486
|
} = source;
|
|
485
|
-
assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
|
|
486
|
-
assert(accessToken, 'executeModel: missing accessToken');
|
|
487
|
-
assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
|
|
488
|
-
assert(type !== MapType.TILESET, 'executeModel: Tilesets not supported');
|
|
487
|
+
assert$2(apiBaseUrl, 'executeModel: missing apiBaseUrl');
|
|
488
|
+
assert$2(accessToken, 'executeModel: missing accessToken');
|
|
489
|
+
assert$2(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
|
|
490
|
+
assert$2(type !== MapType.TILESET, 'executeModel: Tilesets not supported');
|
|
489
491
|
let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
|
|
490
492
|
const {
|
|
491
493
|
filters,
|
|
@@ -915,6 +917,1373 @@ class WidgetTableSource extends WidgetBaseSource {
|
|
|
915
917
|
}
|
|
916
918
|
}
|
|
917
919
|
|
|
920
|
+
/**
|
|
921
|
+
* Throws an `Error` with the optional `message` if `condition` is falsy
|
|
922
|
+
* @note Replacement for the external assert method to reduce bundle size
|
|
923
|
+
*/
|
|
924
|
+
function assert$1(condition, message) {
|
|
925
|
+
if (!condition) {
|
|
926
|
+
throw new Error(message || 'loader assertion failed.');
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// Purpose: include this in your module to avoid
|
|
931
|
+
/** true if running in a browser */
|
|
932
|
+
const isBrowser$1 =
|
|
933
|
+
// @ts-ignore process does not exist on browser
|
|
934
|
+
Boolean(typeof process !== 'object' || String(process) !== '[object process]' || process.browser);
|
|
935
|
+
// Extract node major version
|
|
936
|
+
typeof process !== 'undefined' && process.version && /v([0-9]*)/.exec(process.version);
|
|
937
|
+
|
|
938
|
+
// Do not name these variables the same as the global objects - will break bundling
|
|
939
|
+
const window_ = globalThis;
|
|
940
|
+
const process_ = globalThis.process || {};
|
|
941
|
+
|
|
942
|
+
// based on https://github.com/cheton/is-electron
|
|
943
|
+
// https://github.com/electron/electron/issues/2288
|
|
944
|
+
/* eslint-disable complexity */
|
|
945
|
+
function isElectron(mockUserAgent) {
|
|
946
|
+
// Renderer process
|
|
947
|
+
// @ts-expect-error
|
|
948
|
+
if (typeof window !== 'undefined' && window.process?.type === 'renderer') {
|
|
949
|
+
return true;
|
|
950
|
+
}
|
|
951
|
+
// Main process
|
|
952
|
+
// eslint-disable-next-line
|
|
953
|
+
if (typeof process !== 'undefined' && Boolean(process.versions?.['electron'])) {
|
|
954
|
+
return true;
|
|
955
|
+
}
|
|
956
|
+
// Detect the user agent when the `nodeIntegration` option is set to true
|
|
957
|
+
const realUserAgent = typeof navigator !== 'undefined' && navigator.userAgent;
|
|
958
|
+
const userAgent = mockUserAgent || realUserAgent;
|
|
959
|
+
return Boolean(userAgent && userAgent.indexOf('Electron') >= 0);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// This function is needed in initialization stages,
|
|
963
|
+
/** Check if in browser by duck-typing Node context */
|
|
964
|
+
function isBrowser() {
|
|
965
|
+
const isNode =
|
|
966
|
+
// @ts-expect-error
|
|
967
|
+
typeof process === 'object' && String(process) === '[object process]' && !process?.browser;
|
|
968
|
+
return !isNode || isElectron();
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// Extract injected version from package.json (injected by babel plugin)
|
|
972
|
+
// @ts-expect-error
|
|
973
|
+
const VERSION$2 = "4.0.7" ;
|
|
974
|
+
// TODO - wish we could just export a constant
|
|
975
|
+
// export const isBrowser = checkIfBrowser();
|
|
976
|
+
|
|
977
|
+
// probe.gl, MIT license
|
|
978
|
+
function getStorage(type) {
|
|
979
|
+
try {
|
|
980
|
+
const storage = window[type];
|
|
981
|
+
const x = '__storage_test__';
|
|
982
|
+
storage.setItem(x, x);
|
|
983
|
+
storage.removeItem(x);
|
|
984
|
+
return storage;
|
|
985
|
+
} catch (e) {
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
// Store keys in local storage via simple interface
|
|
990
|
+
class LocalStorage {
|
|
991
|
+
constructor(id, defaultConfig, type = 'sessionStorage') {
|
|
992
|
+
this.storage = getStorage(type);
|
|
993
|
+
this.id = id;
|
|
994
|
+
this.config = defaultConfig;
|
|
995
|
+
this._loadConfiguration();
|
|
996
|
+
}
|
|
997
|
+
getConfiguration() {
|
|
998
|
+
return this.config;
|
|
999
|
+
}
|
|
1000
|
+
setConfiguration(configuration) {
|
|
1001
|
+
Object.assign(this.config, configuration);
|
|
1002
|
+
if (this.storage) {
|
|
1003
|
+
const serialized = JSON.stringify(this.config);
|
|
1004
|
+
this.storage.setItem(this.id, serialized);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
// Get config from persistent store, if available
|
|
1008
|
+
_loadConfiguration() {
|
|
1009
|
+
let configuration = {};
|
|
1010
|
+
if (this.storage) {
|
|
1011
|
+
const serializedConfiguration = this.storage.getItem(this.id);
|
|
1012
|
+
configuration = serializedConfiguration ? JSON.parse(serializedConfiguration) : {};
|
|
1013
|
+
}
|
|
1014
|
+
Object.assign(this.config, configuration);
|
|
1015
|
+
return this;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// probe.gl, MIT license
|
|
1020
|
+
/**
|
|
1021
|
+
* Format time
|
|
1022
|
+
*/
|
|
1023
|
+
function formatTime(ms) {
|
|
1024
|
+
let formatted;
|
|
1025
|
+
if (ms < 10) {
|
|
1026
|
+
formatted = `${ms.toFixed(2)}ms`;
|
|
1027
|
+
} else if (ms < 100) {
|
|
1028
|
+
formatted = `${ms.toFixed(1)}ms`;
|
|
1029
|
+
} else if (ms < 1000) {
|
|
1030
|
+
formatted = `${ms.toFixed(0)}ms`;
|
|
1031
|
+
} else {
|
|
1032
|
+
formatted = `${(ms / 1000).toFixed(2)}s`;
|
|
1033
|
+
}
|
|
1034
|
+
return formatted;
|
|
1035
|
+
}
|
|
1036
|
+
function leftPad(string, length = 8) {
|
|
1037
|
+
const padLength = Math.max(length - string.length, 0);
|
|
1038
|
+
return `${' '.repeat(padLength)}${string}`;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
var COLOR;
|
|
1042
|
+
(function (COLOR) {
|
|
1043
|
+
COLOR[COLOR["BLACK"] = 30] = "BLACK";
|
|
1044
|
+
COLOR[COLOR["RED"] = 31] = "RED";
|
|
1045
|
+
COLOR[COLOR["GREEN"] = 32] = "GREEN";
|
|
1046
|
+
COLOR[COLOR["YELLOW"] = 33] = "YELLOW";
|
|
1047
|
+
COLOR[COLOR["BLUE"] = 34] = "BLUE";
|
|
1048
|
+
COLOR[COLOR["MAGENTA"] = 35] = "MAGENTA";
|
|
1049
|
+
COLOR[COLOR["CYAN"] = 36] = "CYAN";
|
|
1050
|
+
COLOR[COLOR["WHITE"] = 37] = "WHITE";
|
|
1051
|
+
COLOR[COLOR["BRIGHT_BLACK"] = 90] = "BRIGHT_BLACK";
|
|
1052
|
+
COLOR[COLOR["BRIGHT_RED"] = 91] = "BRIGHT_RED";
|
|
1053
|
+
COLOR[COLOR["BRIGHT_GREEN"] = 92] = "BRIGHT_GREEN";
|
|
1054
|
+
COLOR[COLOR["BRIGHT_YELLOW"] = 93] = "BRIGHT_YELLOW";
|
|
1055
|
+
COLOR[COLOR["BRIGHT_BLUE"] = 94] = "BRIGHT_BLUE";
|
|
1056
|
+
COLOR[COLOR["BRIGHT_MAGENTA"] = 95] = "BRIGHT_MAGENTA";
|
|
1057
|
+
COLOR[COLOR["BRIGHT_CYAN"] = 96] = "BRIGHT_CYAN";
|
|
1058
|
+
COLOR[COLOR["BRIGHT_WHITE"] = 97] = "BRIGHT_WHITE";
|
|
1059
|
+
})(COLOR || (COLOR = {}));
|
|
1060
|
+
const BACKGROUND_INCREMENT = 10;
|
|
1061
|
+
function getColor(color) {
|
|
1062
|
+
if (typeof color !== 'string') {
|
|
1063
|
+
return color;
|
|
1064
|
+
}
|
|
1065
|
+
color = color.toUpperCase();
|
|
1066
|
+
return COLOR[color] || COLOR.WHITE;
|
|
1067
|
+
}
|
|
1068
|
+
function addColor(string, color, background) {
|
|
1069
|
+
if (!isBrowser && typeof string === 'string') {
|
|
1070
|
+
if (color) {
|
|
1071
|
+
const colorCode = getColor(color);
|
|
1072
|
+
string = `\u001b[${colorCode}m${string}\u001b[39m`;
|
|
1073
|
+
}
|
|
1074
|
+
if (background) {
|
|
1075
|
+
// background colors values are +10
|
|
1076
|
+
const colorCode = getColor(background);
|
|
1077
|
+
string = `\u001b[${colorCode + BACKGROUND_INCREMENT}m${string}\u001b[49m`;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
return string;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
|
|
1084
|
+
//
|
|
1085
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1086
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
1087
|
+
// in the Software without restriction, including without limitation the rights
|
|
1088
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1089
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
1090
|
+
// furnished to do so, subject to the following conditions:
|
|
1091
|
+
//
|
|
1092
|
+
// The above copyright notice and this permission notice shall be included in
|
|
1093
|
+
// all copies or substantial portions of the Software.
|
|
1094
|
+
//
|
|
1095
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1096
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1097
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1098
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1099
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1100
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1101
|
+
// THE SOFTWARE.
|
|
1102
|
+
/**
|
|
1103
|
+
* Binds the "this" argument of all functions on a class instance to the instance
|
|
1104
|
+
* @param obj - class instance (typically a react component)
|
|
1105
|
+
*/
|
|
1106
|
+
function autobind(obj, predefined = ['constructor']) {
|
|
1107
|
+
const proto = Object.getPrototypeOf(obj);
|
|
1108
|
+
const propNames = Object.getOwnPropertyNames(proto);
|
|
1109
|
+
const object = obj;
|
|
1110
|
+
for (const key of propNames) {
|
|
1111
|
+
const value = object[key];
|
|
1112
|
+
if (typeof value === 'function') {
|
|
1113
|
+
if (!predefined.find(name => key === name)) {
|
|
1114
|
+
object[key] = value.bind(obj);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
function assert(condition, message) {
|
|
1121
|
+
if (!condition) {
|
|
1122
|
+
throw new Error(message || 'Assertion failed');
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// probe.gl, MIT license
|
|
1127
|
+
/** Get best timer available. */
|
|
1128
|
+
function getHiResTimestamp() {
|
|
1129
|
+
let timestamp;
|
|
1130
|
+
if (isBrowser() && window_.performance) {
|
|
1131
|
+
timestamp = window_?.performance?.now?.();
|
|
1132
|
+
} else if ('hrtime' in process_) {
|
|
1133
|
+
// @ts-ignore
|
|
1134
|
+
const timeParts = process_?.hrtime?.();
|
|
1135
|
+
timestamp = timeParts[0] * 1000 + timeParts[1] / 1e6;
|
|
1136
|
+
} else {
|
|
1137
|
+
timestamp = Date.now();
|
|
1138
|
+
}
|
|
1139
|
+
return timestamp;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// probe.gl, MIT license
|
|
1143
|
+
// Instrumentation in other packages may override console methods, so preserve them here
|
|
1144
|
+
const originalConsole = {
|
|
1145
|
+
debug: isBrowser() ? console.debug || console.log : console.log,
|
|
1146
|
+
log: console.log,
|
|
1147
|
+
info: console.info,
|
|
1148
|
+
warn: console.warn,
|
|
1149
|
+
error: console.error
|
|
1150
|
+
};
|
|
1151
|
+
const DEFAULT_LOG_CONFIGURATION = {
|
|
1152
|
+
enabled: true,
|
|
1153
|
+
level: 0
|
|
1154
|
+
};
|
|
1155
|
+
function noop() {} // eslint-disable-line @typescript-eslint/no-empty-function
|
|
1156
|
+
const cache = {};
|
|
1157
|
+
const ONCE = {
|
|
1158
|
+
once: true
|
|
1159
|
+
};
|
|
1160
|
+
/** A console wrapper */
|
|
1161
|
+
class Log {
|
|
1162
|
+
constructor({
|
|
1163
|
+
id
|
|
1164
|
+
} = {
|
|
1165
|
+
id: ''
|
|
1166
|
+
}) {
|
|
1167
|
+
this.VERSION = VERSION$2;
|
|
1168
|
+
this._startTs = getHiResTimestamp();
|
|
1169
|
+
this._deltaTs = getHiResTimestamp();
|
|
1170
|
+
this.userData = {};
|
|
1171
|
+
// TODO - fix support from throttling groups
|
|
1172
|
+
this.LOG_THROTTLE_TIMEOUT = 0; // Time before throttled messages are logged again
|
|
1173
|
+
this.id = id;
|
|
1174
|
+
this.userData = {};
|
|
1175
|
+
this._storage = new LocalStorage(`__probe-${this.id}__`, DEFAULT_LOG_CONFIGURATION);
|
|
1176
|
+
this.timeStamp(`${this.id} started`);
|
|
1177
|
+
autobind(this);
|
|
1178
|
+
Object.seal(this);
|
|
1179
|
+
}
|
|
1180
|
+
set level(newLevel) {
|
|
1181
|
+
this.setLevel(newLevel);
|
|
1182
|
+
}
|
|
1183
|
+
get level() {
|
|
1184
|
+
return this.getLevel();
|
|
1185
|
+
}
|
|
1186
|
+
isEnabled() {
|
|
1187
|
+
return this._storage.config.enabled;
|
|
1188
|
+
}
|
|
1189
|
+
getLevel() {
|
|
1190
|
+
return this._storage.config.level;
|
|
1191
|
+
}
|
|
1192
|
+
/** @return milliseconds, with fractions */
|
|
1193
|
+
getTotal() {
|
|
1194
|
+
return Number((getHiResTimestamp() - this._startTs).toPrecision(10));
|
|
1195
|
+
}
|
|
1196
|
+
/** @return milliseconds, with fractions */
|
|
1197
|
+
getDelta() {
|
|
1198
|
+
return Number((getHiResTimestamp() - this._deltaTs).toPrecision(10));
|
|
1199
|
+
}
|
|
1200
|
+
/** @deprecated use logLevel */
|
|
1201
|
+
set priority(newPriority) {
|
|
1202
|
+
this.level = newPriority;
|
|
1203
|
+
}
|
|
1204
|
+
/** @deprecated use logLevel */
|
|
1205
|
+
get priority() {
|
|
1206
|
+
return this.level;
|
|
1207
|
+
}
|
|
1208
|
+
/** @deprecated use logLevel */
|
|
1209
|
+
getPriority() {
|
|
1210
|
+
return this.level;
|
|
1211
|
+
}
|
|
1212
|
+
// Configure
|
|
1213
|
+
enable(enabled = true) {
|
|
1214
|
+
this._storage.setConfiguration({
|
|
1215
|
+
enabled
|
|
1216
|
+
});
|
|
1217
|
+
return this;
|
|
1218
|
+
}
|
|
1219
|
+
setLevel(level) {
|
|
1220
|
+
this._storage.setConfiguration({
|
|
1221
|
+
level
|
|
1222
|
+
});
|
|
1223
|
+
return this;
|
|
1224
|
+
}
|
|
1225
|
+
/** return the current status of the setting */
|
|
1226
|
+
get(setting) {
|
|
1227
|
+
return this._storage.config[setting];
|
|
1228
|
+
}
|
|
1229
|
+
// update the status of the setting
|
|
1230
|
+
set(setting, value) {
|
|
1231
|
+
this._storage.setConfiguration({
|
|
1232
|
+
[setting]: value
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
/** Logs the current settings as a table */
|
|
1236
|
+
settings() {
|
|
1237
|
+
if (console.table) {
|
|
1238
|
+
console.table(this._storage.config);
|
|
1239
|
+
} else {
|
|
1240
|
+
console.log(this._storage.config);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
// Unconditional logging
|
|
1244
|
+
assert(condition, message) {
|
|
1245
|
+
if (!condition) {
|
|
1246
|
+
throw new Error(message || 'Assertion failed');
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
warn(message) {
|
|
1250
|
+
return this._getLogFunction(0, message, originalConsole.warn, arguments, ONCE);
|
|
1251
|
+
}
|
|
1252
|
+
error(message) {
|
|
1253
|
+
return this._getLogFunction(0, message, originalConsole.error, arguments);
|
|
1254
|
+
}
|
|
1255
|
+
/** Print a deprecation warning */
|
|
1256
|
+
deprecated(oldUsage, newUsage) {
|
|
1257
|
+
return this.warn(`\`${oldUsage}\` is deprecated and will be removed \
|
|
1258
|
+
in a later version. Use \`${newUsage}\` instead`);
|
|
1259
|
+
}
|
|
1260
|
+
/** Print a removal warning */
|
|
1261
|
+
removed(oldUsage, newUsage) {
|
|
1262
|
+
return this.error(`\`${oldUsage}\` has been removed. Use \`${newUsage}\` instead`);
|
|
1263
|
+
}
|
|
1264
|
+
probe(logLevel, message) {
|
|
1265
|
+
return this._getLogFunction(logLevel, message, originalConsole.log, arguments, {
|
|
1266
|
+
time: true,
|
|
1267
|
+
once: true
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
log(logLevel, message) {
|
|
1271
|
+
return this._getLogFunction(logLevel, message, originalConsole.debug, arguments);
|
|
1272
|
+
}
|
|
1273
|
+
info(logLevel, message) {
|
|
1274
|
+
return this._getLogFunction(logLevel, message, console.info, arguments);
|
|
1275
|
+
}
|
|
1276
|
+
once(logLevel, message) {
|
|
1277
|
+
return this._getLogFunction(logLevel, message, originalConsole.debug || originalConsole.info, arguments, ONCE);
|
|
1278
|
+
}
|
|
1279
|
+
/** Logs an object as a table */
|
|
1280
|
+
table(logLevel, table, columns) {
|
|
1281
|
+
if (table) {
|
|
1282
|
+
return this._getLogFunction(logLevel, table, console.table || noop, columns && [columns], {
|
|
1283
|
+
tag: getTableHeader(table)
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
return noop;
|
|
1287
|
+
}
|
|
1288
|
+
time(logLevel, message) {
|
|
1289
|
+
return this._getLogFunction(logLevel, message, console.time ? console.time : console.info);
|
|
1290
|
+
}
|
|
1291
|
+
timeEnd(logLevel, message) {
|
|
1292
|
+
return this._getLogFunction(logLevel, message, console.timeEnd ? console.timeEnd : console.info);
|
|
1293
|
+
}
|
|
1294
|
+
timeStamp(logLevel, message) {
|
|
1295
|
+
return this._getLogFunction(logLevel, message, console.timeStamp || noop);
|
|
1296
|
+
}
|
|
1297
|
+
group(logLevel, message, opts = {
|
|
1298
|
+
collapsed: false
|
|
1299
|
+
}) {
|
|
1300
|
+
const options = normalizeArguments({
|
|
1301
|
+
logLevel,
|
|
1302
|
+
message,
|
|
1303
|
+
opts
|
|
1304
|
+
});
|
|
1305
|
+
const {
|
|
1306
|
+
collapsed
|
|
1307
|
+
} = opts;
|
|
1308
|
+
// @ts-expect-error
|
|
1309
|
+
options.method = (collapsed ? console.groupCollapsed : console.group) || console.info;
|
|
1310
|
+
return this._getLogFunction(options);
|
|
1311
|
+
}
|
|
1312
|
+
groupCollapsed(logLevel, message, opts = {}) {
|
|
1313
|
+
return this.group(logLevel, message, Object.assign({}, opts, {
|
|
1314
|
+
collapsed: true
|
|
1315
|
+
}));
|
|
1316
|
+
}
|
|
1317
|
+
groupEnd(logLevel) {
|
|
1318
|
+
return this._getLogFunction(logLevel, '', console.groupEnd || noop);
|
|
1319
|
+
}
|
|
1320
|
+
// EXPERIMENTAL
|
|
1321
|
+
withGroup(logLevel, message, func) {
|
|
1322
|
+
this.group(logLevel, message)();
|
|
1323
|
+
try {
|
|
1324
|
+
func();
|
|
1325
|
+
} finally {
|
|
1326
|
+
this.groupEnd(logLevel)();
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
trace() {
|
|
1330
|
+
if (console.trace) {
|
|
1331
|
+
console.trace();
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
// PRIVATE METHODS
|
|
1335
|
+
/** Deduces log level from a variety of arguments */
|
|
1336
|
+
_shouldLog(logLevel) {
|
|
1337
|
+
return this.isEnabled() && this.getLevel() >= normalizeLogLevel(logLevel);
|
|
1338
|
+
}
|
|
1339
|
+
_getLogFunction(logLevel, message, method, args, opts) {
|
|
1340
|
+
if (this._shouldLog(logLevel)) {
|
|
1341
|
+
// normalized opts + timings
|
|
1342
|
+
opts = normalizeArguments({
|
|
1343
|
+
logLevel,
|
|
1344
|
+
message,
|
|
1345
|
+
args,
|
|
1346
|
+
opts
|
|
1347
|
+
});
|
|
1348
|
+
method = method || opts.method;
|
|
1349
|
+
assert(method);
|
|
1350
|
+
opts.total = this.getTotal();
|
|
1351
|
+
opts.delta = this.getDelta();
|
|
1352
|
+
// reset delta timer
|
|
1353
|
+
this._deltaTs = getHiResTimestamp();
|
|
1354
|
+
const tag = opts.tag || opts.message;
|
|
1355
|
+
if (opts.once && tag) {
|
|
1356
|
+
if (!cache[tag]) {
|
|
1357
|
+
cache[tag] = getHiResTimestamp();
|
|
1358
|
+
} else {
|
|
1359
|
+
return noop;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
// TODO - Make throttling work with groups
|
|
1363
|
+
// if (opts.nothrottle || !throttle(tag, this.LOG_THROTTLE_TIMEOUT)) {
|
|
1364
|
+
// return noop;
|
|
1365
|
+
// }
|
|
1366
|
+
message = decorateMessage(this.id, opts.message, opts);
|
|
1367
|
+
// Bind console function so that it can be called after being returned
|
|
1368
|
+
return method.bind(console, message, ...opts.args);
|
|
1369
|
+
}
|
|
1370
|
+
return noop;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
Log.VERSION = VERSION$2;
|
|
1374
|
+
/**
|
|
1375
|
+
* Get logLevel from first argument:
|
|
1376
|
+
* - log(logLevel, message, args) => logLevel
|
|
1377
|
+
* - log(message, args) => 0
|
|
1378
|
+
* - log({logLevel, ...}, message, args) => logLevel
|
|
1379
|
+
* - log({logLevel, message, args}) => logLevel
|
|
1380
|
+
*/
|
|
1381
|
+
function normalizeLogLevel(logLevel) {
|
|
1382
|
+
if (!logLevel) {
|
|
1383
|
+
return 0;
|
|
1384
|
+
}
|
|
1385
|
+
let resolvedLevel;
|
|
1386
|
+
switch (typeof logLevel) {
|
|
1387
|
+
case 'number':
|
|
1388
|
+
resolvedLevel = logLevel;
|
|
1389
|
+
break;
|
|
1390
|
+
case 'object':
|
|
1391
|
+
// Backward compatibility
|
|
1392
|
+
// TODO - deprecate `priority`
|
|
1393
|
+
// @ts-expect-error
|
|
1394
|
+
resolvedLevel = logLevel.logLevel || logLevel.priority || 0;
|
|
1395
|
+
break;
|
|
1396
|
+
default:
|
|
1397
|
+
return 0;
|
|
1398
|
+
}
|
|
1399
|
+
// 'log level must be a number'
|
|
1400
|
+
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
|
|
1401
|
+
return resolvedLevel;
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* "Normalizes" the various argument patterns into an object with known types
|
|
1405
|
+
* - log(logLevel, message, args) => {logLevel, message, args}
|
|
1406
|
+
* - log(message, args) => {logLevel: 0, message, args}
|
|
1407
|
+
* - log({logLevel, ...}, message, args) => {logLevel, message, args}
|
|
1408
|
+
* - log({logLevel, message, args}) => {logLevel, message, args}
|
|
1409
|
+
*/
|
|
1410
|
+
function normalizeArguments(opts) {
|
|
1411
|
+
const {
|
|
1412
|
+
logLevel,
|
|
1413
|
+
message
|
|
1414
|
+
} = opts;
|
|
1415
|
+
opts.logLevel = normalizeLogLevel(logLevel);
|
|
1416
|
+
// We use `arguments` instead of rest parameters (...args) because IE
|
|
1417
|
+
// does not support the syntax. Rest parameters is transpiled to code with
|
|
1418
|
+
// perf impact. Doing it here instead avoids constructing args when logging is
|
|
1419
|
+
// disabled.
|
|
1420
|
+
// TODO - remove when/if IE support is dropped
|
|
1421
|
+
const args = opts.args ? Array.from(opts.args) : [];
|
|
1422
|
+
// args should only contain arguments that appear after `message`
|
|
1423
|
+
// eslint-disable-next-line no-empty
|
|
1424
|
+
while (args.length && args.shift() !== message) {}
|
|
1425
|
+
switch (typeof logLevel) {
|
|
1426
|
+
case 'string':
|
|
1427
|
+
case 'function':
|
|
1428
|
+
if (message !== undefined) {
|
|
1429
|
+
args.unshift(message);
|
|
1430
|
+
}
|
|
1431
|
+
opts.message = logLevel;
|
|
1432
|
+
break;
|
|
1433
|
+
case 'object':
|
|
1434
|
+
Object.assign(opts, logLevel);
|
|
1435
|
+
break;
|
|
1436
|
+
}
|
|
1437
|
+
// Resolve functions into strings by calling them
|
|
1438
|
+
if (typeof opts.message === 'function') {
|
|
1439
|
+
opts.message = opts.message();
|
|
1440
|
+
}
|
|
1441
|
+
const messageType = typeof opts.message;
|
|
1442
|
+
// 'log message must be a string' or object
|
|
1443
|
+
assert(messageType === 'string' || messageType === 'object');
|
|
1444
|
+
// original opts + normalized opts + opts arg + fixed up message
|
|
1445
|
+
return Object.assign(opts, {
|
|
1446
|
+
args
|
|
1447
|
+
}, opts.opts);
|
|
1448
|
+
}
|
|
1449
|
+
function decorateMessage(id, message, opts) {
|
|
1450
|
+
if (typeof message === 'string') {
|
|
1451
|
+
const time = opts.time ? leftPad(formatTime(opts.total)) : '';
|
|
1452
|
+
message = opts.time ? `${id}: ${time} ${message}` : `${id}: ${message}`;
|
|
1453
|
+
message = addColor(message, opts.color, opts.background);
|
|
1454
|
+
}
|
|
1455
|
+
return message;
|
|
1456
|
+
}
|
|
1457
|
+
function getTableHeader(table) {
|
|
1458
|
+
for (const key in table) {
|
|
1459
|
+
for (const title in table[key]) {
|
|
1460
|
+
return title || 'untitled';
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
return 'empty';
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// loaders.gl
|
|
1467
|
+
/**
|
|
1468
|
+
* Helper for safely accessing global loaders.gl variables
|
|
1469
|
+
* Wraps initialization of global variable in function to defeat overly aggressive tree-shakers
|
|
1470
|
+
*/
|
|
1471
|
+
function getGlobalLoaderState() {
|
|
1472
|
+
// @ts-ignore
|
|
1473
|
+
globalThis.loaders = globalThis.loaders || {};
|
|
1474
|
+
// @ts-ignore
|
|
1475
|
+
const {
|
|
1476
|
+
loaders
|
|
1477
|
+
} = globalThis;
|
|
1478
|
+
// Add _state object to keep separate from modules added to globalThis.loaders
|
|
1479
|
+
if (!loaders._state) {
|
|
1480
|
+
loaders._state = {};
|
|
1481
|
+
}
|
|
1482
|
+
return loaders._state;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// loaders.gl
|
|
1486
|
+
function isLoaderObject(loader) {
|
|
1487
|
+
if (!loader) {
|
|
1488
|
+
return false;
|
|
1489
|
+
}
|
|
1490
|
+
if (Array.isArray(loader)) {
|
|
1491
|
+
loader = loader[0];
|
|
1492
|
+
}
|
|
1493
|
+
const hasExtensions = Array.isArray(loader?.extensions);
|
|
1494
|
+
/* Now handled by types and worker loaders do not have these
|
|
1495
|
+
let hasParser =
|
|
1496
|
+
loader.parseTextSync ||
|
|
1497
|
+
loader.parseSync ||
|
|
1498
|
+
loader.parse ||
|
|
1499
|
+
loader.parseStream || // TODO Remove, Replace with parseInBatches
|
|
1500
|
+
loader.parseInBatches;
|
|
1501
|
+
*/
|
|
1502
|
+
return hasExtensions;
|
|
1503
|
+
}
|
|
1504
|
+
function normalizeLoader(loader) {
|
|
1505
|
+
// This error is fairly easy to trigger by mixing up import statements etc
|
|
1506
|
+
// So we make an exception and add a developer error message for this case
|
|
1507
|
+
// To help new users from getting stuck here
|
|
1508
|
+
assert$1(loader, 'null loader');
|
|
1509
|
+
assert$1(isLoaderObject(loader), 'invalid loader');
|
|
1510
|
+
// NORMALIZE [LOADER, OPTIONS] => LOADER
|
|
1511
|
+
// If [loader, options], create a new loaders object with options merged in
|
|
1512
|
+
let options;
|
|
1513
|
+
if (Array.isArray(loader)) {
|
|
1514
|
+
options = loader[1];
|
|
1515
|
+
loader = loader[0];
|
|
1516
|
+
loader = {
|
|
1517
|
+
...loader,
|
|
1518
|
+
options: {
|
|
1519
|
+
...loader.options,
|
|
1520
|
+
...options
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
// NORMALIZE text and binary flags
|
|
1525
|
+
// Ensure at least one of text/binary flags are properly set
|
|
1526
|
+
// @ts-expect-error
|
|
1527
|
+
if (loader?.parseTextSync || loader?.parseText) {
|
|
1528
|
+
loader.text = true;
|
|
1529
|
+
}
|
|
1530
|
+
if (!loader.text) {
|
|
1531
|
+
loader.binary = true;
|
|
1532
|
+
}
|
|
1533
|
+
return loader;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// loaders.gl
|
|
1537
|
+
/**
|
|
1538
|
+
* Store global registered loaders on the global object to increase chances of cross loaders-version interoperability
|
|
1539
|
+
* This use case is not reliable but can help when testing new versions of loaders.gl with existing frameworks
|
|
1540
|
+
*/
|
|
1541
|
+
const getGlobalLoaderRegistry = () => {
|
|
1542
|
+
const state = getGlobalLoaderState();
|
|
1543
|
+
state.loaderRegistry = state.loaderRegistry || [];
|
|
1544
|
+
return state.loaderRegistry;
|
|
1545
|
+
};
|
|
1546
|
+
/** Register a list of global loaders */
|
|
1547
|
+
function registerLoaders(loaders) {
|
|
1548
|
+
const loaderRegistry = getGlobalLoaderRegistry();
|
|
1549
|
+
loaders = Array.isArray(loaders) ? loaders : [loaders];
|
|
1550
|
+
for (const loader of loaders) {
|
|
1551
|
+
const normalizedLoader = normalizeLoader(loader);
|
|
1552
|
+
if (!loaderRegistry.find(registeredLoader => normalizedLoader === registeredLoader)) {
|
|
1553
|
+
// add to the beginning of the loaderRegistry, so the last registeredLoader get picked
|
|
1554
|
+
loaderRegistry.unshift(normalizedLoader);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
// Version constant cannot be imported, it needs to correspond to the build version of **this** module.
|
|
1560
|
+
// __VERSION__ is injected by babel-plugin-version-inline
|
|
1561
|
+
// @ts-ignore TS2304: Cannot find name '__VERSION__'.
|
|
1562
|
+
const VERSION$1 = "4.2.3" ;
|
|
1563
|
+
|
|
1564
|
+
// @ts-ignore TS2339: Property does not exist on type
|
|
1565
|
+
const parseImageNode = globalThis.loaders?.parseImageNode;
|
|
1566
|
+
const IMAGE_SUPPORTED = typeof Image !== 'undefined'; // NOTE: "false" positives if jsdom is installed
|
|
1567
|
+
const IMAGE_BITMAP_SUPPORTED = typeof ImageBitmap !== 'undefined';
|
|
1568
|
+
const NODE_IMAGE_SUPPORTED = Boolean(parseImageNode);
|
|
1569
|
+
const DATA_SUPPORTED = isBrowser$1 ? true : NODE_IMAGE_SUPPORTED;
|
|
1570
|
+
/**
|
|
1571
|
+
* Checks if a loaders.gl image type is supported
|
|
1572
|
+
* @param type image type string
|
|
1573
|
+
*/
|
|
1574
|
+
function isImageTypeSupported(type) {
|
|
1575
|
+
switch (type) {
|
|
1576
|
+
case 'auto':
|
|
1577
|
+
// Should only ever be false in Node.js, if polyfills have not been installed...
|
|
1578
|
+
return IMAGE_BITMAP_SUPPORTED || IMAGE_SUPPORTED || DATA_SUPPORTED;
|
|
1579
|
+
case 'imagebitmap':
|
|
1580
|
+
return IMAGE_BITMAP_SUPPORTED;
|
|
1581
|
+
case 'image':
|
|
1582
|
+
return IMAGE_SUPPORTED;
|
|
1583
|
+
case 'data':
|
|
1584
|
+
return DATA_SUPPORTED;
|
|
1585
|
+
default:
|
|
1586
|
+
throw new Error(`@loaders.gl/images: image ${type} not supported in this environment`);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Returns the "most performant" supported image type on this platform
|
|
1591
|
+
* @returns image type string
|
|
1592
|
+
*/
|
|
1593
|
+
function getDefaultImageType() {
|
|
1594
|
+
if (IMAGE_BITMAP_SUPPORTED) {
|
|
1595
|
+
return 'imagebitmap';
|
|
1596
|
+
}
|
|
1597
|
+
if (IMAGE_SUPPORTED) {
|
|
1598
|
+
return 'image';
|
|
1599
|
+
}
|
|
1600
|
+
if (DATA_SUPPORTED) {
|
|
1601
|
+
return 'data';
|
|
1602
|
+
}
|
|
1603
|
+
// This should only happen in Node.js
|
|
1604
|
+
throw new Error('Install \'@loaders.gl/polyfills\' to parse images under Node.js');
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
function getImageType(image) {
|
|
1608
|
+
const format = getImageTypeOrNull(image);
|
|
1609
|
+
if (!format) {
|
|
1610
|
+
throw new Error('Not an image');
|
|
1611
|
+
}
|
|
1612
|
+
return format;
|
|
1613
|
+
}
|
|
1614
|
+
function getImageData(image) {
|
|
1615
|
+
switch (getImageType(image)) {
|
|
1616
|
+
case 'data':
|
|
1617
|
+
return image;
|
|
1618
|
+
case 'image':
|
|
1619
|
+
case 'imagebitmap':
|
|
1620
|
+
// Extract the image data from the image via a canvas
|
|
1621
|
+
const canvas = document.createElement('canvas');
|
|
1622
|
+
// TODO - reuse the canvas?
|
|
1623
|
+
const context = canvas.getContext('2d');
|
|
1624
|
+
if (!context) {
|
|
1625
|
+
throw new Error('getImageData');
|
|
1626
|
+
}
|
|
1627
|
+
// @ts-ignore
|
|
1628
|
+
canvas.width = image.width;
|
|
1629
|
+
// @ts-ignore
|
|
1630
|
+
canvas.height = image.height;
|
|
1631
|
+
// @ts-ignore
|
|
1632
|
+
context.drawImage(image, 0, 0);
|
|
1633
|
+
// @ts-ignore
|
|
1634
|
+
return context.getImageData(0, 0, image.width, image.height);
|
|
1635
|
+
default:
|
|
1636
|
+
throw new Error('getImageData');
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
// PRIVATE
|
|
1640
|
+
// eslint-disable-next-line complexity
|
|
1641
|
+
function getImageTypeOrNull(image) {
|
|
1642
|
+
if (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) {
|
|
1643
|
+
return 'imagebitmap';
|
|
1644
|
+
}
|
|
1645
|
+
if (typeof Image !== 'undefined' && image instanceof Image) {
|
|
1646
|
+
return 'image';
|
|
1647
|
+
}
|
|
1648
|
+
if (image && typeof image === 'object' && image.data && image.width && image.height) {
|
|
1649
|
+
return 'data';
|
|
1650
|
+
}
|
|
1651
|
+
return null;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// SVG parsing has limitations, e.g:
|
|
1655
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=606319
|
|
1656
|
+
const SVG_DATA_URL_PATTERN = /^data:image\/svg\+xml/;
|
|
1657
|
+
const SVG_URL_PATTERN = /\.svg((\?|#).*)?$/;
|
|
1658
|
+
function isSVG(url) {
|
|
1659
|
+
return url && (SVG_DATA_URL_PATTERN.test(url) || SVG_URL_PATTERN.test(url));
|
|
1660
|
+
}
|
|
1661
|
+
function getBlobOrSVGDataUrl(arrayBuffer, url) {
|
|
1662
|
+
if (isSVG(url)) {
|
|
1663
|
+
// Prepare a properly tagged data URL, and load using normal mechanism
|
|
1664
|
+
const textDecoder = new TextDecoder();
|
|
1665
|
+
let xmlText = textDecoder.decode(arrayBuffer);
|
|
1666
|
+
// TODO Escape in browser to support e.g. Chinese characters
|
|
1667
|
+
try {
|
|
1668
|
+
if (typeof unescape === 'function' && typeof encodeURIComponent === 'function') {
|
|
1669
|
+
xmlText = unescape(encodeURIComponent(xmlText));
|
|
1670
|
+
}
|
|
1671
|
+
} catch (error) {
|
|
1672
|
+
throw new Error(error.message);
|
|
1673
|
+
}
|
|
1674
|
+
// base64 encoding is safer. utf-8 fails in some browsers
|
|
1675
|
+
const src = `data:image/svg+xml;base64,${btoa(xmlText)}`;
|
|
1676
|
+
return src;
|
|
1677
|
+
}
|
|
1678
|
+
return getBlob(arrayBuffer, url);
|
|
1679
|
+
}
|
|
1680
|
+
function getBlob(arrayBuffer, url) {
|
|
1681
|
+
if (isSVG(url)) {
|
|
1682
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=606319
|
|
1683
|
+
// return new Blob([new Uint8Array(arrayBuffer)], {type: 'image/svg+xml'});
|
|
1684
|
+
throw new Error('SVG cannot be parsed directly to imagebitmap');
|
|
1685
|
+
}
|
|
1686
|
+
// TODO - how to determine mime type? Param? Sniff here?
|
|
1687
|
+
return new Blob([new Uint8Array(arrayBuffer)]); // MIME type not needed?
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
// Parses html image from array buffer
|
|
1691
|
+
async function parseToImage(arrayBuffer, options, url) {
|
|
1692
|
+
// Note: image parsing requires conversion to Blob (for createObjectURL).
|
|
1693
|
+
// Potentially inefficient for not using `response.blob()` (and for File / Blob inputs)...
|
|
1694
|
+
// But presumably not worth adding 'blob' flag to loader objects?
|
|
1695
|
+
const blobOrDataUrl = getBlobOrSVGDataUrl(arrayBuffer, url);
|
|
1696
|
+
const URL = self.URL || self.webkitURL;
|
|
1697
|
+
const objectUrl = typeof blobOrDataUrl !== 'string' && URL.createObjectURL(blobOrDataUrl);
|
|
1698
|
+
try {
|
|
1699
|
+
return await loadToImage(objectUrl || blobOrDataUrl, options);
|
|
1700
|
+
} finally {
|
|
1701
|
+
if (objectUrl) {
|
|
1702
|
+
URL.revokeObjectURL(objectUrl);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
async function loadToImage(url, options) {
|
|
1707
|
+
const image = new Image();
|
|
1708
|
+
image.src = url;
|
|
1709
|
+
// The `image.onload()` callback does not guarantee that the image has been decoded
|
|
1710
|
+
// so a main thread "freeze" can be incurred when using the image for the first time.
|
|
1711
|
+
// `Image.decode()` returns a promise that completes when image is decoded.
|
|
1712
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode
|
|
1713
|
+
// Note: When calling `img.decode()`, we do not need to wait for `img.onload()`
|
|
1714
|
+
// Note: `HTMLImageElement.decode()` is not available in Edge and IE11
|
|
1715
|
+
if (options.image && options.image.decode && image.decode) {
|
|
1716
|
+
await image.decode();
|
|
1717
|
+
return image;
|
|
1718
|
+
}
|
|
1719
|
+
// Create a promise that tracks onload/onerror callbacks
|
|
1720
|
+
return await new Promise((resolve, reject) => {
|
|
1721
|
+
try {
|
|
1722
|
+
image.onload = () => resolve(image);
|
|
1723
|
+
image.onerror = error => {
|
|
1724
|
+
const message = error instanceof Error ? error.message : 'error';
|
|
1725
|
+
reject(new Error(message));
|
|
1726
|
+
};
|
|
1727
|
+
} catch (error) {
|
|
1728
|
+
reject(error);
|
|
1729
|
+
}
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
const EMPTY_OBJECT = {};
|
|
1734
|
+
let imagebitmapOptionsSupported = true;
|
|
1735
|
+
/**
|
|
1736
|
+
* Asynchronously parses an array buffer into an ImageBitmap - this contains the decoded data
|
|
1737
|
+
* ImageBitmaps are supported on worker threads, but not supported on Edge, IE11 and Safari
|
|
1738
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap#Browser_compatibility
|
|
1739
|
+
*
|
|
1740
|
+
* TODO - createImageBitmap supports source rect (5 param overload), pass through?
|
|
1741
|
+
*/
|
|
1742
|
+
async function parseToImageBitmap(arrayBuffer, options, url) {
|
|
1743
|
+
let blob;
|
|
1744
|
+
// Cannot parse SVG directly to ImageBitmap, parse to Image first
|
|
1745
|
+
if (isSVG(url)) {
|
|
1746
|
+
// Note: this only works on main thread
|
|
1747
|
+
const image = await parseToImage(arrayBuffer, options, url);
|
|
1748
|
+
blob = image;
|
|
1749
|
+
} else {
|
|
1750
|
+
// Create blob from the array buffer
|
|
1751
|
+
blob = getBlob(arrayBuffer, url);
|
|
1752
|
+
}
|
|
1753
|
+
const imagebitmapOptions = options && options.imagebitmap;
|
|
1754
|
+
return await safeCreateImageBitmap(blob, imagebitmapOptions);
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Safely creates an imageBitmap with options
|
|
1758
|
+
* *
|
|
1759
|
+
* Firefox crashes if imagebitmapOptions is supplied
|
|
1760
|
+
* Avoid supplying if not provided or supported, remember if not supported
|
|
1761
|
+
*/
|
|
1762
|
+
async function safeCreateImageBitmap(blob, imagebitmapOptions = null) {
|
|
1763
|
+
if (isEmptyObject(imagebitmapOptions) || !imagebitmapOptionsSupported) {
|
|
1764
|
+
imagebitmapOptions = null;
|
|
1765
|
+
}
|
|
1766
|
+
if (imagebitmapOptions) {
|
|
1767
|
+
try {
|
|
1768
|
+
// @ts-ignore Options
|
|
1769
|
+
return await createImageBitmap(blob, imagebitmapOptions);
|
|
1770
|
+
} catch (error) {
|
|
1771
|
+
console.warn(error); // eslint-disable-line
|
|
1772
|
+
imagebitmapOptionsSupported = false;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
return await createImageBitmap(blob);
|
|
1776
|
+
}
|
|
1777
|
+
function isEmptyObject(object) {
|
|
1778
|
+
// @ts-ignore
|
|
1779
|
+
for (const key in object || EMPTY_OBJECT) {
|
|
1780
|
+
return false;
|
|
1781
|
+
}
|
|
1782
|
+
return true;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
// loaders.gl
|
|
1786
|
+
// SPDX-License-Identifier: MIT
|
|
1787
|
+
// Copyright (c) vis.gl contributors
|
|
1788
|
+
// code adapted from https://github.com/sindresorhus/file-type under MIT license
|
|
1789
|
+
/**
|
|
1790
|
+
* Tests if a buffer is in ISO base media file format (ISOBMFF) @see https://en.wikipedia.org/wiki/ISO_base_media_file_format
|
|
1791
|
+
* (ISOBMFF is a media container standard based on the Apple QuickTime container format)
|
|
1792
|
+
*/
|
|
1793
|
+
function getISOBMFFMediaType(buffer) {
|
|
1794
|
+
// Almost all ISO base media files start with `ftyp` box. (It's not required to be first, but it's recommended to be.)
|
|
1795
|
+
if (!checkString(buffer, 'ftyp', 4)) {
|
|
1796
|
+
return null;
|
|
1797
|
+
}
|
|
1798
|
+
// Extra check: test for 8859-1 printable characters (for simplicity, it's a mask which also catches one non-printable character).
|
|
1799
|
+
if ((buffer[8] & 0x60) === 0x00) {
|
|
1800
|
+
return null;
|
|
1801
|
+
}
|
|
1802
|
+
// `ftyp` box must contain a brand major identifier, which must consist of ISO 8859-1 printable characters.
|
|
1803
|
+
return decodeMajorBrand(buffer);
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* brands explained @see https://github.com/strukturag/libheif/issues/83
|
|
1807
|
+
* code adapted from @see https://github.com/sindresorhus/file-type/blob/main/core.js#L489-L492
|
|
1808
|
+
*/
|
|
1809
|
+
function decodeMajorBrand(buffer) {
|
|
1810
|
+
const brandMajor = getUTF8String(buffer, 8, 12).replace('\0', ' ').trim();
|
|
1811
|
+
switch (brandMajor) {
|
|
1812
|
+
case 'avif':
|
|
1813
|
+
case 'avis':
|
|
1814
|
+
return {
|
|
1815
|
+
extension: 'avif',
|
|
1816
|
+
mimeType: 'image/avif'
|
|
1817
|
+
};
|
|
1818
|
+
default:
|
|
1819
|
+
return null;
|
|
1820
|
+
}
|
|
1821
|
+
// We don't need these now, but they are easy to add
|
|
1822
|
+
// case 'mif1':
|
|
1823
|
+
// return {extension: 'heic', mimeType: 'image/heif'};
|
|
1824
|
+
// case 'msf1':
|
|
1825
|
+
// return {extension: 'heic', mimeType: 'image/heif-sequence'};
|
|
1826
|
+
// case 'heic':
|
|
1827
|
+
// case 'heix':
|
|
1828
|
+
// return {extension: 'heic', mimeType: 'image/heic'};
|
|
1829
|
+
// case 'hevc':
|
|
1830
|
+
// case 'hevx':
|
|
1831
|
+
// return {extension: 'heic', mimeType: 'image/heic-sequence'};
|
|
1832
|
+
// case 'qt':
|
|
1833
|
+
// return {ext: 'mov', mime: 'video/quicktime'};
|
|
1834
|
+
// case 'M4V':
|
|
1835
|
+
// case 'M4VH':
|
|
1836
|
+
// case 'M4VP':
|
|
1837
|
+
// return {ext: 'm4v', mime: 'video/x-m4v'};
|
|
1838
|
+
// case 'M4P':
|
|
1839
|
+
// return {ext: 'm4p', mime: 'video/mp4'};
|
|
1840
|
+
// case 'M4B':
|
|
1841
|
+
// return {ext: 'm4b', mime: 'audio/mp4'};
|
|
1842
|
+
// case 'M4A':
|
|
1843
|
+
// return {ext: 'm4a', mime: 'audio/x-m4a'};
|
|
1844
|
+
// case 'F4V':
|
|
1845
|
+
// return {ext: 'f4v', mime: 'video/mp4'};
|
|
1846
|
+
// case 'F4P':
|
|
1847
|
+
// return {ext: 'f4p', mime: 'video/mp4'};
|
|
1848
|
+
// case 'F4A':
|
|
1849
|
+
// return {ext: 'f4a', mime: 'audio/mp4'};
|
|
1850
|
+
// case 'F4B':
|
|
1851
|
+
// return {ext: 'f4b', mime: 'audio/mp4'};
|
|
1852
|
+
// case 'crx':
|
|
1853
|
+
// return {ext: 'cr3', mime: 'image/x-canon-cr3'};
|
|
1854
|
+
// default:
|
|
1855
|
+
// if (brandMajor.startsWith('3g')) {
|
|
1856
|
+
// if (brandMajor.startsWith('3g2')) {
|
|
1857
|
+
// return {ext: '3g2', mime: 'video/3gpp2'};
|
|
1858
|
+
// }
|
|
1859
|
+
// return {ext: '3gp', mime: 'video/3gpp'};
|
|
1860
|
+
// }
|
|
1861
|
+
// return {ext: 'mp4', mime: 'video/mp4'};
|
|
1862
|
+
}
|
|
1863
|
+
/** Interpret a chunk of bytes as a UTF8 string */
|
|
1864
|
+
function getUTF8String(array, start, end) {
|
|
1865
|
+
return String.fromCharCode(...array.slice(start, end));
|
|
1866
|
+
}
|
|
1867
|
+
function stringToBytes(string) {
|
|
1868
|
+
return [...string].map(character => character.charCodeAt(0));
|
|
1869
|
+
}
|
|
1870
|
+
function checkString(buffer, header, offset = 0) {
|
|
1871
|
+
const headerBytes = stringToBytes(header);
|
|
1872
|
+
for (let i = 0; i < headerBytes.length; ++i) {
|
|
1873
|
+
if (headerBytes[i] !== buffer[i + offset]) {
|
|
1874
|
+
return false;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
return true;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// Attributions
|
|
1881
|
+
const BIG_ENDIAN = false;
|
|
1882
|
+
const LITTLE_ENDIAN = true;
|
|
1883
|
+
/**
|
|
1884
|
+
* Extracts `{mimeType, width and height}` from a memory buffer containing a known image format
|
|
1885
|
+
* Currently supports `image/png`, `image/jpeg`, `image/bmp` and `image/gif`.
|
|
1886
|
+
* @param binaryData: DataView | ArrayBuffer image file memory to parse
|
|
1887
|
+
* @returns metadata or null if memory is not a valid image file format layout.
|
|
1888
|
+
*/
|
|
1889
|
+
function getBinaryImageMetadata(binaryData) {
|
|
1890
|
+
const dataView = toDataView(binaryData);
|
|
1891
|
+
return getPngMetadata(dataView) || getJpegMetadata(dataView) || getGifMetadata(dataView) || getBmpMetadata(dataView) || getISOBMFFMetadata(dataView);
|
|
1892
|
+
}
|
|
1893
|
+
// ISOBMFF
|
|
1894
|
+
function getISOBMFFMetadata(binaryData) {
|
|
1895
|
+
const buffer = new Uint8Array(binaryData instanceof DataView ? binaryData.buffer : binaryData);
|
|
1896
|
+
const mediaType = getISOBMFFMediaType(buffer);
|
|
1897
|
+
if (!mediaType) {
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1900
|
+
return {
|
|
1901
|
+
mimeType: mediaType.mimeType,
|
|
1902
|
+
// TODO - decode width and height
|
|
1903
|
+
width: 0,
|
|
1904
|
+
height: 0
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
// PNG
|
|
1908
|
+
function getPngMetadata(binaryData) {
|
|
1909
|
+
const dataView = toDataView(binaryData);
|
|
1910
|
+
// Check file contains the first 4 bytes of the PNG signature.
|
|
1911
|
+
const isPng = dataView.byteLength >= 24 && dataView.getUint32(0, BIG_ENDIAN) === 0x89504e47;
|
|
1912
|
+
if (!isPng) {
|
|
1913
|
+
return null;
|
|
1914
|
+
}
|
|
1915
|
+
// Extract size from a binary PNG file
|
|
1916
|
+
return {
|
|
1917
|
+
mimeType: 'image/png',
|
|
1918
|
+
width: dataView.getUint32(16, BIG_ENDIAN),
|
|
1919
|
+
height: dataView.getUint32(20, BIG_ENDIAN)
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
// GIF
|
|
1923
|
+
// Extract size from a binary GIF file
|
|
1924
|
+
// TODO: GIF is not this simple
|
|
1925
|
+
function getGifMetadata(binaryData) {
|
|
1926
|
+
const dataView = toDataView(binaryData);
|
|
1927
|
+
// Check first 4 bytes of the GIF signature ("GIF8").
|
|
1928
|
+
const isGif = dataView.byteLength >= 10 && dataView.getUint32(0, BIG_ENDIAN) === 0x47494638;
|
|
1929
|
+
if (!isGif) {
|
|
1930
|
+
return null;
|
|
1931
|
+
}
|
|
1932
|
+
// GIF is little endian.
|
|
1933
|
+
return {
|
|
1934
|
+
mimeType: 'image/gif',
|
|
1935
|
+
width: dataView.getUint16(6, LITTLE_ENDIAN),
|
|
1936
|
+
height: dataView.getUint16(8, LITTLE_ENDIAN)
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
// BMP
|
|
1940
|
+
// TODO: BMP is not this simple
|
|
1941
|
+
function getBmpMetadata(binaryData) {
|
|
1942
|
+
const dataView = toDataView(binaryData);
|
|
1943
|
+
// Check magic number is valid (first 2 characters should be "BM").
|
|
1944
|
+
// The mandatory bitmap file header is 14 bytes long.
|
|
1945
|
+
const isBmp = dataView.byteLength >= 14 && dataView.getUint16(0, BIG_ENDIAN) === 0x424d && dataView.getUint32(2, LITTLE_ENDIAN) === dataView.byteLength;
|
|
1946
|
+
if (!isBmp) {
|
|
1947
|
+
return null;
|
|
1948
|
+
}
|
|
1949
|
+
// BMP is little endian.
|
|
1950
|
+
return {
|
|
1951
|
+
mimeType: 'image/bmp',
|
|
1952
|
+
width: dataView.getUint32(18, LITTLE_ENDIAN),
|
|
1953
|
+
height: dataView.getUint32(22, LITTLE_ENDIAN)
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
// JPEG
|
|
1957
|
+
// Extract width and height from a binary JPEG file
|
|
1958
|
+
function getJpegMetadata(binaryData) {
|
|
1959
|
+
const dataView = toDataView(binaryData);
|
|
1960
|
+
// Check file contains the JPEG "start of image" (SOI) marker
|
|
1961
|
+
// followed by another marker.
|
|
1962
|
+
const isJpeg = dataView.byteLength >= 3 && dataView.getUint16(0, BIG_ENDIAN) === 0xffd8 && dataView.getUint8(2) === 0xff;
|
|
1963
|
+
if (!isJpeg) {
|
|
1964
|
+
return null;
|
|
1965
|
+
}
|
|
1966
|
+
const {
|
|
1967
|
+
tableMarkers,
|
|
1968
|
+
sofMarkers
|
|
1969
|
+
} = getJpegMarkers();
|
|
1970
|
+
// Exclude the two byte SOI marker.
|
|
1971
|
+
let i = 2;
|
|
1972
|
+
while (i + 9 < dataView.byteLength) {
|
|
1973
|
+
const marker = dataView.getUint16(i, BIG_ENDIAN);
|
|
1974
|
+
// The frame that contains the width and height of the JPEG image.
|
|
1975
|
+
if (sofMarkers.has(marker)) {
|
|
1976
|
+
return {
|
|
1977
|
+
mimeType: 'image/jpeg',
|
|
1978
|
+
height: dataView.getUint16(i + 5, BIG_ENDIAN),
|
|
1979
|
+
// Number of lines
|
|
1980
|
+
width: dataView.getUint16(i + 7, BIG_ENDIAN) // Number of pixels per line
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
// Miscellaneous tables/data preceding the frame header.
|
|
1984
|
+
if (!tableMarkers.has(marker)) {
|
|
1985
|
+
return null;
|
|
1986
|
+
}
|
|
1987
|
+
// Length includes size of length parameter but not the two byte header.
|
|
1988
|
+
i += 2;
|
|
1989
|
+
i += dataView.getUint16(i, BIG_ENDIAN);
|
|
1990
|
+
}
|
|
1991
|
+
return null;
|
|
1992
|
+
}
|
|
1993
|
+
function getJpegMarkers() {
|
|
1994
|
+
// Tables/misc header markers.
|
|
1995
|
+
// DQT, DHT, DAC, DRI, COM, APP_n
|
|
1996
|
+
const tableMarkers = new Set([0xffdb, 0xffc4, 0xffcc, 0xffdd, 0xfffe]);
|
|
1997
|
+
for (let i = 0xffe0; i < 0xfff0; ++i) {
|
|
1998
|
+
tableMarkers.add(i);
|
|
1999
|
+
}
|
|
2000
|
+
// SOF markers and DHP marker.
|
|
2001
|
+
// These markers are after tables/misc data.
|
|
2002
|
+
const sofMarkers = new Set([0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc9, 0xffca, 0xffcb, 0xffcd, 0xffce, 0xffcf, 0xffde]);
|
|
2003
|
+
return {
|
|
2004
|
+
tableMarkers,
|
|
2005
|
+
sofMarkers
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
// TODO - move into image module?
|
|
2009
|
+
function toDataView(data) {
|
|
2010
|
+
if (data instanceof DataView) {
|
|
2011
|
+
return data;
|
|
2012
|
+
}
|
|
2013
|
+
if (ArrayBuffer.isView(data)) {
|
|
2014
|
+
return new DataView(data.buffer);
|
|
2015
|
+
}
|
|
2016
|
+
// TODO: make these functions work for Node.js buffers?
|
|
2017
|
+
// if (bufferToArrayBuffer) {
|
|
2018
|
+
// data = bufferToArrayBuffer(data);
|
|
2019
|
+
// }
|
|
2020
|
+
// Careful - Node Buffers will look like ArrayBuffers (keep after isBuffer)
|
|
2021
|
+
if (data instanceof ArrayBuffer) {
|
|
2022
|
+
return new DataView(data);
|
|
2023
|
+
}
|
|
2024
|
+
throw new Error('toDataView');
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// Use polyfills if installed to parsed image using get-pixels
|
|
2028
|
+
async function parseToNodeImage(arrayBuffer, options) {
|
|
2029
|
+
const {
|
|
2030
|
+
mimeType
|
|
2031
|
+
} = getBinaryImageMetadata(arrayBuffer) || {};
|
|
2032
|
+
// @ts-ignore
|
|
2033
|
+
const parseImageNode = globalThis.loaders?.parseImageNode;
|
|
2034
|
+
assert$1(parseImageNode); // '@loaders.gl/polyfills not installed'
|
|
2035
|
+
// @ts-expect-error TODO should we throw error in this case?
|
|
2036
|
+
return await parseImageNode(arrayBuffer, mimeType);
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// Parse to platform defined image type (data on node, ImageBitmap or HTMLImage on browser)
|
|
2040
|
+
// eslint-disable-next-line complexity
|
|
2041
|
+
async function parseImage(arrayBuffer, options, context) {
|
|
2042
|
+
options = options || {};
|
|
2043
|
+
const imageOptions = options.image || {};
|
|
2044
|
+
// The user can request a specific output format via `options.image.type`
|
|
2045
|
+
const imageType = imageOptions.type || 'auto';
|
|
2046
|
+
const {
|
|
2047
|
+
url
|
|
2048
|
+
} = context || {};
|
|
2049
|
+
// Note: For options.image.type === `data`, we may still need to load as `image` or `imagebitmap`
|
|
2050
|
+
const loadType = getLoadableImageType(imageType);
|
|
2051
|
+
let image;
|
|
2052
|
+
switch (loadType) {
|
|
2053
|
+
case 'imagebitmap':
|
|
2054
|
+
image = await parseToImageBitmap(arrayBuffer, options, url);
|
|
2055
|
+
break;
|
|
2056
|
+
case 'image':
|
|
2057
|
+
image = await parseToImage(arrayBuffer, options, url);
|
|
2058
|
+
break;
|
|
2059
|
+
case 'data':
|
|
2060
|
+
// Node.js loads imagedata directly
|
|
2061
|
+
image = await parseToNodeImage(arrayBuffer);
|
|
2062
|
+
break;
|
|
2063
|
+
default:
|
|
2064
|
+
assert$1(false);
|
|
2065
|
+
}
|
|
2066
|
+
// Browser: if options.image.type === 'data', we can now extract data from the loaded image
|
|
2067
|
+
if (imageType === 'data') {
|
|
2068
|
+
image = getImageData(image);
|
|
2069
|
+
}
|
|
2070
|
+
return image;
|
|
2071
|
+
}
|
|
2072
|
+
// Get a loadable image type from image type
|
|
2073
|
+
function getLoadableImageType(type) {
|
|
2074
|
+
switch (type) {
|
|
2075
|
+
case 'auto':
|
|
2076
|
+
case 'data':
|
|
2077
|
+
// Browser: For image data we need still need to load using an image format
|
|
2078
|
+
// Node: the default image type is `data`.
|
|
2079
|
+
return getDefaultImageType();
|
|
2080
|
+
default:
|
|
2081
|
+
// Throw an error if not supported
|
|
2082
|
+
isImageTypeSupported(type);
|
|
2083
|
+
return type;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// import type { ImageType } from '@loaders.gl/schema';
|
|
2088
|
+
const EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'ico', 'svg', 'avif'];
|
|
2089
|
+
const MIME_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/avif', 'image/bmp', 'image/vnd.microsoft.icon', 'image/svg+xml'];
|
|
2090
|
+
const DEFAULT_IMAGE_LOADER_OPTIONS = {
|
|
2091
|
+
image: {
|
|
2092
|
+
type: 'auto',
|
|
2093
|
+
decode: true // if format is HTML
|
|
2094
|
+
}
|
|
2095
|
+
// imagebitmap: {} - passes (platform dependent) parameters to ImageBitmap constructor
|
|
2096
|
+
};
|
|
2097
|
+
/**
|
|
2098
|
+
* Loads a platform-specific image type
|
|
2099
|
+
* Note: This type can be used as input data to WebGL texture creation
|
|
2100
|
+
*/
|
|
2101
|
+
const ImageLoader = {
|
|
2102
|
+
dataType: null,
|
|
2103
|
+
batchType: null,
|
|
2104
|
+
id: 'image',
|
|
2105
|
+
module: 'images',
|
|
2106
|
+
name: 'Images',
|
|
2107
|
+
version: VERSION$1,
|
|
2108
|
+
mimeTypes: MIME_TYPES,
|
|
2109
|
+
extensions: EXTENSIONS,
|
|
2110
|
+
parse: parseImage,
|
|
2111
|
+
// TODO: byteOffset, byteLength;
|
|
2112
|
+
tests: [arrayBuffer => Boolean(getBinaryImageMetadata(new DataView(arrayBuffer)))],
|
|
2113
|
+
options: DEFAULT_IMAGE_LOADER_OPTIONS
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
const defaultLogger = new Log({
|
|
2117
|
+
id: 'deck'
|
|
2118
|
+
});
|
|
2119
|
+
var log = defaultLogger;
|
|
2120
|
+
|
|
2121
|
+
const logState = {
|
|
2122
|
+
attributeUpdateStart: -1,
|
|
2123
|
+
attributeManagerUpdateStart: -1,
|
|
2124
|
+
attributeUpdateMessages: []
|
|
2125
|
+
};
|
|
2126
|
+
const LOG_LEVEL_MAJOR_UPDATE = 1; // Events with direct perf impact
|
|
2127
|
+
const LOG_LEVEL_MINOR_UPDATE = 2; // Events that may affect perf
|
|
2128
|
+
const LOG_LEVEL_UPDATE_DETAIL = 3;
|
|
2129
|
+
const LOG_LEVEL_INFO = 4;
|
|
2130
|
+
const LOG_LEVEL_DRAW = 2;
|
|
2131
|
+
const getLoggers = log => ({
|
|
2132
|
+
/* Layer events */
|
|
2133
|
+
'layer.changeFlag': (layer, key, flags) => {
|
|
2134
|
+
log.log(LOG_LEVEL_UPDATE_DETAIL, `${layer.id} ${key}: `, flags[key])();
|
|
2135
|
+
},
|
|
2136
|
+
'layer.initialize': layer => {
|
|
2137
|
+
log.log(LOG_LEVEL_MAJOR_UPDATE, `Initializing ${layer}`)();
|
|
2138
|
+
},
|
|
2139
|
+
'layer.update': (layer, needsUpdate) => {
|
|
2140
|
+
if (needsUpdate) {
|
|
2141
|
+
const flags = layer.getChangeFlags();
|
|
2142
|
+
log.log(LOG_LEVEL_MINOR_UPDATE, `Updating ${layer} because: ${Object.keys(flags).filter(key => flags[key]).join(', ')}`)();
|
|
2143
|
+
} else {
|
|
2144
|
+
log.log(LOG_LEVEL_INFO, `${layer} does not need update`)();
|
|
2145
|
+
}
|
|
2146
|
+
},
|
|
2147
|
+
'layer.matched': (layer, changed) => {
|
|
2148
|
+
if (changed) {
|
|
2149
|
+
log.log(LOG_LEVEL_INFO, `Matched ${layer}, state transfered`)();
|
|
2150
|
+
}
|
|
2151
|
+
},
|
|
2152
|
+
'layer.finalize': layer => {
|
|
2153
|
+
log.log(LOG_LEVEL_MAJOR_UPDATE, `Finalizing ${layer}`)();
|
|
2154
|
+
},
|
|
2155
|
+
/* CompositeLayer events */
|
|
2156
|
+
'compositeLayer.renderLayers': (layer, updated, subLayers) => {
|
|
2157
|
+
if (updated) {
|
|
2158
|
+
log.log(LOG_LEVEL_MINOR_UPDATE, `Composite layer rendered new subLayers ${layer}`, subLayers)();
|
|
2159
|
+
} else {
|
|
2160
|
+
log.log(LOG_LEVEL_INFO, `Composite layer reused subLayers ${layer}`, subLayers)();
|
|
2161
|
+
}
|
|
2162
|
+
},
|
|
2163
|
+
/* LayerManager events */
|
|
2164
|
+
'layerManager.setLayers': (layerManager, updated, layers) => {
|
|
2165
|
+
if (updated) {
|
|
2166
|
+
log.log(LOG_LEVEL_MINOR_UPDATE, `Updating ${layers.length} deck layers`)();
|
|
2167
|
+
}
|
|
2168
|
+
},
|
|
2169
|
+
'layerManager.activateViewport': (layerManager, viewport) => {
|
|
2170
|
+
log.log(LOG_LEVEL_UPDATE_DETAIL, 'Viewport changed', viewport)();
|
|
2171
|
+
},
|
|
2172
|
+
/* AttributeManager events */
|
|
2173
|
+
'attributeManager.invalidate': (attributeManager, trigger, attributeNames) => {
|
|
2174
|
+
log.log(LOG_LEVEL_MAJOR_UPDATE, attributeNames ? `invalidated attributes ${attributeNames} (${trigger}) for ${attributeManager.id}` : `invalidated all attributes for ${attributeManager.id}`)();
|
|
2175
|
+
},
|
|
2176
|
+
'attributeManager.updateStart': attributeManager => {
|
|
2177
|
+
logState.attributeUpdateMessages.length = 0;
|
|
2178
|
+
logState.attributeManagerUpdateStart = Date.now();
|
|
2179
|
+
},
|
|
2180
|
+
'attributeManager.updateEnd': (attributeManager, numInstances) => {
|
|
2181
|
+
const timeMs = Math.round(Date.now() - logState.attributeManagerUpdateStart);
|
|
2182
|
+
log.groupCollapsed(LOG_LEVEL_MINOR_UPDATE, `Updated attributes for ${numInstances} instances in ${attributeManager.id} in ${timeMs}ms`)();
|
|
2183
|
+
for (const updateMessage of logState.attributeUpdateMessages) {
|
|
2184
|
+
log.log(LOG_LEVEL_UPDATE_DETAIL, updateMessage)();
|
|
2185
|
+
}
|
|
2186
|
+
log.groupEnd(LOG_LEVEL_MINOR_UPDATE)();
|
|
2187
|
+
},
|
|
2188
|
+
/* Attribute events */
|
|
2189
|
+
'attribute.updateStart': attribute => {
|
|
2190
|
+
logState.attributeUpdateStart = Date.now();
|
|
2191
|
+
},
|
|
2192
|
+
'attribute.allocate': (attribute, numInstances) => {
|
|
2193
|
+
const message = `${attribute.id} allocated ${numInstances}`;
|
|
2194
|
+
logState.attributeUpdateMessages.push(message);
|
|
2195
|
+
},
|
|
2196
|
+
'attribute.updateEnd': (attribute, numInstances) => {
|
|
2197
|
+
const timeMs = Math.round(Date.now() - logState.attributeUpdateStart);
|
|
2198
|
+
const message = `${attribute.id} updated ${numInstances} in ${timeMs}ms`;
|
|
2199
|
+
logState.attributeUpdateMessages.push(message);
|
|
2200
|
+
},
|
|
2201
|
+
/* Render events */
|
|
2202
|
+
'deckRenderer.renderLayers': (deckRenderer, renderStats, opts) => {
|
|
2203
|
+
const {
|
|
2204
|
+
pass,
|
|
2205
|
+
redrawReason,
|
|
2206
|
+
stats
|
|
2207
|
+
} = opts;
|
|
2208
|
+
for (const status of renderStats) {
|
|
2209
|
+
const {
|
|
2210
|
+
totalCount,
|
|
2211
|
+
visibleCount,
|
|
2212
|
+
compositeCount,
|
|
2213
|
+
pickableCount
|
|
2214
|
+
} = status;
|
|
2215
|
+
const primitiveCount = totalCount - compositeCount;
|
|
2216
|
+
const hiddenCount = primitiveCount - visibleCount;
|
|
2217
|
+
log.log(LOG_LEVEL_DRAW, `RENDER #${deckRenderer.renderCount} \
|
|
2218
|
+
${visibleCount} (of ${totalCount} layers) to ${pass} because ${redrawReason} \
|
|
2219
|
+
(${hiddenCount} hidden, ${compositeCount} composite ${pickableCount} pickable)`)();
|
|
2220
|
+
if (stats) {
|
|
2221
|
+
stats.get('Redraw Layers').add(visibleCount);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
});
|
|
2226
|
+
|
|
2227
|
+
// Conditionally load default loggers in development mode
|
|
2228
|
+
// eslint-disable-next-line
|
|
2229
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
2230
|
+
getLoggers(log);
|
|
2231
|
+
}
|
|
2232
|
+
function register(handlers) {
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
function isJSON(text) {
|
|
2236
|
+
const firstChar = text[0];
|
|
2237
|
+
const lastChar = text[text.length - 1];
|
|
2238
|
+
return firstChar === '{' && lastChar === '}' || firstChar === '[' && lastChar === ']';
|
|
2239
|
+
}
|
|
2240
|
+
// A light weight version instead of @loaders.gl/json (stream processing etc.)
|
|
2241
|
+
var jsonLoader = {
|
|
2242
|
+
dataType: null,
|
|
2243
|
+
batchType: null,
|
|
2244
|
+
id: 'JSON',
|
|
2245
|
+
name: 'JSON',
|
|
2246
|
+
module: '',
|
|
2247
|
+
version: '',
|
|
2248
|
+
options: {},
|
|
2249
|
+
extensions: ['json', 'geojson'],
|
|
2250
|
+
mimeTypes: ['application/json', 'application/geo+json'],
|
|
2251
|
+
testText: isJSON,
|
|
2252
|
+
parseTextSync: JSON.parse
|
|
2253
|
+
};
|
|
2254
|
+
|
|
2255
|
+
// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
|
|
2256
|
+
function checkVersion() {
|
|
2257
|
+
// Version detection using typescript plugin.
|
|
2258
|
+
// Fallback for tests and SSR since global variable is defined by esbuild.
|
|
2259
|
+
const version = "9.0.30" ;
|
|
2260
|
+
// Note: a `deck` object not created by deck.gl may exist in the global scope
|
|
2261
|
+
const existingVersion = globalThis.deck && globalThis.deck.VERSION;
|
|
2262
|
+
if (existingVersion && existingVersion !== version) {
|
|
2263
|
+
throw new Error(`deck.gl - multiple versions detected: ${existingVersion} vs ${version}`);
|
|
2264
|
+
}
|
|
2265
|
+
if (!existingVersion) {
|
|
2266
|
+
log.log(1, `deck.gl ${version}`)();
|
|
2267
|
+
globalThis.deck = {
|
|
2268
|
+
...globalThis.deck,
|
|
2269
|
+
VERSION: version,
|
|
2270
|
+
version,
|
|
2271
|
+
log,
|
|
2272
|
+
// experimental
|
|
2273
|
+
_registerLoggers: register
|
|
2274
|
+
};
|
|
2275
|
+
registerLoaders([jsonLoader,
|
|
2276
|
+
// @ts-expect-error non-standard Loader format
|
|
2277
|
+
[ImageLoader, {
|
|
2278
|
+
imagebitmap: {
|
|
2279
|
+
premultiplyAlpha: 'none'
|
|
2280
|
+
}
|
|
2281
|
+
}]]);
|
|
2282
|
+
}
|
|
2283
|
+
return version;
|
|
2284
|
+
}
|
|
2285
|
+
const VERSION = checkVersion();
|
|
2286
|
+
|
|
918
2287
|
const DEFAULT_TILE_RESOLUTION = 0.5;
|
|
919
2288
|
const DEFAULT_AGGREGATION_RES_LEVEL_H3 = 4;
|
|
920
2289
|
const DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN = 6;
|
|
@@ -994,7 +2363,7 @@ function buildSourceUrl({
|
|
|
994
2363
|
*/
|
|
995
2364
|
const DEFAULT_PARAMETERS = {
|
|
996
2365
|
v: V3_MINOR_VERSION,
|
|
997
|
-
deckglVersion:
|
|
2366
|
+
deckglVersion: VERSION
|
|
998
2367
|
};
|
|
999
2368
|
const DEFAULT_HEADERS = {
|
|
1000
2369
|
Accept: 'application/json',
|
|
@@ -1480,5 +2849,5 @@ function assignDefaultProps(props) {
|
|
|
1480
2849
|
}
|
|
1481
2850
|
}
|
|
1482
2851
|
|
|
1483
|
-
export { FilterType, WidgetBaseSource, WidgetQuerySource, WidgetTableSource, addFilter, clearFilters, createPolygonSpatialFilter, createViewportSpatialFilter, getClient, getFilter, h3QuerySource, h3TableSource, hasFilter, quadbinQuerySource, quadbinTableSource, removeFilter, setClient, vectorQuerySource, vectorTableSource };
|
|
2852
|
+
export { API_CLIENT_VERSION, FilterType, WidgetBaseSource, WidgetQuerySource, WidgetTableSource, addFilter, clearFilters, createPolygonSpatialFilter, createViewportSpatialFilter, getClient, getFilter, h3QuerySource, h3TableSource, hasFilter, quadbinQuerySource, quadbinTableSource, removeFilter, setClient, vectorQuerySource, vectorTableSource };
|
|
1484
2853
|
//# sourceMappingURL=api-client.modern.js.map
|