@geolibre/core 2.7.0 → 2.8.0
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/dist/index.d.mts +358 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +592 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -2270,14 +2270,24 @@ function batchDecodePolylines(input, options = {}) {
|
|
|
2270
2270
|
}
|
|
2271
2271
|
//#endregion
|
|
2272
2272
|
//#region src/runtime-env.ts
|
|
2273
|
+
const buildEnv = typeof __GEOLIBRE_BUILD_ENV__ === "undefined" ? {} : __GEOLIBRE_BUILD_ENV__;
|
|
2273
2274
|
/**
|
|
2274
|
-
*
|
|
2275
|
-
*
|
|
2276
|
-
*
|
|
2277
|
-
*
|
|
2278
|
-
*
|
|
2275
|
+
* The allowlisted build-time environment, with no runtime overlay.
|
|
2276
|
+
*
|
|
2277
|
+
* For settings that must be fixed by the build and NOT overridable by a
|
|
2278
|
+
* `.geolibre.json` a user opened — the auth gate, the deployment profile, the
|
|
2279
|
+
* embed origin allowlist. Routing those through {@link getRuntimeEnvironment}
|
|
2280
|
+
* would let project-supplied `__GEOLIBRE_RUNTIME_ENV__` values relax them.
|
|
2281
|
+
*
|
|
2282
|
+
* Callers should prefer this over reading `import.meta.env` directly: a
|
|
2283
|
+
* whole-object read defeats Vite's per-key replacement and inlines every
|
|
2284
|
+
* `VITE_` var on the build machine into the chunk.
|
|
2285
|
+
*
|
|
2286
|
+
* @returns The build-time environment record.
|
|
2279
2287
|
*/
|
|
2280
|
-
|
|
2288
|
+
function getBuildEnvironment() {
|
|
2289
|
+
return buildEnv;
|
|
2290
|
+
}
|
|
2281
2291
|
/**
|
|
2282
2292
|
* Merges build-time env with project runtime env (the latter wins). Falls back
|
|
2283
2293
|
* to build-time env alone outside a browser (e.g. in tests).
|
|
@@ -2285,9 +2295,9 @@ const buildEnv = import.meta.env;
|
|
|
2285
2295
|
* @returns The resolved environment variables.
|
|
2286
2296
|
*/
|
|
2287
2297
|
function getRuntimeEnvironment() {
|
|
2288
|
-
if (typeof window === "undefined") return buildEnv
|
|
2298
|
+
if (typeof window === "undefined") return buildEnv;
|
|
2289
2299
|
return {
|
|
2290
|
-
...buildEnv
|
|
2300
|
+
...buildEnv,
|
|
2291
2301
|
...window.__GEOLIBRE_RUNTIME_ENV__ ?? {}
|
|
2292
2302
|
};
|
|
2293
2303
|
}
|
|
@@ -4135,6 +4145,302 @@ function featureForEvaluation(properties, feature) {
|
|
|
4135
4145
|
};
|
|
4136
4146
|
}
|
|
4137
4147
|
//#endregion
|
|
4148
|
+
//#region src/popup.ts
|
|
4149
|
+
/** Match an inline base64 raster image (excludes SVG, which can carry scripts). */
|
|
4150
|
+
const INLINE_IMAGE_DATA_URL = /^data:image\/(?!svg)[\w.+-]+;base64,/i;
|
|
4151
|
+
/**
|
|
4152
|
+
* A trimmed non-empty string, or `undefined` for anything else.
|
|
4153
|
+
*
|
|
4154
|
+
* Popup configs arrive from untrusted JSON — a hand-edited `.geolibre.json`, an
|
|
4155
|
+
* imported layer-library bundle, an MCP-authored project — so a field typed as
|
|
4156
|
+
* `string` may hold a number, an object or null. `value.trim()` on one of those
|
|
4157
|
+
* throws and takes the whole popup render with it, so every string read here
|
|
4158
|
+
* goes through this.
|
|
4159
|
+
*/
|
|
4160
|
+
function trimmedString(value) {
|
|
4161
|
+
if (typeof value !== "string") return void 0;
|
|
4162
|
+
const trimmed = value.trim();
|
|
4163
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
4164
|
+
}
|
|
4165
|
+
/** Whether the Identify popup should open for a layer. Default: yes. */
|
|
4166
|
+
function isPopupClickEnabled(popup) {
|
|
4167
|
+
return popup?.click !== false;
|
|
4168
|
+
}
|
|
4169
|
+
/** Whether a hover tooltip should follow the pointer. Default: no. */
|
|
4170
|
+
function isPopupHoverEnabled(popup) {
|
|
4171
|
+
return popup?.hover === true;
|
|
4172
|
+
}
|
|
4173
|
+
/** The label a popup shows for a configured field. */
|
|
4174
|
+
function popupFieldLabel(config) {
|
|
4175
|
+
return trimmedString(config.label) ?? config.field;
|
|
4176
|
+
}
|
|
4177
|
+
/**
|
|
4178
|
+
* Property keys that never belong in a popup: GeoLibre's own internal columns
|
|
4179
|
+
* and the full-resolution companion of a photo thumbnail (an internal twin of
|
|
4180
|
+
* a value already shown, and often multiple megabytes of data URL).
|
|
4181
|
+
*/
|
|
4182
|
+
function isInternalPopupField(key) {
|
|
4183
|
+
return key === "photo_full" || key.startsWith("__geolibre_");
|
|
4184
|
+
}
|
|
4185
|
+
/**
|
|
4186
|
+
* The property keys a popup may show, before any popup config narrows them:
|
|
4187
|
+
* the feature's own keys minus the internal ones and anything the author
|
|
4188
|
+
* marked `"hidden"` or `"excluded"`.
|
|
4189
|
+
*/
|
|
4190
|
+
function visiblePopupFields(properties, fieldVisibility) {
|
|
4191
|
+
return Object.keys(properties).filter((key) => !isInternalPopupField(key) && !fieldVisibility?.[key]);
|
|
4192
|
+
}
|
|
4193
|
+
function formatNumber(value, format, locale) {
|
|
4194
|
+
const options = { useGrouping: format.thousands === true };
|
|
4195
|
+
if (format.decimals != null && Number.isFinite(format.decimals)) {
|
|
4196
|
+
const digits = Math.max(0, Math.min(20, Math.trunc(format.decimals)));
|
|
4197
|
+
options.minimumFractionDigits = digits;
|
|
4198
|
+
options.maximumFractionDigits = digits;
|
|
4199
|
+
}
|
|
4200
|
+
return new Intl.NumberFormat(locale, options).format(value);
|
|
4201
|
+
}
|
|
4202
|
+
/**
|
|
4203
|
+
* Coerce a property value to a Date. A number is epoch milliseconds (what a
|
|
4204
|
+
* GeoJSON timestamp column normally holds); a string goes through `Date`'s own
|
|
4205
|
+
* parser. Anything that does not parse comes back as `null` so the caller can
|
|
4206
|
+
* fall back to the raw text rather than printing "Invalid Date".
|
|
4207
|
+
*/
|
|
4208
|
+
function toDate(value) {
|
|
4209
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
|
|
4210
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
4211
|
+
const fromEpoch = new Date(value);
|
|
4212
|
+
return Number.isNaN(fromEpoch.getTime()) ? null : fromEpoch;
|
|
4213
|
+
}
|
|
4214
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
4215
|
+
const parsed = new Date(value);
|
|
4216
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
4217
|
+
}
|
|
4218
|
+
return null;
|
|
4219
|
+
}
|
|
4220
|
+
function formatDate(date, dateFormat, locale) {
|
|
4221
|
+
switch (dateFormat) {
|
|
4222
|
+
case "datetime": return date.toLocaleString(locale);
|
|
4223
|
+
case "time": return date.toLocaleTimeString(locale);
|
|
4224
|
+
case "iso": return date.toISOString();
|
|
4225
|
+
case "year": return String(date.getFullYear());
|
|
4226
|
+
default: return date.toLocaleDateString(locale);
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
/** Stringify a value the way the untyped popup always has. */
|
|
4230
|
+
function stringifyPopupValue(value) {
|
|
4231
|
+
if (value == null) return "";
|
|
4232
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
4233
|
+
return String(value);
|
|
4234
|
+
}
|
|
4235
|
+
/**
|
|
4236
|
+
* Render one value as text under a field's kind and format. `"auto"` and
|
|
4237
|
+
* `"image"` values are returned verbatim (the renderer draws them itself);
|
|
4238
|
+
* every other kind is stringified, formatted, then wrapped in the configured
|
|
4239
|
+
* prefix/suffix.
|
|
4240
|
+
*/
|
|
4241
|
+
function formatPopupValue(value, config = {}, options = {}) {
|
|
4242
|
+
const kind = config.kind ?? "auto";
|
|
4243
|
+
const format = config.format ?? {};
|
|
4244
|
+
if (kind === "auto" || kind === "image") return stringifyPopupValue(value);
|
|
4245
|
+
if (value == null || typeof value === "string" && value.trim() === "") return "";
|
|
4246
|
+
let body;
|
|
4247
|
+
if (kind === "number") {
|
|
4248
|
+
const numeric = typeof value === "number" ? value : Number(stringifyPopupValue(value));
|
|
4249
|
+
body = Number.isFinite(numeric) ? formatNumber(numeric, format, options.locale) : stringifyPopupValue(value);
|
|
4250
|
+
} else if (kind === "date") {
|
|
4251
|
+
const date = toDate(value);
|
|
4252
|
+
body = date ? formatDate(date, format.dateFormat ?? "date", options.locale) : stringifyPopupValue(value);
|
|
4253
|
+
} else body = stringifyPopupValue(value);
|
|
4254
|
+
if (body === "") return "";
|
|
4255
|
+
return `${format.prefix ?? ""}${body}${format.suffix ?? ""}`;
|
|
4256
|
+
}
|
|
4257
|
+
/** Whether a row would draw as a picture rather than as text. */
|
|
4258
|
+
function rendersAsImage(kind, value) {
|
|
4259
|
+
return kind === "image" || kind === "auto" && isInlineImageValue(value);
|
|
4260
|
+
}
|
|
4261
|
+
/**
|
|
4262
|
+
* The properties a popup may read, with the author's hidden and excluded
|
|
4263
|
+
* fields and GeoLibre's internal columns removed.
|
|
4264
|
+
*
|
|
4265
|
+
* Expressions get this rather than the raw record. `["get", "ssn"]` in a title
|
|
4266
|
+
* or body would otherwise reach a column the author hid, printing it into the
|
|
4267
|
+
* popup — and onto the hover tooltip, which needs no click at all. The rest of
|
|
4268
|
+
* this module already honors `fieldVisibility` field by field; an expression
|
|
4269
|
+
* has no field list to filter, so the filtering has to happen to its input.
|
|
4270
|
+
*/
|
|
4271
|
+
function visiblePopupProperties(properties, fieldVisibility) {
|
|
4272
|
+
const visible = {};
|
|
4273
|
+
for (const key of visiblePopupFields(properties, fieldVisibility)) visible[key] = properties[key];
|
|
4274
|
+
return visible;
|
|
4275
|
+
}
|
|
4276
|
+
/**
|
|
4277
|
+
* The rows a popup (or hover tooltip) should render for one feature's
|
|
4278
|
+
* properties.
|
|
4279
|
+
*
|
|
4280
|
+
* With no `popup.fields`, every visible property is returned in the feature's
|
|
4281
|
+
* own key order and left untyped, which is exactly what the popup did before
|
|
4282
|
+
* the designer existed. With a list, only the listed fields appear, in the
|
|
4283
|
+
* listed order, under their labels and formats — and a listed field the
|
|
4284
|
+
* feature does not carry is skipped rather than printed empty, so one config
|
|
4285
|
+
* can cover a layer whose features have ragged properties.
|
|
4286
|
+
*
|
|
4287
|
+
* `hover: true` narrows the list to fields flagged `hover`. A hover request
|
|
4288
|
+
* with no flagged field returns nothing: an author who turned the tooltip on
|
|
4289
|
+
* without choosing a field gets no tip rather than the whole table following
|
|
4290
|
+
* the pointer.
|
|
4291
|
+
*/
|
|
4292
|
+
function resolvePopupRows(properties, options = {}) {
|
|
4293
|
+
const { popup, fieldVisibility, hover = false, locale } = options;
|
|
4294
|
+
const configured = (Array.isArray(popup?.fields) ? popup.fields : []).filter((config) => Boolean(config) && typeof config.field === "string");
|
|
4295
|
+
if (configured.length === 0) {
|
|
4296
|
+
if (hover) return [];
|
|
4297
|
+
return visiblePopupFields(properties, fieldVisibility).map((field) => ({
|
|
4298
|
+
field,
|
|
4299
|
+
label: field,
|
|
4300
|
+
value: properties[field],
|
|
4301
|
+
text: stringifyPopupValue(properties[field]),
|
|
4302
|
+
kind: "auto"
|
|
4303
|
+
}));
|
|
4304
|
+
}
|
|
4305
|
+
const rows = [];
|
|
4306
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4307
|
+
for (const config of configured) {
|
|
4308
|
+
if (hover && config.hover !== true) continue;
|
|
4309
|
+
if (fieldVisibility?.[config.field]) continue;
|
|
4310
|
+
if (isInternalPopupField(config.field)) continue;
|
|
4311
|
+
if (!(config.field in properties)) continue;
|
|
4312
|
+
if (seen.has(config.field)) continue;
|
|
4313
|
+
const value = properties[config.field];
|
|
4314
|
+
if (hover && rendersAsImage(config.kind ?? "auto", value)) continue;
|
|
4315
|
+
seen.add(config.field);
|
|
4316
|
+
rows.push({
|
|
4317
|
+
field: config.field,
|
|
4318
|
+
label: popupFieldLabel(config),
|
|
4319
|
+
value,
|
|
4320
|
+
text: formatPopupValue(value, config, { locale }),
|
|
4321
|
+
kind: config.kind ?? "auto",
|
|
4322
|
+
...trimmedString(config.format?.linkLabel) ? { linkLabel: trimmedString(config.format?.linkLabel) } : {}
|
|
4323
|
+
});
|
|
4324
|
+
}
|
|
4325
|
+
return rows;
|
|
4326
|
+
}
|
|
4327
|
+
/**
|
|
4328
|
+
* Compiled title/body expressions, keyed by zoom and source.
|
|
4329
|
+
*
|
|
4330
|
+
* `createHoverTooltipElement` calls {@link resolvePopupTitle} once per
|
|
4331
|
+
* animation frame for as long as the pointer sits on a hovered feature, and
|
|
4332
|
+
* compiling means a `JSON.parse` plus a full style-spec validation. Without
|
|
4333
|
+
* this the same unchanged source string would be re-parsed sixty times a
|
|
4334
|
+
* second. Zoom is part of the key because a compiled expression bakes it in
|
|
4335
|
+
* for `["zoom"]`; it is constant through a hover, so the cache still hits.
|
|
4336
|
+
*/
|
|
4337
|
+
const EXPRESSION_CACHE = /* @__PURE__ */ new Map();
|
|
4338
|
+
/** Bound on the cache, so a project full of layers cannot grow it without end. */
|
|
4339
|
+
const EXPRESSION_CACHE_LIMIT = 64;
|
|
4340
|
+
function compiledPopupExpression(source, zoom) {
|
|
4341
|
+
const key = `${zoom}\u0000${source}`;
|
|
4342
|
+
const cached = EXPRESSION_CACHE.get(key);
|
|
4343
|
+
if (cached) return cached;
|
|
4344
|
+
const compiled = compileFeatureExpression(source, { zoom });
|
|
4345
|
+
if (EXPRESSION_CACHE.size >= EXPRESSION_CACHE_LIMIT) {
|
|
4346
|
+
const oldest = EXPRESSION_CACHE.keys().next().value;
|
|
4347
|
+
if (oldest !== void 0) EXPRESSION_CACHE.delete(oldest);
|
|
4348
|
+
}
|
|
4349
|
+
EXPRESSION_CACHE.set(key, compiled);
|
|
4350
|
+
return compiled;
|
|
4351
|
+
}
|
|
4352
|
+
/**
|
|
4353
|
+
* Evaluate a popup expression against a feature's properties, or return
|
|
4354
|
+
* `undefined` when it does not compile or throws. Both failures mean the same
|
|
4355
|
+
* thing to every caller here: fall back to what the popup would show without
|
|
4356
|
+
* the expression.
|
|
4357
|
+
*/
|
|
4358
|
+
function evaluatePopupExpression(source, properties, options) {
|
|
4359
|
+
const compiled = compiledPopupExpression(source, options.zoom ?? 0);
|
|
4360
|
+
if (!compiled.ok || !compiled.evaluate) return void 0;
|
|
4361
|
+
try {
|
|
4362
|
+
return compiled.evaluate(featureFor(visiblePopupProperties(properties, options.fieldVisibility), options.feature));
|
|
4363
|
+
} catch {
|
|
4364
|
+
return;
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
/** Build the synthetic feature an expression is evaluated against. */
|
|
4368
|
+
function featureFor(properties, feature) {
|
|
4369
|
+
if (feature) return {
|
|
4370
|
+
...feature,
|
|
4371
|
+
properties
|
|
4372
|
+
};
|
|
4373
|
+
return {
|
|
4374
|
+
type: "Feature",
|
|
4375
|
+
geometry: null,
|
|
4376
|
+
properties
|
|
4377
|
+
};
|
|
4378
|
+
}
|
|
4379
|
+
/**
|
|
4380
|
+
* The heading a popup should show: the title expression's value, else the
|
|
4381
|
+
* title field's value, else the layer name. An expression that fails to
|
|
4382
|
+
* compile or evaluate, and a title field that is empty or hidden, both fall
|
|
4383
|
+
* back to the layer name rather than leaving the popup headless.
|
|
4384
|
+
*/
|
|
4385
|
+
function resolvePopupTitle(layerName, properties, popup, options = {}) {
|
|
4386
|
+
return resolveConfiguredPopupTitle(properties, popup, options) ?? layerName;
|
|
4387
|
+
}
|
|
4388
|
+
/**
|
|
4389
|
+
* The title the author's own configuration produced, or `null` when there is
|
|
4390
|
+
* none — no title field or expression, or one that evaluated to nothing, or a
|
|
4391
|
+
* field the author hid.
|
|
4392
|
+
*
|
|
4393
|
+
* {@link resolvePopupTitle} is this plus the layer-name fallback. The hover
|
|
4394
|
+
* tooltip needs the two apart: a tip with no fields and no configured title
|
|
4395
|
+
* would be a box repeating the layer name, so it is suppressed — but that
|
|
4396
|
+
* decision has to rest on whether a title was *configured*, not on whether the
|
|
4397
|
+
* resolved text happens to equal the layer name. A city layer named "Olympia"
|
|
4398
|
+
* whose feature is also called "Olympia" is a real title, not a fallback.
|
|
4399
|
+
*/
|
|
4400
|
+
function resolveConfiguredPopupTitle(properties, popup, options = {}) {
|
|
4401
|
+
const source = trimmedString(popup?.titleExpression);
|
|
4402
|
+
if (source) {
|
|
4403
|
+
const text = stringifyPopupValue(evaluatePopupExpression(source, properties, options)).trim();
|
|
4404
|
+
if (text) return text;
|
|
4405
|
+
}
|
|
4406
|
+
const field = trimmedString(popup?.titleField);
|
|
4407
|
+
if (field && !options.fieldVisibility?.[field] && !isInternalPopupField(field)) {
|
|
4408
|
+
const text = stringifyPopupValue(properties[field]).trim();
|
|
4409
|
+
if (text) return text;
|
|
4410
|
+
}
|
|
4411
|
+
return null;
|
|
4412
|
+
}
|
|
4413
|
+
/**
|
|
4414
|
+
* The popup body text when the author supplied a body expression, or `null`
|
|
4415
|
+
* when there is none (or it failed) and the field rows should render instead.
|
|
4416
|
+
*/
|
|
4417
|
+
function resolvePopupBody(properties, popup, options = {}) {
|
|
4418
|
+
const source = trimmedString(popup?.bodyExpression);
|
|
4419
|
+
if (!source) return null;
|
|
4420
|
+
const preview = evaluatePopupExpression(source, properties, options);
|
|
4421
|
+
if (preview === void 0) return null;
|
|
4422
|
+
const text = stringifyPopupValue(preview);
|
|
4423
|
+
return text.trim() ? text : null;
|
|
4424
|
+
}
|
|
4425
|
+
/**
|
|
4426
|
+
* Whether a value should render as an inline image thumbnail under `"auto"`.
|
|
4427
|
+
* Kept here so the renderer and the designer's preview agree on what counts.
|
|
4428
|
+
*/
|
|
4429
|
+
function isInlineImageValue(value) {
|
|
4430
|
+
return typeof value === "string" && INLINE_IMAGE_DATA_URL.test(value);
|
|
4431
|
+
}
|
|
4432
|
+
/**
|
|
4433
|
+
* Whether a URL is safe to put in a popup `href`/`src`. Only http(s) and
|
|
4434
|
+
* inline raster data URLs: a `javascript:` or `data:text/html` value coming
|
|
4435
|
+
* from an untrusted GeoJSON must never become a live link.
|
|
4436
|
+
*/
|
|
4437
|
+
function isSafePopupUrl(value, allowDataImage = false) {
|
|
4438
|
+
if (typeof value !== "string") return false;
|
|
4439
|
+
const trimmed = value.trim();
|
|
4440
|
+
if (/^https?:\/\//i.test(trimmed)) return true;
|
|
4441
|
+
return allowDataImage && INLINE_IMAGE_DATA_URL.test(trimmed);
|
|
4442
|
+
}
|
|
4443
|
+
//#endregion
|
|
4138
4444
|
//#region src/virtual-fields.ts
|
|
4139
4445
|
/**
|
|
4140
4446
|
* Virtual fields (QGIS Field Calculator → "Create virtual field", issue
|
|
@@ -4604,6 +4910,246 @@ function reapplyLayerJoins(layers) {
|
|
|
4604
4910
|
return current;
|
|
4605
4911
|
}
|
|
4606
4912
|
//#endregion
|
|
4913
|
+
//#region src/quick-filters.ts
|
|
4914
|
+
/**
|
|
4915
|
+
* Quick filters (issue #2114): per-layer, data-driven filter controls that
|
|
4916
|
+
* compile down to the MapLibre filter a layer already supports.
|
|
4917
|
+
*
|
|
4918
|
+
* The persisted record is the *control state* (field, kind, chosen values),
|
|
4919
|
+
* never the compiled expression. Storing the compiled output would make a
|
|
4920
|
+
* filter unreadable and un-editable the moment it is saved, which is exactly
|
|
4921
|
+
* the wall this feature exists to remove: a rule filter, Select by Expression,
|
|
4922
|
+
* and the attribute table's filter box all already accept a hand-written
|
|
4923
|
+
* MapLibre expression.
|
|
4924
|
+
*
|
|
4925
|
+
* Compilation happens at sync time in `@geolibre/map`'s layer sync, which
|
|
4926
|
+
* combines the result with the transient `timeFilter`, the embed API's
|
|
4927
|
+
* `embedFilter`, and the rule-based visibility filter under one `["all", …]`,
|
|
4928
|
+
* so a host page's filter and a user's filter narrow the layer together
|
|
4929
|
+
* instead of clobbering each other.
|
|
4930
|
+
*
|
|
4931
|
+
* Every clause reads the property in place, so the same expression is correct
|
|
4932
|
+
* for a GeoJSON source and for a tile-backed source whose tiles decode later.
|
|
4933
|
+
*/
|
|
4934
|
+
/** Day length in milliseconds, used to make a date filter's end day inclusive. */
|
|
4935
|
+
const DAY_MS = 864e5;
|
|
4936
|
+
/** The `YYYY-MM-DD` prefix length every ISO date comparison slices to. */
|
|
4937
|
+
const ISO_DAY_LENGTH = 10;
|
|
4938
|
+
/** Whether a filter is switched on (the field defaults to enabled). */
|
|
4939
|
+
function isEnabled(filter) {
|
|
4940
|
+
return filter.enabled !== false;
|
|
4941
|
+
}
|
|
4942
|
+
/**
|
|
4943
|
+
* Validate a `YYYY-MM-DD` bound, returning its canonical text and UTC midnight,
|
|
4944
|
+
* or `null` when the text is blank, malformed, or not a real calendar day.
|
|
4945
|
+
*
|
|
4946
|
+
* The round-trip check is what rejects a day that does not exist: `Date.parse`
|
|
4947
|
+
* happily reads `2026-02-30` as March 2, so shape-checking alone would compile
|
|
4948
|
+
* a bound the user never chose. Rejecting here means a half-typed or impossible
|
|
4949
|
+
* bound compiles to no clause at all, leaving that side unconstrained rather
|
|
4950
|
+
* than filtering on a date nobody asked for.
|
|
4951
|
+
*/
|
|
4952
|
+
function parseIsoDayBound(day) {
|
|
4953
|
+
if (typeof day !== "string") return null;
|
|
4954
|
+
const trimmed = day.trim();
|
|
4955
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return null;
|
|
4956
|
+
const ms = Date.parse(`${trimmed}T00:00:00Z`);
|
|
4957
|
+
if (!Number.isFinite(ms)) return null;
|
|
4958
|
+
return new Date(ms).toISOString().slice(0, ISO_DAY_LENGTH) === trimmed ? {
|
|
4959
|
+
day: trimmed,
|
|
4960
|
+
ms
|
|
4961
|
+
} : null;
|
|
4962
|
+
}
|
|
4963
|
+
/** A finite number, or `null` for every other input (including `NaN`). */
|
|
4964
|
+
function finite(value) {
|
|
4965
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
4966
|
+
}
|
|
4967
|
+
/**
|
|
4968
|
+
* `["get", field]` coerced for comparison, guarded by `["has", field]` where a
|
|
4969
|
+
* missing property would otherwise coerce into range (`to-number` turns a
|
|
4970
|
+
* missing property into `0`, and `to-string` into `""`, either of which can sit
|
|
4971
|
+
* inside a one-sided bound).
|
|
4972
|
+
*/
|
|
4973
|
+
function presenceGuard(field) {
|
|
4974
|
+
return ["has", field];
|
|
4975
|
+
}
|
|
4976
|
+
function compileCategorical(filter) {
|
|
4977
|
+
const values = filter.values ?? [];
|
|
4978
|
+
if (values.length === 0) return null;
|
|
4979
|
+
return [
|
|
4980
|
+
"in",
|
|
4981
|
+
["get", filter.field],
|
|
4982
|
+
["literal", values]
|
|
4983
|
+
];
|
|
4984
|
+
}
|
|
4985
|
+
function compileRange(filter) {
|
|
4986
|
+
const first = finite(filter.min);
|
|
4987
|
+
const second = finite(filter.max);
|
|
4988
|
+
if (first === null && second === null) return null;
|
|
4989
|
+
const min = first !== null && second !== null ? Math.min(first, second) : first;
|
|
4990
|
+
const max = first !== null && second !== null ? Math.max(first, second) : second;
|
|
4991
|
+
const value = ["to-number", ["get", filter.field]];
|
|
4992
|
+
const clauses = [presenceGuard(filter.field)];
|
|
4993
|
+
if (min !== null) clauses.push([
|
|
4994
|
+
">=",
|
|
4995
|
+
value,
|
|
4996
|
+
min
|
|
4997
|
+
]);
|
|
4998
|
+
if (max !== null) clauses.push([
|
|
4999
|
+
"<=",
|
|
5000
|
+
value,
|
|
5001
|
+
max
|
|
5002
|
+
]);
|
|
5003
|
+
return ["all", ...clauses];
|
|
5004
|
+
}
|
|
5005
|
+
function compileDate(filter) {
|
|
5006
|
+
const first = parseIsoDayBound(filter.start);
|
|
5007
|
+
const second = parseIsoDayBound(filter.end);
|
|
5008
|
+
if (first === null && second === null) return null;
|
|
5009
|
+
const inverted = first !== null && second !== null && first.ms > second.ms;
|
|
5010
|
+
const start = inverted ? second : first;
|
|
5011
|
+
const end = inverted ? first : second;
|
|
5012
|
+
const clauses = [presenceGuard(filter.field)];
|
|
5013
|
+
if ((filter.dateKind ?? "iso") === "iso") {
|
|
5014
|
+
const value = [
|
|
5015
|
+
"slice",
|
|
5016
|
+
["to-string", ["get", filter.field]],
|
|
5017
|
+
0,
|
|
5018
|
+
ISO_DAY_LENGTH
|
|
5019
|
+
];
|
|
5020
|
+
if (start !== null) clauses.push([
|
|
5021
|
+
">=",
|
|
5022
|
+
value,
|
|
5023
|
+
start.day
|
|
5024
|
+
]);
|
|
5025
|
+
if (end !== null) clauses.push([
|
|
5026
|
+
"<=",
|
|
5027
|
+
value,
|
|
5028
|
+
end.day
|
|
5029
|
+
]);
|
|
5030
|
+
return ["all", ...clauses];
|
|
5031
|
+
}
|
|
5032
|
+
const scale = filter.dateKind === "epochS" ? .001 : 1;
|
|
5033
|
+
const value = ["to-number", ["get", filter.field]];
|
|
5034
|
+
if (start !== null) clauses.push([
|
|
5035
|
+
">=",
|
|
5036
|
+
value,
|
|
5037
|
+
start.ms * scale
|
|
5038
|
+
]);
|
|
5039
|
+
if (end !== null) clauses.push([
|
|
5040
|
+
"<",
|
|
5041
|
+
value,
|
|
5042
|
+
(end.ms + DAY_MS) * scale
|
|
5043
|
+
]);
|
|
5044
|
+
return ["all", ...clauses];
|
|
5045
|
+
}
|
|
5046
|
+
function compileText(filter) {
|
|
5047
|
+
const needle = filter.text?.trim().toLowerCase() ?? "";
|
|
5048
|
+
if (needle === "") return null;
|
|
5049
|
+
const haystack = ["downcase", ["to-string", ["get", filter.field]]];
|
|
5050
|
+
switch (filter.operator ?? "contains") {
|
|
5051
|
+
case "equals": return [
|
|
5052
|
+
"==",
|
|
5053
|
+
haystack,
|
|
5054
|
+
needle
|
|
5055
|
+
];
|
|
5056
|
+
case "startsWith": return [
|
|
5057
|
+
"==",
|
|
5058
|
+
[
|
|
5059
|
+
"index-of",
|
|
5060
|
+
needle,
|
|
5061
|
+
haystack
|
|
5062
|
+
],
|
|
5063
|
+
0
|
|
5064
|
+
];
|
|
5065
|
+
default: return [
|
|
5066
|
+
"!=",
|
|
5067
|
+
[
|
|
5068
|
+
"index-of",
|
|
5069
|
+
needle,
|
|
5070
|
+
haystack
|
|
5071
|
+
],
|
|
5072
|
+
-1
|
|
5073
|
+
];
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
/**
|
|
5077
|
+
* Compile one quick filter to a MapLibre filter expression, or `null` when it
|
|
5078
|
+
* places no constraint (switched off, no field, or nothing chosen yet). A
|
|
5079
|
+
* control that has been added but not yet answered must never hide features.
|
|
5080
|
+
*
|
|
5081
|
+
* @param filter - The persisted control state.
|
|
5082
|
+
* @returns A MapLibre filter expression, or `null`.
|
|
5083
|
+
*/
|
|
5084
|
+
function compileQuickFilter(filter) {
|
|
5085
|
+
if (!isEnabled(filter) || typeof filter.field !== "string" || filter.field === "") return null;
|
|
5086
|
+
switch (filter.kind) {
|
|
5087
|
+
case "categorical": return compileCategorical(filter);
|
|
5088
|
+
case "range": return compileRange(filter);
|
|
5089
|
+
case "date": return compileDate(filter);
|
|
5090
|
+
case "text": return compileText(filter);
|
|
5091
|
+
default: return null;
|
|
5092
|
+
}
|
|
5093
|
+
}
|
|
5094
|
+
/**
|
|
5095
|
+
* Compile a layer's quick filters into a single MapLibre filter expression.
|
|
5096
|
+
* Multiple controls narrow the data together (`["all", …]`), matching how a
|
|
5097
|
+
* viewer reads a stack of filters. Returns `null` when no control constrains
|
|
5098
|
+
* anything, so the common path adds no filter at all.
|
|
5099
|
+
*
|
|
5100
|
+
* @param filters - The layer's persisted quick filters.
|
|
5101
|
+
* @returns A MapLibre filter expression, or `null`.
|
|
5102
|
+
*/
|
|
5103
|
+
function compileQuickFilters(filters) {
|
|
5104
|
+
if (!filters || filters.length === 0) return null;
|
|
5105
|
+
const clauses = [];
|
|
5106
|
+
for (const filter of filters) {
|
|
5107
|
+
const compiled = compileQuickFilter(filter);
|
|
5108
|
+
if (compiled) clauses.push(compiled);
|
|
5109
|
+
}
|
|
5110
|
+
if (clauses.length === 0) return null;
|
|
5111
|
+
return clauses.length === 1 ? clauses[0] : ["all", ...clauses];
|
|
5112
|
+
}
|
|
5113
|
+
/**
|
|
5114
|
+
* The quick filters that actually constrain the layer right now. Drives the
|
|
5115
|
+
* "filtered" badge on the layer row and its count, so an active filter is
|
|
5116
|
+
* never mistaken for missing data.
|
|
5117
|
+
*
|
|
5118
|
+
* @param layer - The layer to inspect.
|
|
5119
|
+
* @returns The constraining filters, in their configured order.
|
|
5120
|
+
*/
|
|
5121
|
+
function activeQuickFilters(layer) {
|
|
5122
|
+
return (layer.quickFilters ?? []).filter((filter) => compileQuickFilter(filter) !== null);
|
|
5123
|
+
}
|
|
5124
|
+
/**
|
|
5125
|
+
* Whether the layer is currently narrowed by at least one quick filter.
|
|
5126
|
+
*
|
|
5127
|
+
* @param layer - The layer to inspect.
|
|
5128
|
+
* @returns `true` when a quick filter constrains the rendered features.
|
|
5129
|
+
*/
|
|
5130
|
+
function hasActiveQuickFilter(layer) {
|
|
5131
|
+
return (layer.quickFilters ?? []).some((filter) => compileQuickFilter(filter) !== null);
|
|
5132
|
+
}
|
|
5133
|
+
/**
|
|
5134
|
+
* Clear every chosen value while keeping the controls themselves, so "Clear
|
|
5135
|
+
* filters" is one action that leaves the layer's configured controls in place
|
|
5136
|
+
* for the next question.
|
|
5137
|
+
*
|
|
5138
|
+
* @param filters - The layer's persisted quick filters.
|
|
5139
|
+
* @returns The same controls with their selections emptied.
|
|
5140
|
+
*/
|
|
5141
|
+
function clearQuickFilterValues(filters) {
|
|
5142
|
+
return (filters ?? []).map((filter) => ({
|
|
5143
|
+
...filter,
|
|
5144
|
+
values: filter.kind === "categorical" ? [] : filter.values,
|
|
5145
|
+
min: filter.kind === "range" ? null : filter.min,
|
|
5146
|
+
max: filter.kind === "range" ? null : filter.max,
|
|
5147
|
+
start: filter.kind === "date" ? null : filter.start,
|
|
5148
|
+
end: filter.kind === "date" ? null : filter.end,
|
|
5149
|
+
text: filter.kind === "text" ? "" : filter.text
|
|
5150
|
+
}));
|
|
5151
|
+
}
|
|
5152
|
+
//#endregion
|
|
4607
5153
|
//#region src/capabilities.ts
|
|
4608
5154
|
/**
|
|
4609
5155
|
* Default inferred capabilities for a layer based on its type and metadata.
|
|
@@ -8373,7 +8919,8 @@ function captureLayerLibraryEntry(layer, options) {
|
|
|
8373
8919
|
...localPath ? { sourcePath: localPath } : {},
|
|
8374
8920
|
...layer.joins?.length ? { joins: structuredClone(layer.joins) } : {},
|
|
8375
8921
|
...layer.virtualFields?.length ? { virtualFields: structuredClone(layer.virtualFields) } : {},
|
|
8376
|
-
...layer.attributeForm ? { attributeForm: structuredClone(layer.attributeForm) } : {}
|
|
8922
|
+
...layer.attributeForm ? { attributeForm: structuredClone(layer.attributeForm) } : {},
|
|
8923
|
+
...layer.popup ? { popup: structuredClone(layer.popup) } : {}
|
|
8377
8924
|
};
|
|
8378
8925
|
const withFeatures = embed && !controlPainted ? {
|
|
8379
8926
|
...base,
|
|
@@ -8429,7 +8976,8 @@ function planLayerLibraryAdd(entry, options) {
|
|
|
8429
8976
|
...entry.geojson ? { geojson: structuredClone(entry.geojson) } : {},
|
|
8430
8977
|
...entry.joins ? { joins: structuredClone(entry.joins) } : {},
|
|
8431
8978
|
...entry.virtualFields ? { virtualFields: structuredClone(entry.virtualFields) } : {},
|
|
8432
|
-
...entry.attributeForm ? { attributeForm: structuredClone(entry.attributeForm) } : {}
|
|
8979
|
+
...entry.attributeForm ? { attributeForm: structuredClone(entry.attributeForm) } : {},
|
|
8980
|
+
...entry.popup ? { popup: structuredClone(entry.popup) } : {}
|
|
8433
8981
|
}
|
|
8434
8982
|
};
|
|
8435
8983
|
}
|
|
@@ -8447,7 +8995,8 @@ function layerLibraryConfigPatch(entry) {
|
|
|
8447
8995
|
opacity: entry.opacity,
|
|
8448
8996
|
...entry.joins ? { joins: structuredClone(entry.joins) } : {},
|
|
8449
8997
|
...entry.virtualFields ? { virtualFields: structuredClone(entry.virtualFields) } : {},
|
|
8450
|
-
...entry.attributeForm ? { attributeForm: structuredClone(entry.attributeForm) } : {}
|
|
8998
|
+
...entry.attributeForm ? { attributeForm: structuredClone(entry.attributeForm) } : {},
|
|
8999
|
+
...entry.popup ? { popup: structuredClone(entry.popup) } : {}
|
|
8451
9000
|
};
|
|
8452
9001
|
}
|
|
8453
9002
|
/**
|
|
@@ -8533,6 +9082,24 @@ function validAttributeForm(value) {
|
|
|
8533
9082
|
fields
|
|
8534
9083
|
});
|
|
8535
9084
|
}
|
|
9085
|
+
/**
|
|
9086
|
+
* A structurally plausible popup design, or undefined. `fields` is optional (a
|
|
9087
|
+
* config may carry only a title or the hover flag), so unlike the attribute
|
|
9088
|
+
* form an empty field list does not disqualify the block — but a config with
|
|
9089
|
+
* nothing set at all is dropped rather than stored as an empty object.
|
|
9090
|
+
*/
|
|
9091
|
+
function validPopup(value) {
|
|
9092
|
+
const config = plainObject(value);
|
|
9093
|
+
if (!config) return void 0;
|
|
9094
|
+
const fields = Array.isArray(config.fields) ? config.fields.filter((field) => plainObject(field) !== void 0 && nonEmptyString(field.field)) : void 0;
|
|
9095
|
+
const rest = { ...config };
|
|
9096
|
+
delete rest.fields;
|
|
9097
|
+
if (!fields?.length && Object.keys(rest).length === 0) return void 0;
|
|
9098
|
+
return structuredClone({
|
|
9099
|
+
...rest,
|
|
9100
|
+
...fields?.length ? { fields } : {}
|
|
9101
|
+
});
|
|
9102
|
+
}
|
|
8536
9103
|
/** An array of plain JSON objects, or undefined when nothing usable is present. */
|
|
8537
9104
|
function objectArray(value) {
|
|
8538
9105
|
if (!Array.isArray(value)) return void 0;
|
|
@@ -8598,10 +9165,12 @@ function normalizeLayerLibraryEntries(value) {
|
|
|
8598
9165
|
const joins = validJoins(candidate.joins);
|
|
8599
9166
|
const virtualFields = validVirtualFields(candidate.virtualFields);
|
|
8600
9167
|
const attributeForm = validAttributeForm(candidate.attributeForm);
|
|
9168
|
+
const popup = validPopup(candidate.popup);
|
|
8601
9169
|
return {
|
|
8602
9170
|
...joins ? { joins } : {},
|
|
8603
9171
|
...virtualFields ? { virtualFields } : {},
|
|
8604
|
-
...attributeForm ? { attributeForm } : {}
|
|
9172
|
+
...attributeForm ? { attributeForm } : {},
|
|
9173
|
+
...popup ? { popup } : {}
|
|
8605
9174
|
};
|
|
8606
9175
|
})(),
|
|
8607
9176
|
...geojson ? { geojson: structuredClone(geojson) } : {},
|
|
@@ -9729,6 +10298,7 @@ const useAppStore = create()(temporal((set, get) => ({
|
|
|
9729
10298
|
};
|
|
9730
10299
|
}),
|
|
9731
10300
|
setLayerAttributeForm: (id, attributeForm) => get().updateLayer(id, { attributeForm }),
|
|
10301
|
+
setLayerPopup: (id, popup) => get().updateLayer(id, { popup }),
|
|
9732
10302
|
setLayerEditorTracking: (id, editorTracking) => get().updateLayer(id, { editorTracking }),
|
|
9733
10303
|
setLayerVirtualFields: (id, fields) => set((s) => {
|
|
9734
10304
|
let layers = s.layers.map((l) => l.id === id ? applyJoinsToLayer(l, s.layers, void 0, fields) : l);
|
|
@@ -9738,6 +10308,7 @@ const useAppStore = create()(temporal((set, get) => ({
|
|
|
9738
10308
|
isDirty: true
|
|
9739
10309
|
};
|
|
9740
10310
|
}),
|
|
10311
|
+
setLayerQuickFilters: (id, filters) => get().updateLayer(id, { quickFilters: filters.length > 0 ? filters : void 0 }),
|
|
9741
10312
|
setLayerVisibility: (id, visible) => get().updateLayer(id, { visible }),
|
|
9742
10313
|
setLayerOpacity: (id, opacity) => get().updateLayer(id, { opacity }),
|
|
9743
10314
|
setLayerStyle: (id, style) => set((s) => ({
|
|
@@ -10853,12 +11424,14 @@ function parseCsvRows(text) {
|
|
|
10853
11424
|
const input = text.replace(/\r\n?/g, "\n");
|
|
10854
11425
|
for (let i = 0; i < input.length; i++) {
|
|
10855
11426
|
const ch = input[i];
|
|
10856
|
-
if (inQuotes)
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
11427
|
+
if (inQuotes) {
|
|
11428
|
+
if (ch === "\"") {
|
|
11429
|
+
if (input[i + 1] === "\"") {
|
|
11430
|
+
field += "\"";
|
|
11431
|
+
i++;
|
|
11432
|
+
} else inQuotes = false;
|
|
11433
|
+
} else field += ch;
|
|
11434
|
+
} else if (ch === "\"") inQuotes = true;
|
|
10862
11435
|
else if (ch === ",") {
|
|
10863
11436
|
row.push(field);
|
|
10864
11437
|
field = "";
|
|
@@ -12058,6 +12631,6 @@ function currentEditorIdentity() {
|
|
|
12058
12631
|
return pickEditorIdentity(isActive ? selfName : void 0, readStoredAuthorName());
|
|
12059
12632
|
}
|
|
12060
12633
|
//#endregion
|
|
12061
|
-
export { BLANK_BASEMAP, BLEND_MODES, BUILT_IN_STYLE_PRESETS, CARTOCIUDAD_MIN_INTERVAL_MS, CARTOCIUDAD_PUBLIC_HOST, CHINA_BASEMAPS, DEFAULT_BASEMAP, DEFAULT_BLEND_MODE, DEFAULT_COLLABORATION_STATE, DEFAULT_DASHBOARD_COLUMNS, DEFAULT_EDITOR_IDENTITY, DEFAULT_EDITOR_TRACKING_CONFIG, DEFAULT_ELLIPSOID_ID, DEFAULT_FORWARD_GEOCODE_ENDPOINT, DEFAULT_GEOCODING_PROVIDER_ID, DEFAULT_LAYER_GROUP_OPACITY, DEFAULT_LAYER_STYLE, DEFAULT_LEGEND_CONFIG, DEFAULT_MAP_GRID_LAYOUT, DEFAULT_PRINT_LAYOUT, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_PREFERENCES, DEFAULT_REVERSE_GEOCODE_ENDPOINT, DEFAULT_ROUTING_ENDPOINT, DEFAULT_STORY_MAP, DUCKDB_VECTOR_FEATURE_WARN_COUNT, DUCKDB_VECTOR_ROUTE_BYTES, EARTH_MEAN_RADIUS_METERS, EDITOR_IDENTITY_STORAGE_KEY, ELEVATION_REQUEST_TIMEOUT_MS, ELLIPSOIDS, EXPRESSION_FUNCTION_CATEGORIES, ElevationFetchError, FEET_PER_METER, FEET_PER_MILE, GEOCODE_DISPLAY_NAME_KEY, GEOCODE_LAT_KEY, GEOCODE_LON_KEY, GEOCODE_PROVIDER_KEY, GEOCODE_SCORE_KEY, GEOCODE_STATUS_KEY, GEOCODING_PROVIDERS, GOOGLE_MAPS_API_KEY_HEADER, LARGE_VECTOR_FEATURE_THRESHOLD, LAYER_LIBRARY_BUNDLE_TYPE, LAYER_LIBRARY_BUNDLE_VERSION, LAYER_PALETTE, LAYER_TYPES, MAX_DASHBOARD_COLUMNS, MAX_DIAGRAM_FEATURES, MAX_DIAGRAM_SCAN_FEATURES, MAX_LAYER_LIBRARY_ENTRIES, MAX_LAYER_LIBRARY_ENTRY_BYTES, MAX_MAP_GRID_DIM, MAX_POINTS_PER_REQUEST, MAX_PROCESSING_HISTORY, MAX_REDACT_DEPTH, MERCATOR_METERS_PER_PIXEL_AT_ZOOM_0, METERS_PER_FOOT, METERS_PER_MILE, METERS_PER_NAUTICAL_MILE, MIN_DASHBOARD_COLUMNS, MIN_DIAGRAM_SIZE, NETCDF_IMAGE_SOURCE_KIND, NOMINATIM_MIN_INTERVAL_MS, NOMINATIM_PUBLIC_HOST, OPENFREEMAP_BASEMAPS, PHOTO_FULL_PROPERTY, PHOTO_PROPERTY, PLANETARY_BASEMAPS, PLANETARY_BASEMAP_GROUPS, PLANETARY_BASEMAP_SENTINEL_PREFIX, PLANET_SWITCHER_OPTIONS, POINTER_ELEVATION_CACHE_LIMIT, POINTER_ELEVATION_DEBOUNCE_MS, PROJECT_CREDENTIAL_FIELDS, PROJECT_VERSION, PROTOMAPS_BASEMAPS, PUBLIC_GEOCODE_ROW_CAP, PUBLISHABLE_PLUGIN_SETTINGS, RAMP_STYLE_KEYS, RASTER_APPEARANCE_STATE_KEYS, REGIONAL_BASEMAPS, REGIONAL_BASEMAP_GROUPS, REGIONAL_BASEMAP_SENTINEL_PREFIX, RoutingRequestError, SELECTION_MODES, SQL_QUERY_SOURCE_KIND, STYLE_LIBRARY_BUNDLE_TYPE, STYLE_LIBRARY_BUNDLE_VERSION, SYMBOL_STYLE_KEYS, VECTOR_COLOR_RAMPS, applyCopiedLayerStyle, applyGroupEffects, applyJoinsToLayer, applyLayerJoins, applyLayerVirtualFields, applyMatchedSelection, applyProjectToStore, applySelectionMode, attributeFormFieldLabel, attributeLinkUrl, batchDecodePolylines, bodyLengthToEarth, buildForwardGeocodeUrl, buildIsochroneRequest, buildLayerPanelUnits, buildLayerTree, buildMatrixRequest, buildReverseGeocodeUrl, buildRouteRequest, canRedoProjectRestore, canSaveLayerToLibrary, canUndoProjectRestore, captureLayerLibraryEntry, cascadeLayerJoinRefresh, circleRadiusValue, clearExternalNativePaintBridge, clearHistory, coerceAttributeFormValue, collectDiagramData, collectTransitiveJoinSourceIds, compareSequenceValues, compileFeatureExpression, controlRendersLayer, copyableLayerStyleKind, createDefaultMapView, createDefaultPrintLayout, createEmptyProject, createEqualIntervalBreaks, createGraduatedClassBreaks, createLayerLibraryEntryId, createPointerElevationResolver, createProjectTemplate, createQuantileBreaks, createSampleStoryMap, createStyleLibraryEntryId, csvRowsToGeocodeRequests, currentEditorIdentity, darkenHex, decodePolyline, decodePolylineDetailed, detachProjectCopy, detectNonGeographicCoordinates, diagramAnchor, diagramPixelSize, diagramsSuppressedByPointRenderer, dominantGeometry, drawMarkerPath, earthAreaToBody, earthLengthToBody, editorTrackingFieldNames, effectiveLayerRenderState, effectiveVectorRules, encodePolyline, ensureEditorTrackingFields, evaluateMapExpression, excludeHiddenFieldsFromGeojson, excludeHiddenFieldsFromProject, extractCopiedLayerStyle, extractStyleLibraryStyle, extrusionColorValue, extrusionHeightValue, featureSelectionId, fetchElevations, formatCameraAltitude, formatExpressionPreviewValue, formatRoundNum, generatorCircleRadiusValue, generatorSizeRange, geoJSONToPolylineStr, geocodeForward, geocodeMatchToFeature, geocodeReverse, geocoderMinIntervalMs, geocoderNeedsApiKey, geojsonHasZCoordinates, getActiveBodyRadiusRatio, getActiveEllipsoid, getActiveMeanRadiusMeters, getActiveSemiMajorAxisMeters, getAttributeFormField, getCesiumIonToken, getEllipsoid, getExternalNativePaintBridge, getGeocoderConfig, getGeocodingProvider, getGoogleMapsApiKey, getHistoryCoalesceMs, getMapboxAccessToken, getMaxHistoryFeatureCount, getPlanetaryBasemapById, getPlanetaryBasemapByStyleUrl, getProtomapsApiKey, getProtomapsStyleUrl, getRegionalBasemapById, getRegionalBasemapByStyleUrl, getRoundNum, getRoutingConfig, getRuntimeEnvironment, getSpatialExtensionPath, getVectorColorRamp, googleMapsApiKeyHeaderValue, groupMemberIndices, hasPathTraversal, hasRestorableLayerSource, hasSimpleStyleProperties, inferFieldTypes, inferLayerCapabilities, initialLayerStyle, interpolateColors, interpolateHexColor, interpolateRampColors, invertSelection, isAbsoluteFilesystemPath, isAllowedPluginManifestUrl, isAttributeFormFieldVisible, isCredentialFieldName, isDefaultPrintLayout, isDiagramStyleEnabled, isDuckDBQueryLayer, isExternalNativeLayerRecord, isGooglePhotorealisticTilesetUrl, isHexColor, isInitialLayerStyle, isIpadDesktopUserAgent, isMaintainedEditorTrackingField, isRegionalBasemapSentinel, isStyleLibraryTargetLayer, isStyleSpecColor, isVectorColorExpression, isochroneResponseToFeatures, layerGroupDepth, layerGroupMoveability, layerJoinKey, layerLibraryConfigPatch, layerLibraryEntryNeedsLocalFile, layerPanelGroupHeaders, lineWidthValue, mapZoomStepOutputs, matchFeaturesByExpression, matrixResponseToFeatures, meanRadiusMeters, mercatorMetersPerPixelAtZoom0, metersWidthExpression, nextDelayMs, nextLayerPaletteColor, nominatimResultToFeature, nominatimReverseResultToDisplay, nonEmptyRecord, normalizeDashboardColumns, normalizeGeocodingProviderId, normalizeGroupContiguity, normalizeHexColor, normalizeLayerCapabilities, normalizeLayerLibraryEntries, normalizeMapLayout, normalizeMapViewState, normalizeModelGraph, normalizeModels, normalizePrintLayoutConfig, normalizeProcessingHistory, normalizeProjectComments, normalizeSecondaryMapViews, normalizeStoryMap, normalizeStyleLibraryEntries, normalizeWidgets, parseContours, parseHexColor, parseHexColorList, parseJsonExpression, parseLayerLibrary, parseProject, parseStoryMapCsv, parseStoryMapJson, parseStyleLibrary, parseValueMapText, persistedThreeDTilesRequestHeaders, pickEditorIdentity, planLayerLibraryAdd, pluginOwnsPaint, polylineStrToGeoJSON, printLayoutConfigsEqual, projectFromStore, projectPathLabel, proportionalRadiusExpression, proportionalSizeRange, readStoredAuthorName, reapplyLayerJoins, redactCredentials, redactProjectCredentials, redactUrlCredentials, redo, registerProjectRestoreHistory, removeTrailingJsonCommas, reorderLayerGroupInPanel, requestIsochrone, requestMatrix, requestRoute, resolveEditorTrackingConfig, resolveGeocoderConfig, resolveLayerCapabilities, resolveMapGrid, resolveSvgSource, resolveThreeDTilesRequestHeaders, rgbToHex, routeResponseToFeatures, rowCap, ruleBasedColorExpression, ruleBasedVisibilityFilter, sampleMapTerrain, sampleMapTerrainPoint, sampleRemoteElevations, sanitizeLayerStylePatch, scaleAltitudeToActiveBody, scaleDenomination, scaleSpan, scrubCommentsForRemovedLayers, scrubLegendForRemovedLayers, scrubPrintLayoutForLayers, scrubPrintLayoutForRemovedLayers, scrubWidgetsForRemovedLayers, serializeLayerLibrary, serializeProject, serializeStoryMapCsv, serializeStoryMapJson, serializeStyleLibrary, setActiveEllipsoidId, setExternalNativePaintBridge, setGeocodingFetch, setHistoryCoalesceMs, setMaxHistoryFeatureCount, setStoredAuthorName, shouldThrottle, shouldUseTiledRendering, simpleStyleNumberValue, stampFeatureCollectionEditorTracking, stampFeatureEditorTracking, stampFeaturePropertiesEditorTracking, storyMapHasContent, stripGoogleMapsApiKeyHeader, stripJoinFields, stripVirtualFieldColumns, styleValue, subscribeProjectRestoreHistory, substituteExpressionVariables, supportsBridgedOpacity, transformGeojsonElevation, trimHistoryBySize, undo, unescapePolyline, unmatchedGeocodeFeature, unresolvedLayerLibraryJoins, useAppStore, validateAttributeFormField, validateAttributeFormValues, validateMapExpression, valueMapLabelFor, valueMapToText, vectorCircleColorValue, vectorColorExpression, vectorFillColorValue, vectorFillOpacityValue, vectorLineColorValue, vectorOutlineColorValue, vectorStrokeWidthValue };
|
|
12634
|
+
export { BLANK_BASEMAP, BLEND_MODES, BUILT_IN_STYLE_PRESETS, CARTOCIUDAD_MIN_INTERVAL_MS, CARTOCIUDAD_PUBLIC_HOST, CHINA_BASEMAPS, DEFAULT_BASEMAP, DEFAULT_BLEND_MODE, DEFAULT_COLLABORATION_STATE, DEFAULT_DASHBOARD_COLUMNS, DEFAULT_EDITOR_IDENTITY, DEFAULT_EDITOR_TRACKING_CONFIG, DEFAULT_ELLIPSOID_ID, DEFAULT_FORWARD_GEOCODE_ENDPOINT, DEFAULT_GEOCODING_PROVIDER_ID, DEFAULT_LAYER_GROUP_OPACITY, DEFAULT_LAYER_STYLE, DEFAULT_LEGEND_CONFIG, DEFAULT_MAP_GRID_LAYOUT, DEFAULT_PRINT_LAYOUT, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_PREFERENCES, DEFAULT_REVERSE_GEOCODE_ENDPOINT, DEFAULT_ROUTING_ENDPOINT, DEFAULT_STORY_MAP, DUCKDB_VECTOR_FEATURE_WARN_COUNT, DUCKDB_VECTOR_ROUTE_BYTES, EARTH_MEAN_RADIUS_METERS, EDITOR_IDENTITY_STORAGE_KEY, ELEVATION_REQUEST_TIMEOUT_MS, ELLIPSOIDS, EXPRESSION_FUNCTION_CATEGORIES, ElevationFetchError, FEET_PER_METER, FEET_PER_MILE, GEOCODE_DISPLAY_NAME_KEY, GEOCODE_LAT_KEY, GEOCODE_LON_KEY, GEOCODE_PROVIDER_KEY, GEOCODE_SCORE_KEY, GEOCODE_STATUS_KEY, GEOCODING_PROVIDERS, GOOGLE_MAPS_API_KEY_HEADER, LARGE_VECTOR_FEATURE_THRESHOLD, LAYER_LIBRARY_BUNDLE_TYPE, LAYER_LIBRARY_BUNDLE_VERSION, LAYER_PALETTE, LAYER_TYPES, MAX_DASHBOARD_COLUMNS, MAX_DIAGRAM_FEATURES, MAX_DIAGRAM_SCAN_FEATURES, MAX_LAYER_LIBRARY_ENTRIES, MAX_LAYER_LIBRARY_ENTRY_BYTES, MAX_MAP_GRID_DIM, MAX_POINTS_PER_REQUEST, MAX_PROCESSING_HISTORY, MAX_REDACT_DEPTH, MERCATOR_METERS_PER_PIXEL_AT_ZOOM_0, METERS_PER_FOOT, METERS_PER_MILE, METERS_PER_NAUTICAL_MILE, MIN_DASHBOARD_COLUMNS, MIN_DIAGRAM_SIZE, NETCDF_IMAGE_SOURCE_KIND, NOMINATIM_MIN_INTERVAL_MS, NOMINATIM_PUBLIC_HOST, OPENFREEMAP_BASEMAPS, PHOTO_FULL_PROPERTY, PHOTO_PROPERTY, PLANETARY_BASEMAPS, PLANETARY_BASEMAP_GROUPS, PLANETARY_BASEMAP_SENTINEL_PREFIX, PLANET_SWITCHER_OPTIONS, POINTER_ELEVATION_CACHE_LIMIT, POINTER_ELEVATION_DEBOUNCE_MS, PROJECT_CREDENTIAL_FIELDS, PROJECT_VERSION, PROTOMAPS_BASEMAPS, PUBLIC_GEOCODE_ROW_CAP, PUBLISHABLE_PLUGIN_SETTINGS, RAMP_STYLE_KEYS, RASTER_APPEARANCE_STATE_KEYS, REGIONAL_BASEMAPS, REGIONAL_BASEMAP_GROUPS, REGIONAL_BASEMAP_SENTINEL_PREFIX, RoutingRequestError, SELECTION_MODES, SQL_QUERY_SOURCE_KIND, STYLE_LIBRARY_BUNDLE_TYPE, STYLE_LIBRARY_BUNDLE_VERSION, SYMBOL_STYLE_KEYS, VECTOR_COLOR_RAMPS, activeQuickFilters, applyCopiedLayerStyle, applyGroupEffects, applyJoinsToLayer, applyLayerJoins, applyLayerVirtualFields, applyMatchedSelection, applyProjectToStore, applySelectionMode, attributeFormFieldLabel, attributeLinkUrl, batchDecodePolylines, bodyLengthToEarth, buildForwardGeocodeUrl, buildIsochroneRequest, buildLayerPanelUnits, buildLayerTree, buildMatrixRequest, buildReverseGeocodeUrl, buildRouteRequest, canRedoProjectRestore, canSaveLayerToLibrary, canUndoProjectRestore, captureLayerLibraryEntry, cascadeLayerJoinRefresh, circleRadiusValue, clearExternalNativePaintBridge, clearHistory, clearQuickFilterValues, coerceAttributeFormValue, collectDiagramData, collectTransitiveJoinSourceIds, compareSequenceValues, compileFeatureExpression, compileQuickFilter, compileQuickFilters, controlRendersLayer, copyableLayerStyleKind, createDefaultMapView, createDefaultPrintLayout, createEmptyProject, createEqualIntervalBreaks, createGraduatedClassBreaks, createLayerLibraryEntryId, createPointerElevationResolver, createProjectTemplate, createQuantileBreaks, createSampleStoryMap, createStyleLibraryEntryId, csvRowsToGeocodeRequests, currentEditorIdentity, darkenHex, decodePolyline, decodePolylineDetailed, detachProjectCopy, detectNonGeographicCoordinates, diagramAnchor, diagramPixelSize, diagramsSuppressedByPointRenderer, dominantGeometry, drawMarkerPath, earthAreaToBody, earthLengthToBody, editorTrackingFieldNames, effectiveLayerRenderState, effectiveVectorRules, encodePolyline, ensureEditorTrackingFields, evaluateMapExpression, excludeHiddenFieldsFromGeojson, excludeHiddenFieldsFromProject, extractCopiedLayerStyle, extractStyleLibraryStyle, extrusionColorValue, extrusionHeightValue, featureSelectionId, fetchElevations, formatCameraAltitude, formatExpressionPreviewValue, formatPopupValue, formatRoundNum, generatorCircleRadiusValue, generatorSizeRange, geoJSONToPolylineStr, geocodeForward, geocodeMatchToFeature, geocodeReverse, geocoderMinIntervalMs, geocoderNeedsApiKey, geojsonHasZCoordinates, getActiveBodyRadiusRatio, getActiveEllipsoid, getActiveMeanRadiusMeters, getActiveSemiMajorAxisMeters, getAttributeFormField, getBuildEnvironment, getCesiumIonToken, getEllipsoid, getExternalNativePaintBridge, getGeocoderConfig, getGeocodingProvider, getGoogleMapsApiKey, getHistoryCoalesceMs, getMapboxAccessToken, getMaxHistoryFeatureCount, getPlanetaryBasemapById, getPlanetaryBasemapByStyleUrl, getProtomapsApiKey, getProtomapsStyleUrl, getRegionalBasemapById, getRegionalBasemapByStyleUrl, getRoundNum, getRoutingConfig, getRuntimeEnvironment, getSpatialExtensionPath, getVectorColorRamp, googleMapsApiKeyHeaderValue, groupMemberIndices, hasActiveQuickFilter, hasPathTraversal, hasRestorableLayerSource, hasSimpleStyleProperties, inferFieldTypes, inferLayerCapabilities, initialLayerStyle, interpolateColors, interpolateHexColor, interpolateRampColors, invertSelection, isAbsoluteFilesystemPath, isAllowedPluginManifestUrl, isAttributeFormFieldVisible, isCredentialFieldName, isDefaultPrintLayout, isDiagramStyleEnabled, isDuckDBQueryLayer, isExternalNativeLayerRecord, isGooglePhotorealisticTilesetUrl, isHexColor, isInitialLayerStyle, isInlineImageValue, isInternalPopupField, isIpadDesktopUserAgent, isMaintainedEditorTrackingField, isPopupClickEnabled, isPopupHoverEnabled, isRegionalBasemapSentinel, isSafePopupUrl, isStyleLibraryTargetLayer, isStyleSpecColor, isVectorColorExpression, isochroneResponseToFeatures, layerGroupDepth, layerGroupMoveability, layerJoinKey, layerLibraryConfigPatch, layerLibraryEntryNeedsLocalFile, layerPanelGroupHeaders, lineWidthValue, mapZoomStepOutputs, matchFeaturesByExpression, matrixResponseToFeatures, meanRadiusMeters, mercatorMetersPerPixelAtZoom0, metersWidthExpression, nextDelayMs, nextLayerPaletteColor, nominatimResultToFeature, nominatimReverseResultToDisplay, nonEmptyRecord, normalizeDashboardColumns, normalizeGeocodingProviderId, normalizeGroupContiguity, normalizeHexColor, normalizeLayerCapabilities, normalizeLayerLibraryEntries, normalizeMapLayout, normalizeMapViewState, normalizeModelGraph, normalizeModels, normalizePrintLayoutConfig, normalizeProcessingHistory, normalizeProjectComments, normalizeSecondaryMapViews, normalizeStoryMap, normalizeStyleLibraryEntries, normalizeWidgets, parseContours, parseHexColor, parseHexColorList, parseJsonExpression, parseLayerLibrary, parseProject, parseStoryMapCsv, parseStoryMapJson, parseStyleLibrary, parseValueMapText, persistedThreeDTilesRequestHeaders, pickEditorIdentity, planLayerLibraryAdd, pluginOwnsPaint, polylineStrToGeoJSON, popupFieldLabel, printLayoutConfigsEqual, projectFromStore, projectPathLabel, proportionalRadiusExpression, proportionalSizeRange, readStoredAuthorName, reapplyLayerJoins, redactCredentials, redactProjectCredentials, redactUrlCredentials, redo, registerProjectRestoreHistory, removeTrailingJsonCommas, reorderLayerGroupInPanel, requestIsochrone, requestMatrix, requestRoute, resolveConfiguredPopupTitle, resolveEditorTrackingConfig, resolveGeocoderConfig, resolveLayerCapabilities, resolveMapGrid, resolvePopupBody, resolvePopupRows, resolvePopupTitle, resolveSvgSource, resolveThreeDTilesRequestHeaders, rgbToHex, routeResponseToFeatures, rowCap, ruleBasedColorExpression, ruleBasedVisibilityFilter, sampleMapTerrain, sampleMapTerrainPoint, sampleRemoteElevations, sanitizeLayerStylePatch, scaleAltitudeToActiveBody, scaleDenomination, scaleSpan, scrubCommentsForRemovedLayers, scrubLegendForRemovedLayers, scrubPrintLayoutForLayers, scrubPrintLayoutForRemovedLayers, scrubWidgetsForRemovedLayers, serializeLayerLibrary, serializeProject, serializeStoryMapCsv, serializeStoryMapJson, serializeStyleLibrary, setActiveEllipsoidId, setExternalNativePaintBridge, setGeocodingFetch, setHistoryCoalesceMs, setMaxHistoryFeatureCount, setStoredAuthorName, shouldThrottle, shouldUseTiledRendering, simpleStyleNumberValue, stampFeatureCollectionEditorTracking, stampFeatureEditorTracking, stampFeaturePropertiesEditorTracking, storyMapHasContent, stringifyPopupValue, stripGoogleMapsApiKeyHeader, stripJoinFields, stripVirtualFieldColumns, styleValue, subscribeProjectRestoreHistory, substituteExpressionVariables, supportsBridgedOpacity, transformGeojsonElevation, trimHistoryBySize, undo, unescapePolyline, unmatchedGeocodeFeature, unresolvedLayerLibraryJoins, useAppStore, validateAttributeFormField, validateAttributeFormValues, validateMapExpression, valueMapLabelFor, valueMapToText, vectorCircleColorValue, vectorColorExpression, vectorFillColorValue, vectorFillOpacityValue, vectorLineColorValue, vectorOutlineColorValue, vectorStrokeWidthValue, visiblePopupFields, visiblePopupProperties };
|
|
12062
12635
|
|
|
12063
12636
|
//# sourceMappingURL=index.mjs.map
|