@guardian/interactive-component-library 0.1.0-alpha.58 → 0.1.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.
|
@@ -6180,174 +6180,103 @@
|
|
|
6180
6180
|
)
|
|
6181
6181
|
] });
|
|
6182
6182
|
}
|
|
6183
|
-
class
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6183
|
+
class Feature {
|
|
6184
|
+
/**
|
|
6185
|
+
* Represents a feature on the map
|
|
6186
|
+
* @constructor
|
|
6187
|
+
* @param {Object} props - The properties for the feature.
|
|
6188
|
+
* @property {string} id - The unique identifier of the feature
|
|
6189
|
+
* @property {Array} geometries - The geometries of the feature
|
|
6190
|
+
* @property {Object} properties - The properties of the feature
|
|
6191
|
+
* @property {import("./styles").Style | import("./styles").StyleFunction} style - The style of the feature
|
|
6192
|
+
*/
|
|
6193
|
+
constructor({ id: id2, geometries, properties, style: style2 }) {
|
|
6194
|
+
this.id = id2;
|
|
6195
|
+
this.geometries = geometries;
|
|
6196
|
+
this.properties = properties;
|
|
6188
6197
|
this.style = style2;
|
|
6198
|
+
this.uid = createUid();
|
|
6189
6199
|
}
|
|
6190
|
-
|
|
6191
|
-
if (
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
this.
|
|
6197
|
-
|
|
6198
|
-
const geometries = feature.getProjectedGeometries(projection);
|
|
6199
|
-
if (frameState.debug) {
|
|
6200
|
-
try {
|
|
6201
|
-
validateGeometries(geometries);
|
|
6202
|
-
} catch {
|
|
6203
|
-
console.error(
|
|
6204
|
-
`Invalid geometry. Feature skipped during rendering. Click here to inspect geometry: ${generateDebugUrl(feature)}
|
|
6205
|
-
`,
|
|
6206
|
-
feature
|
|
6207
|
-
);
|
|
6208
|
-
}
|
|
6209
|
-
}
|
|
6210
|
-
for (const geometry of geometries) {
|
|
6211
|
-
this.drawingFunction(geometry);
|
|
6212
|
-
}
|
|
6213
|
-
if (fill) {
|
|
6214
|
-
context.fillStyle = fill.getRgba();
|
|
6215
|
-
context.fill();
|
|
6216
|
-
}
|
|
6217
|
-
if (stroke) {
|
|
6218
|
-
context.lineWidth = stroke.width * pixelRatio / transform.k;
|
|
6219
|
-
context.strokeStyle = stroke.getRgba();
|
|
6220
|
-
context.stroke();
|
|
6221
|
-
}
|
|
6222
|
-
}
|
|
6223
|
-
}
|
|
6224
|
-
const textPadding = {
|
|
6225
|
-
top: 20,
|
|
6226
|
-
right: 20,
|
|
6227
|
-
bottom: 20,
|
|
6228
|
-
left: 20
|
|
6229
|
-
};
|
|
6230
|
-
class TextLayerRenderer {
|
|
6231
|
-
constructor(layer) {
|
|
6232
|
-
this.layer = layer;
|
|
6233
|
-
this.featureRenderer = new FeatureRenderer();
|
|
6234
|
-
this._element = document.createElement("div");
|
|
6235
|
-
this._element.className = "gv-text-layer";
|
|
6236
|
-
const style2 = this._element.style;
|
|
6237
|
-
style2.position = "absolute";
|
|
6238
|
-
style2.width = "100%";
|
|
6239
|
-
style2.height = "100%";
|
|
6240
|
-
style2.pointerEvents = "none";
|
|
6241
|
-
style2.overflow = "hidden";
|
|
6200
|
+
getExtent() {
|
|
6201
|
+
if (this._extent) return this._extent;
|
|
6202
|
+
const extent = this.geometries.reduce((combinedExtent, geometries) => {
|
|
6203
|
+
if (!combinedExtent) return geometries.extent;
|
|
6204
|
+
return combineExtents(geometries.extent, combinedExtent);
|
|
6205
|
+
}, null);
|
|
6206
|
+
this._extent = extent;
|
|
6207
|
+
return extent;
|
|
6242
6208
|
}
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
const { projection, viewPortSize, sizeInPixels, visibleExtent, transform } = frameState.viewState;
|
|
6247
|
-
this._element.style.opacity = this.layer.opacity;
|
|
6248
|
-
const source = this.layer.source;
|
|
6249
|
-
const features = source.getFeaturesInExtent(visibleExtent);
|
|
6250
|
-
const textElements = [];
|
|
6251
|
-
for (const feature of features) {
|
|
6252
|
-
const geometries = feature.getProjectedGeometries(projection);
|
|
6253
|
-
const point = geometries.find((d2) => d2.type === "Point");
|
|
6254
|
-
if (!point) {
|
|
6255
|
-
throw new Error(
|
|
6256
|
-
`Expected Point geometry for feature in TextLayer: ${feature}`
|
|
6257
|
-
);
|
|
6258
|
-
}
|
|
6259
|
-
const styleFunction2 = feature.getStyleFunction() || this.layer.getStyleFunction();
|
|
6260
|
-
const featureStyle = styleFunction2(feature);
|
|
6261
|
-
const textElement = this.getTextElementWithID(feature.uid);
|
|
6262
|
-
textElement.innerText = featureStyle.text.content;
|
|
6263
|
-
const [relativeX, relativeY] = transform.apply(point.coordinates).map((d2, i) => d2 / sizeInPixels[i]);
|
|
6264
|
-
const position = {
|
|
6265
|
-
left: `${relativeX * 100}%`,
|
|
6266
|
-
top: `${relativeY * 100}%`
|
|
6267
|
-
};
|
|
6268
|
-
this.styleTextElement(textElement, featureStyle.text, position);
|
|
6269
|
-
const bbox = this.getElementBBox(textElement, {
|
|
6270
|
-
x: relativeX * viewPortSize[0],
|
|
6271
|
-
y: relativeY * viewPortSize[1]
|
|
6272
|
-
});
|
|
6273
|
-
if (declutterTree.collides(bbox)) {
|
|
6274
|
-
continue;
|
|
6275
|
-
}
|
|
6276
|
-
declutterTree.insert(bbox);
|
|
6277
|
-
if (this.layer.drawCollisionBoxes) {
|
|
6278
|
-
const collisionBoxDebugElement = this.getCollisionBoxElement(bbox);
|
|
6279
|
-
textElements.push(collisionBoxDebugElement);
|
|
6280
|
-
}
|
|
6281
|
-
textElements.push(textElement);
|
|
6282
|
-
}
|
|
6283
|
-
replaceChildren(this._element, textElements);
|
|
6284
|
-
return this._element;
|
|
6209
|
+
setgeometries(geometries) {
|
|
6210
|
+
this.geometries = geometries;
|
|
6211
|
+
this._extent = void 0;
|
|
6285
6212
|
}
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
textElement = document.createElement("div");
|
|
6291
|
-
textElement.id = elementId;
|
|
6292
|
-
}
|
|
6293
|
-
return textElement;
|
|
6213
|
+
getProjectedGeometries(projection) {
|
|
6214
|
+
return this.geometries.map(
|
|
6215
|
+
(d2) => d2.getProjected(projection, projection.revision)
|
|
6216
|
+
);
|
|
6294
6217
|
}
|
|
6295
|
-
|
|
6296
|
-
const style2 =
|
|
6297
|
-
style2
|
|
6298
|
-
style2
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
style2.whiteSpace = "nowrap";
|
|
6303
|
-
style2.fontFamily = textStyle.fontFamily;
|
|
6304
|
-
style2.fontSize = textStyle.fontSize;
|
|
6305
|
-
style2.fontWeight = textStyle.fontWeight;
|
|
6306
|
-
style2.lineHeight = textStyle.lineHeight;
|
|
6307
|
-
style2.color = textStyle.color;
|
|
6308
|
-
style2.textShadow = textStyle.textShadow;
|
|
6309
|
-
style2.padding = `${textPadding.top}px ${textPadding.right}px ${textPadding.bottom}px ${textPadding.left}px`;
|
|
6218
|
+
getStyleFunction() {
|
|
6219
|
+
const style2 = this.style;
|
|
6220
|
+
if (!style2) return null;
|
|
6221
|
+
if (typeof style2 === "function") return style2;
|
|
6222
|
+
return () => {
|
|
6223
|
+
return style2;
|
|
6224
|
+
};
|
|
6310
6225
|
}
|
|
6311
|
-
|
|
6312
|
-
if (!
|
|
6313
|
-
|
|
6226
|
+
containsCoordinate(coordinate) {
|
|
6227
|
+
if (!containsCoordinate(this.getExtent(), coordinate)) {
|
|
6228
|
+
return false;
|
|
6314
6229
|
}
|
|
6315
|
-
const
|
|
6316
|
-
|
|
6317
|
-
|
|
6230
|
+
for (const geometries of this.geometries) {
|
|
6231
|
+
if (d3Geo.geoContains(geometries.getGeoJSON(), coordinate)) {
|
|
6232
|
+
return true;
|
|
6233
|
+
}
|
|
6318
6234
|
}
|
|
6319
|
-
return
|
|
6320
|
-
minX: Math.floor(position.x) - width / 2,
|
|
6321
|
-
minY: Math.floor(position.y) - height / 2,
|
|
6322
|
-
maxX: Math.ceil(position.x + width / 2),
|
|
6323
|
-
maxY: Math.ceil(position.y + height / 2)
|
|
6324
|
-
};
|
|
6325
|
-
}
|
|
6326
|
-
getCollisionBoxElement(bbox) {
|
|
6327
|
-
const element = document.createElement("div");
|
|
6328
|
-
const style2 = element.style;
|
|
6329
|
-
style2.position = "absolute";
|
|
6330
|
-
style2.left = `${bbox.minX}px`;
|
|
6331
|
-
style2.top = `${bbox.minY}px`;
|
|
6332
|
-
style2.width = `${bbox.maxX - bbox.minX}px`;
|
|
6333
|
-
style2.height = `${bbox.maxY - bbox.minY}px`;
|
|
6334
|
-
style2.border = "2px solid black";
|
|
6335
|
-
return element;
|
|
6336
|
-
}
|
|
6337
|
-
}
|
|
6338
|
-
class Style {
|
|
6339
|
-
constructor(properties) {
|
|
6340
|
-
this.stroke = properties == null ? void 0 : properties.stroke;
|
|
6341
|
-
this.fill = properties == null ? void 0 : properties.fill;
|
|
6342
|
-
this.text = properties == null ? void 0 : properties.text;
|
|
6235
|
+
return false;
|
|
6343
6236
|
}
|
|
6344
6237
|
clone() {
|
|
6345
|
-
return new
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6238
|
+
return new Feature({
|
|
6239
|
+
id: this.id,
|
|
6240
|
+
geometries: this.geometries.map((d2) => d2.clone()),
|
|
6241
|
+
properties: this.properties,
|
|
6242
|
+
style: this.style
|
|
6349
6243
|
});
|
|
6350
6244
|
}
|
|
6245
|
+
/**
|
|
6246
|
+
* Returns the geometries as a GeoJSON object
|
|
6247
|
+
* @returns {Object} The GeoJSON representation of the geometries
|
|
6248
|
+
*/
|
|
6249
|
+
getGeoJSON() {
|
|
6250
|
+
const geometries = this.geometries.map((d2) => d2.getGeoJSON());
|
|
6251
|
+
if (geometries.length === 1) return geometries[0];
|
|
6252
|
+
return {
|
|
6253
|
+
type: "Feature",
|
|
6254
|
+
geometry: this._getGeometryGeoJSON(),
|
|
6255
|
+
properties: this.properties
|
|
6256
|
+
};
|
|
6257
|
+
}
|
|
6258
|
+
_getGeometryGeoJSON() {
|
|
6259
|
+
const geometries = this.geometries.map((d2) => d2.getGeoJSON());
|
|
6260
|
+
if (geometries.length === 0) throw new Error("Feature has no geometries");
|
|
6261
|
+
if (geometries.length === 1) return geometries[0];
|
|
6262
|
+
if (geometries[0].type === "Polygon") {
|
|
6263
|
+
return {
|
|
6264
|
+
type: "MultiPolygon",
|
|
6265
|
+
coordinates: geometries.map((d2) => d2.coordinates)
|
|
6266
|
+
};
|
|
6267
|
+
} else if (geometries[0].type === "LineString") {
|
|
6268
|
+
return {
|
|
6269
|
+
type: "MultiLineString",
|
|
6270
|
+
coordinates: geometries.map((d2) => d2.coordinates)
|
|
6271
|
+
};
|
|
6272
|
+
} else if (geometries[0].type === "Point") {
|
|
6273
|
+
return {
|
|
6274
|
+
type: "MultiPoint",
|
|
6275
|
+
coordinates: geometries.map((d2) => d2.coordinates)
|
|
6276
|
+
};
|
|
6277
|
+
}
|
|
6278
|
+
throw new Error("Could not determine geometry type");
|
|
6279
|
+
}
|
|
6351
6280
|
}
|
|
6352
6281
|
function memoise(fn) {
|
|
6353
6282
|
let called = false;
|
|
@@ -6365,928 +6294,1031 @@
|
|
|
6365
6294
|
return lastResult;
|
|
6366
6295
|
};
|
|
6367
6296
|
}
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
let r = parseInt(rgbaMatch[1], 10);
|
|
6383
|
-
let g = parseInt(rgbaMatch[2], 10);
|
|
6384
|
-
let b = parseInt(rgbaMatch[3], 10);
|
|
6385
|
-
let a = rgbaMatch[4] !== void 0 ? parseFloat(rgbaMatch[4]) : opacity;
|
|
6386
|
-
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
6387
|
-
}
|
|
6388
|
-
throw new Error("Unsupported color format");
|
|
6389
|
-
}
|
|
6390
|
-
class Stroke {
|
|
6391
|
-
constructor(options) {
|
|
6392
|
-
this.color = (options == null ? void 0 : options.color) || "#121212";
|
|
6393
|
-
this.width = (options == null ? void 0 : options.width) || 0.5;
|
|
6394
|
-
this.opacity = (options == null ? void 0 : options.opacity) || 1;
|
|
6395
|
-
this._getRgba = memoise(toRgba);
|
|
6396
|
-
}
|
|
6397
|
-
getRgba() {
|
|
6398
|
-
return this._getRgba(this.color, this.opacity);
|
|
6399
|
-
}
|
|
6400
|
-
}
|
|
6401
|
-
class Fill {
|
|
6402
|
-
constructor(options) {
|
|
6403
|
-
this.color = (options == null ? void 0 : options.color) || "#CCC";
|
|
6404
|
-
this.opacity = (options == null ? void 0 : options.opacity) || 1;
|
|
6405
|
-
this._getRgba = memoise(toRgba);
|
|
6297
|
+
class Geometry {
|
|
6298
|
+
/**
|
|
6299
|
+
* Represents vector geometry
|
|
6300
|
+
* @constructor
|
|
6301
|
+
* @param {Object} options
|
|
6302
|
+
* @param {string} options.type - The type of geometry (e.g., 'Point', 'LineString', 'Polygon')
|
|
6303
|
+
* @param {Array} options.extent - The extent of the geometry (e.g., [xmin, ymin, xmax, ymax])
|
|
6304
|
+
* @param {Array} options.coordinates - The coordinates of the geometry (e.g., [[x1, y1], [x2, y2], ...])
|
|
6305
|
+
*/
|
|
6306
|
+
constructor({ type, extent, coordinates }) {
|
|
6307
|
+
this.type = type;
|
|
6308
|
+
this.extent = extent;
|
|
6309
|
+
this.coordinates = coordinates;
|
|
6310
|
+
this.getProjected = memoise(this._getProjected).bind(this);
|
|
6406
6311
|
}
|
|
6407
|
-
|
|
6408
|
-
|
|
6312
|
+
/**
|
|
6313
|
+
* Returns the geometry as a GeoJSON object
|
|
6314
|
+
* @function
|
|
6315
|
+
* @param {import("../projection").Projection} projection - The projection to use for the geometry
|
|
6316
|
+
* @returns {Object} A GeoJSON representation of the projected geometry
|
|
6317
|
+
* @private
|
|
6318
|
+
*/
|
|
6319
|
+
// eslint-disable-next-line no-unused-vars
|
|
6320
|
+
_getProjected(projection) {
|
|
6321
|
+
throw new Error("Not implemented");
|
|
6409
6322
|
}
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
this.textShadow = (options == null ? void 0 : options.textShadow) || "1px 1px 0px #f6f6f6, -1px -1px 0px #f6f6f6, -1px 1px 0px #f6f6f6, 1px -1px #f6f6f6";
|
|
6323
|
+
/**
|
|
6324
|
+
* Returns the geometry as a GeoJSON object
|
|
6325
|
+
* @returns {Object} The GeoJSON representation of the geometry
|
|
6326
|
+
*/
|
|
6327
|
+
getGeoJSON() {
|
|
6328
|
+
return {
|
|
6329
|
+
type: this.type,
|
|
6330
|
+
coordinates: this.coordinates
|
|
6331
|
+
};
|
|
6420
6332
|
}
|
|
6421
6333
|
}
|
|
6422
|
-
class
|
|
6423
|
-
constructor(
|
|
6424
|
-
|
|
6425
|
-
this.length = this.data.length;
|
|
6426
|
-
this.compare = compare;
|
|
6427
|
-
if (this.length > 0) {
|
|
6428
|
-
for (let i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
|
|
6429
|
-
}
|
|
6430
|
-
}
|
|
6431
|
-
push(item) {
|
|
6432
|
-
this.data.push(item);
|
|
6433
|
-
this.length++;
|
|
6434
|
-
this._up(this.length - 1);
|
|
6334
|
+
class LineString extends Geometry {
|
|
6335
|
+
constructor({ type = "LineString", extent, coordinates }) {
|
|
6336
|
+
super({ type, extent, coordinates });
|
|
6435
6337
|
}
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
const
|
|
6439
|
-
|
|
6440
|
-
this.length--;
|
|
6441
|
-
if (this.length > 0) {
|
|
6442
|
-
this.data[0] = bottom;
|
|
6443
|
-
this._down(0);
|
|
6338
|
+
_getProjected(projection) {
|
|
6339
|
+
const projected = [];
|
|
6340
|
+
for (const point of this.coordinates) {
|
|
6341
|
+
projected.push(projection(point));
|
|
6444
6342
|
}
|
|
6445
|
-
return
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6343
|
+
return {
|
|
6344
|
+
type: this.type,
|
|
6345
|
+
coordinates: projected
|
|
6346
|
+
};
|
|
6449
6347
|
}
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
const parent = pos - 1 >> 1;
|
|
6455
|
-
const current = data[parent];
|
|
6456
|
-
if (compare(item, current) >= 0) break;
|
|
6457
|
-
data[pos] = current;
|
|
6458
|
-
pos = parent;
|
|
6459
|
-
}
|
|
6460
|
-
data[pos] = item;
|
|
6348
|
+
}
|
|
6349
|
+
class Polygon extends Geometry {
|
|
6350
|
+
constructor({ type = "Polygon", extent, coordinates }) {
|
|
6351
|
+
super({ type, extent, coordinates });
|
|
6461
6352
|
}
|
|
6462
|
-
|
|
6463
|
-
const
|
|
6464
|
-
const
|
|
6465
|
-
const
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6353
|
+
_getProjected(projection) {
|
|
6354
|
+
const projected = [];
|
|
6355
|
+
const rings = this.coordinates;
|
|
6356
|
+
for (const ring of rings) {
|
|
6357
|
+
const projectedRing = [];
|
|
6358
|
+
for (const point of ring) {
|
|
6359
|
+
const projectedPoint = projection(point);
|
|
6360
|
+
if (projectedPoint) {
|
|
6361
|
+
projectedRing.push(projectedPoint);
|
|
6362
|
+
} else {
|
|
6363
|
+
break;
|
|
6364
|
+
}
|
|
6473
6365
|
}
|
|
6474
|
-
if (
|
|
6475
|
-
|
|
6476
|
-
pos = left;
|
|
6477
|
-
}
|
|
6478
|
-
data[pos] = item;
|
|
6479
|
-
}
|
|
6480
|
-
}
|
|
6481
|
-
function defaultCompare(a, b) {
|
|
6482
|
-
return a < b ? -1 : a > b ? 1 : 0;
|
|
6483
|
-
}
|
|
6484
|
-
function knn(tree, x, y, n2, predicate, maxDistance) {
|
|
6485
|
-
let node = tree.data;
|
|
6486
|
-
const result = [];
|
|
6487
|
-
const toBBox = tree.toBBox;
|
|
6488
|
-
const queue = new TinyQueue(void 0, compareDist);
|
|
6489
|
-
while (node) {
|
|
6490
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
6491
|
-
const child = node.children[i];
|
|
6492
|
-
const dist = boxDist(x, y, node.leaf ? toBBox(child) : child);
|
|
6493
|
-
{
|
|
6494
|
-
queue.push({
|
|
6495
|
-
node: child,
|
|
6496
|
-
isItem: node.leaf,
|
|
6497
|
-
dist
|
|
6498
|
-
});
|
|
6366
|
+
if (projectedRing.length > 0) {
|
|
6367
|
+
projected.push(projectedRing);
|
|
6499
6368
|
}
|
|
6500
6369
|
}
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
if (result.length === n2) return result;
|
|
6506
|
-
}
|
|
6507
|
-
node = queue.pop();
|
|
6508
|
-
if (node) node = node.node;
|
|
6370
|
+
return {
|
|
6371
|
+
type: this.type,
|
|
6372
|
+
coordinates: projected
|
|
6373
|
+
};
|
|
6509
6374
|
}
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
function compareDist(a, b) {
|
|
6513
|
-
return a.dist - b.dist;
|
|
6514
|
-
}
|
|
6515
|
-
function boxDist(x, y, box) {
|
|
6516
|
-
const dx = axisDist(x, box.minX, box.maxX), dy = axisDist(y, box.minY, box.maxY);
|
|
6517
|
-
return dx * dx + dy * dy;
|
|
6518
|
-
}
|
|
6519
|
-
function axisDist(k, min, max) {
|
|
6520
|
-
return k < min ? min - k : k <= max ? 0 : k - max;
|
|
6521
|
-
}
|
|
6522
|
-
class VectorSource {
|
|
6523
|
-
constructor({ features }) {
|
|
6524
|
-
this.dispatcher = new Dispatcher(this);
|
|
6525
|
-
this._featuresRtree = new RBush();
|
|
6526
|
-
this.setFeatures(features);
|
|
6375
|
+
getOuterRing() {
|
|
6376
|
+
return this.coordinates[0];
|
|
6527
6377
|
}
|
|
6528
|
-
|
|
6529
|
-
this.
|
|
6378
|
+
setOuterRing(coordinates) {
|
|
6379
|
+
this.coordinates[0] = coordinates;
|
|
6530
6380
|
}
|
|
6531
|
-
|
|
6532
|
-
|
|
6381
|
+
setCoordinates(coordinates) {
|
|
6382
|
+
this.coordinates = coordinates;
|
|
6533
6383
|
}
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
this.
|
|
6538
|
-
lon,
|
|
6539
|
-
lat,
|
|
6540
|
-
10,
|
|
6541
|
-
(d2) => d2.feature.containsCoordinate(coordinate)
|
|
6542
|
-
).map((d2) => {
|
|
6543
|
-
const midX = d2.minX + (d2.minX + d2.maxX) / 2;
|
|
6544
|
-
const midY = d2.minY + (d2.minY + d2.maxY) / 2;
|
|
6545
|
-
d2.distance = Math.hypot(midX - lon, midY - lat);
|
|
6546
|
-
return d2;
|
|
6384
|
+
clone() {
|
|
6385
|
+
return new Polygon({
|
|
6386
|
+
extent: this.extent,
|
|
6387
|
+
coordinates: JSON.parse(JSON.stringify(this.coordinates))
|
|
6547
6388
|
});
|
|
6548
|
-
features.sort((a, b) => a.distance - b.distance);
|
|
6549
|
-
return features.map((d2) => d2.feature);
|
|
6550
6389
|
}
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6390
|
+
}
|
|
6391
|
+
class Point extends Geometry {
|
|
6392
|
+
constructor({ type = "Point", coordinates }) {
|
|
6393
|
+
super({ type, extent: null, coordinates });
|
|
6394
|
+
this.extent = [...coordinates, ...coordinates];
|
|
6554
6395
|
}
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
minX: Math.floor(minX),
|
|
6561
|
-
minY: Math.floor(minY),
|
|
6562
|
-
maxX: Math.ceil(maxX),
|
|
6563
|
-
maxY: Math.ceil(maxY),
|
|
6564
|
-
feature
|
|
6565
|
-
});
|
|
6566
|
-
}
|
|
6567
|
-
this._features = features;
|
|
6568
|
-
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
6396
|
+
_getProjected(projection) {
|
|
6397
|
+
return {
|
|
6398
|
+
type: this.type,
|
|
6399
|
+
coordinates: projection(this.coordinates)
|
|
6400
|
+
};
|
|
6569
6401
|
}
|
|
6570
6402
|
}
|
|
6571
|
-
class
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
features
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6403
|
+
class GeoJSON {
|
|
6404
|
+
readFeaturesFromObject(object) {
|
|
6405
|
+
const geoJSONObject = object;
|
|
6406
|
+
let features = null;
|
|
6407
|
+
if (geoJSONObject["type"] === "FeatureCollection") {
|
|
6408
|
+
const geoJSONFeatureCollection = object;
|
|
6409
|
+
features = [];
|
|
6410
|
+
const geoJSONFeatures = geoJSONFeatureCollection["features"];
|
|
6411
|
+
for (let i = 0, ii = geoJSONFeatures.length; i < ii; ++i) {
|
|
6412
|
+
const featureObject = this.readFeatureFromObject(geoJSONFeatures[i]);
|
|
6413
|
+
if (!featureObject) {
|
|
6414
|
+
continue;
|
|
6415
|
+
}
|
|
6416
|
+
features.push(featureObject);
|
|
6417
|
+
}
|
|
6418
|
+
} else if (geoJSONObject["type"] === "Feature") {
|
|
6419
|
+
features = [this.readFeatureFromObject(geoJSONObject)];
|
|
6420
|
+
} else if (Array.isArray(geoJSONObject)) {
|
|
6421
|
+
features = [];
|
|
6422
|
+
for (let i = 0, ii = geoJSONObject.length; i < ii; ++i) {
|
|
6423
|
+
const featureObject = this.readFeatureFromObject(geoJSONObject[i]);
|
|
6424
|
+
if (!featureObject) {
|
|
6425
|
+
continue;
|
|
6426
|
+
}
|
|
6427
|
+
features.push(featureObject);
|
|
6428
|
+
}
|
|
6429
|
+
} else {
|
|
6430
|
+
try {
|
|
6431
|
+
const geometries = this.readGeometriesFromObject(geoJSONObject);
|
|
6432
|
+
const feature = new Feature({ geometries });
|
|
6433
|
+
features = [feature];
|
|
6434
|
+
} catch {
|
|
6435
|
+
console.warn("Unable to interpret GeoJSON:", geoJSONObject);
|
|
6436
|
+
return;
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6439
|
+
return features.flat();
|
|
6440
|
+
}
|
|
6441
|
+
readFeatureFromObject(geoJSONObject) {
|
|
6442
|
+
const geometries = this.readGeometriesFromObject(geoJSONObject["geometry"]);
|
|
6443
|
+
if (geometries.length > 0) {
|
|
6444
|
+
return new Feature({
|
|
6445
|
+
id: geoJSONObject["id"],
|
|
6446
|
+
geometries,
|
|
6447
|
+
properties: geoJSONObject["properties"]
|
|
6448
|
+
});
|
|
6449
|
+
}
|
|
6597
6450
|
return null;
|
|
6598
6451
|
}
|
|
6452
|
+
readGeometriesFromObject(geometry) {
|
|
6453
|
+
const geometries = [];
|
|
6454
|
+
if (geometry.type === "Polygon") {
|
|
6455
|
+
const polygon = this.readPolygonForCoordinates(geometry.coordinates);
|
|
6456
|
+
geometries.push(polygon);
|
|
6457
|
+
} else if (geometry.type === "MultiPolygon") {
|
|
6458
|
+
for (const polygonCoordinates of geometry.coordinates) {
|
|
6459
|
+
const polygon = this.readPolygonForCoordinates(polygonCoordinates);
|
|
6460
|
+
geometries.push(polygon);
|
|
6461
|
+
}
|
|
6462
|
+
} else if (geometry.type === "LineString") {
|
|
6463
|
+
const lineString = this.readLineStringForCoordinates(geometry.coordinates);
|
|
6464
|
+
geometries.push(lineString);
|
|
6465
|
+
} else if (geometry.type === "MultiLineString") {
|
|
6466
|
+
for (const lineStringCoordinates of geometry.coordinates) {
|
|
6467
|
+
const lineString = this.readLineStringForCoordinates(
|
|
6468
|
+
lineStringCoordinates
|
|
6469
|
+
);
|
|
6470
|
+
geometries.push(lineString);
|
|
6471
|
+
}
|
|
6472
|
+
} else if (geometry.type === "Point") {
|
|
6473
|
+
const point = this.readPointForCoordinates(geometry.coordinates);
|
|
6474
|
+
geometries.push(point);
|
|
6475
|
+
}
|
|
6476
|
+
return geometries;
|
|
6477
|
+
}
|
|
6478
|
+
readPolygonForCoordinates(coordinates) {
|
|
6479
|
+
const outerRing = coordinates[0];
|
|
6480
|
+
const extent = extentForCoordinates(outerRing);
|
|
6481
|
+
return new Polygon({ extent, coordinates });
|
|
6482
|
+
}
|
|
6483
|
+
readLineStringForCoordinates(coordinates) {
|
|
6484
|
+
const extent = extentForCoordinates(coordinates);
|
|
6485
|
+
return new LineString({ extent, coordinates });
|
|
6486
|
+
}
|
|
6487
|
+
readPointForCoordinates(coordinates) {
|
|
6488
|
+
return new Point({ coordinates });
|
|
6489
|
+
}
|
|
6490
|
+
}
|
|
6491
|
+
class FeatureCollection {
|
|
6599
6492
|
/**
|
|
6600
|
-
*
|
|
6601
|
-
* @param {
|
|
6493
|
+
* Create a feature collection from GeoJSON features.
|
|
6494
|
+
* @param {Object[]} geoJSON - The GeoJSON object
|
|
6495
|
+
* @returns {FeatureCollection} The feature collection
|
|
6602
6496
|
*/
|
|
6603
|
-
static
|
|
6604
|
-
const
|
|
6605
|
-
return new
|
|
6497
|
+
static fromGeoJSON(geoJSON) {
|
|
6498
|
+
const features = new GeoJSON().readFeaturesFromObject(geoJSON);
|
|
6499
|
+
return new FeatureCollection(features);
|
|
6606
6500
|
}
|
|
6607
6501
|
/**
|
|
6608
|
-
*
|
|
6609
|
-
* @
|
|
6610
|
-
* @param {
|
|
6611
|
-
* @param {number} [params.minZoom=0]
|
|
6612
|
-
* @param {number} [params.opacity=1]
|
|
6613
|
-
* @param {boolean} [params.declutter=true]
|
|
6614
|
-
* @param {boolean} [params.drawCollisionBoxes=false]
|
|
6502
|
+
* Create a feature collection.
|
|
6503
|
+
* @constructor
|
|
6504
|
+
* @param {import("./Feature").Feature[]} features - The features to put in the collection
|
|
6615
6505
|
*/
|
|
6616
|
-
constructor({
|
|
6617
|
-
|
|
6618
|
-
style: style2,
|
|
6619
|
-
minZoom = 0,
|
|
6620
|
-
opacity = 1,
|
|
6621
|
-
declutter = true,
|
|
6622
|
-
drawCollisionBoxes = false
|
|
6623
|
-
}) {
|
|
6624
|
-
this.source = source;
|
|
6625
|
-
this._style = style2;
|
|
6626
|
-
this.minZoom = minZoom;
|
|
6627
|
-
this.opacity = opacity;
|
|
6628
|
-
this.declutter = declutter;
|
|
6629
|
-
this.drawCollisionBoxes = drawCollisionBoxes;
|
|
6630
|
-
this.renderer = new TextLayerRenderer(this);
|
|
6631
|
-
this.dispatcher = new Dispatcher(this);
|
|
6632
|
-
}
|
|
6633
|
-
tearDown() {
|
|
6634
|
-
this.dispatcher = null;
|
|
6635
|
-
}
|
|
6636
|
-
get style() {
|
|
6637
|
-
if (this._style) return this._style;
|
|
6638
|
-
const defaultStyle = new Style({
|
|
6639
|
-
text: new Text()
|
|
6640
|
-
});
|
|
6641
|
-
return defaultStyle;
|
|
6642
|
-
}
|
|
6643
|
-
set style(style2) {
|
|
6644
|
-
this._style = style2;
|
|
6645
|
-
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
6506
|
+
constructor(features) {
|
|
6507
|
+
this.features = features;
|
|
6646
6508
|
}
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
const featureExtent = feature.getExtent();
|
|
6652
|
-
if (!combinedExtent) return featureExtent;
|
|
6653
|
-
return combineExtents(featureExtent, combinedExtent);
|
|
6654
|
-
}, null);
|
|
6655
|
-
this._extent = extent;
|
|
6656
|
-
return extent;
|
|
6509
|
+
}
|
|
6510
|
+
class FeatureRenderer {
|
|
6511
|
+
constructor() {
|
|
6512
|
+
this.drawingFunction = d3Geo.geoPath();
|
|
6657
6513
|
}
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
if (typeof style2 === "function") return style2;
|
|
6661
|
-
return () => {
|
|
6662
|
-
return style2;
|
|
6663
|
-
};
|
|
6514
|
+
setStyle(style2) {
|
|
6515
|
+
this.style = style2;
|
|
6664
6516
|
}
|
|
6665
|
-
|
|
6666
|
-
|
|
6517
|
+
render(frameState, feature, context) {
|
|
6518
|
+
if (!this.style) {
|
|
6519
|
+
return;
|
|
6520
|
+
}
|
|
6521
|
+
const { projection, transform, pixelRatio } = frameState.viewState;
|
|
6522
|
+
const { stroke, fill } = this.style;
|
|
6523
|
+
this.drawingFunction.context(context);
|
|
6524
|
+
context.beginPath();
|
|
6525
|
+
const geometries = feature.getProjectedGeometries(projection);
|
|
6526
|
+
if (frameState.debug) {
|
|
6527
|
+
try {
|
|
6528
|
+
validateGeometries(geometries);
|
|
6529
|
+
} catch {
|
|
6530
|
+
console.error(
|
|
6531
|
+
`Invalid geometry. Feature skipped during rendering. Click here to inspect geometry: ${generateDebugUrl(feature)}
|
|
6532
|
+
`,
|
|
6533
|
+
feature
|
|
6534
|
+
);
|
|
6535
|
+
}
|
|
6536
|
+
}
|
|
6537
|
+
for (const geometry of geometries) {
|
|
6538
|
+
this.drawingFunction(geometry);
|
|
6539
|
+
}
|
|
6540
|
+
if (fill) {
|
|
6541
|
+
context.fillStyle = fill.getRgba();
|
|
6542
|
+
context.fill();
|
|
6543
|
+
}
|
|
6544
|
+
if (stroke) {
|
|
6545
|
+
context.lineWidth = stroke.width * pixelRatio / transform.k;
|
|
6546
|
+
context.strokeStyle = stroke.getRgba();
|
|
6547
|
+
context.stroke();
|
|
6548
|
+
}
|
|
6667
6549
|
}
|
|
6668
6550
|
}
|
|
6669
|
-
|
|
6551
|
+
const textPadding = {
|
|
6552
|
+
top: 20,
|
|
6553
|
+
right: 20,
|
|
6554
|
+
bottom: 20,
|
|
6555
|
+
left: 20
|
|
6556
|
+
};
|
|
6557
|
+
class TextLayerRenderer {
|
|
6670
6558
|
constructor(layer) {
|
|
6671
6559
|
this.layer = layer;
|
|
6672
6560
|
this.featureRenderer = new FeatureRenderer();
|
|
6561
|
+
this._element = document.createElement("div");
|
|
6562
|
+
this._element.className = "gv-text-layer";
|
|
6563
|
+
const style2 = this._element.style;
|
|
6564
|
+
style2.position = "absolute";
|
|
6565
|
+
style2.width = "100%";
|
|
6566
|
+
style2.height = "100%";
|
|
6567
|
+
style2.pointerEvents = "none";
|
|
6568
|
+
style2.overflow = "hidden";
|
|
6673
6569
|
}
|
|
6674
6570
|
renderFrame(frameState, targetElement) {
|
|
6675
6571
|
if (this.layer.opacity === 0) return targetElement;
|
|
6676
|
-
const {
|
|
6677
|
-
const
|
|
6678
|
-
|
|
6679
|
-
context.save();
|
|
6680
|
-
context.translate(transform.x, transform.y);
|
|
6681
|
-
context.scale(transform.k, transform.k);
|
|
6682
|
-
context.lineJoin = "round";
|
|
6683
|
-
context.lineCap = "round";
|
|
6684
|
-
context.globalAlpha = this.layer.opacity;
|
|
6572
|
+
const { declutterTree } = frameState;
|
|
6573
|
+
const { projection, viewPortSize, sizeInPixels, visibleExtent, transform } = frameState.viewState;
|
|
6574
|
+
this._element.style.opacity = this.layer.opacity;
|
|
6685
6575
|
const source = this.layer.source;
|
|
6686
6576
|
const features = source.getFeaturesInExtent(visibleExtent);
|
|
6577
|
+
const textElements = [];
|
|
6687
6578
|
for (const feature of features) {
|
|
6579
|
+
const geometries = feature.getProjectedGeometries(projection);
|
|
6580
|
+
const point = geometries.find((d2) => d2.type === "Point");
|
|
6581
|
+
if (!point) {
|
|
6582
|
+
throw new Error(
|
|
6583
|
+
`Expected Point geometry for feature in TextLayer: ${feature}`
|
|
6584
|
+
);
|
|
6585
|
+
}
|
|
6688
6586
|
const styleFunction2 = feature.getStyleFunction() || this.layer.getStyleFunction();
|
|
6689
6587
|
const featureStyle = styleFunction2(feature);
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6588
|
+
const textElement = this.getTextElementWithID(feature.uid);
|
|
6589
|
+
textElement.innerText = featureStyle.text.content;
|
|
6590
|
+
const [relativeX, relativeY] = transform.apply(point.coordinates).map((d2, i) => d2 / sizeInPixels[i]);
|
|
6591
|
+
const position = {
|
|
6592
|
+
left: `${relativeX * 100}%`,
|
|
6593
|
+
top: `${relativeY * 100}%`
|
|
6594
|
+
};
|
|
6595
|
+
this.styleTextElement(textElement, featureStyle.text, position);
|
|
6596
|
+
const bbox = this.getElementBBox(textElement, {
|
|
6597
|
+
x: relativeX * viewPortSize[0],
|
|
6598
|
+
y: relativeY * viewPortSize[1]
|
|
6599
|
+
});
|
|
6600
|
+
if (declutterTree.collides(bbox)) {
|
|
6601
|
+
continue;
|
|
6602
|
+
}
|
|
6603
|
+
declutterTree.insert(bbox);
|
|
6604
|
+
if (this.layer.drawCollisionBoxes) {
|
|
6605
|
+
const collisionBoxDebugElement = this.getCollisionBoxElement(bbox);
|
|
6606
|
+
textElements.push(collisionBoxDebugElement);
|
|
6607
|
+
}
|
|
6608
|
+
textElements.push(textElement);
|
|
6703
6609
|
}
|
|
6704
|
-
|
|
6705
|
-
return
|
|
6610
|
+
replaceChildren(this._element, textElements);
|
|
6611
|
+
return this._element;
|
|
6706
6612
|
}
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
let
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
containerReused = true;
|
|
6714
|
-
} else if (this._container) {
|
|
6715
|
-
container2 = this._container;
|
|
6716
|
-
} else {
|
|
6717
|
-
container2 = this.createContainer();
|
|
6718
|
-
}
|
|
6719
|
-
if (!containerReused) {
|
|
6720
|
-
const canvas2 = container2.firstElementChild;
|
|
6721
|
-
canvas2.width = sizeInPixels[0];
|
|
6722
|
-
canvas2.height = sizeInPixels[1];
|
|
6613
|
+
getTextElementWithID(id2) {
|
|
6614
|
+
const elementId = `text-feature-${id2}`;
|
|
6615
|
+
let textElement = this._element.querySelector(`#${elementId}`);
|
|
6616
|
+
if (!textElement) {
|
|
6617
|
+
textElement = document.createElement("div");
|
|
6618
|
+
textElement.id = elementId;
|
|
6723
6619
|
}
|
|
6724
|
-
|
|
6725
|
-
return container2;
|
|
6620
|
+
return textElement;
|
|
6726
6621
|
}
|
|
6727
|
-
|
|
6728
|
-
const
|
|
6729
|
-
container2.className = "gv-map-layer";
|
|
6730
|
-
let style2 = container2.style;
|
|
6731
|
-
style2.position = "absolute";
|
|
6732
|
-
style2.width = "100%";
|
|
6733
|
-
style2.height = "100%";
|
|
6734
|
-
const canvas = document.createElement("canvas");
|
|
6735
|
-
style2 = canvas.style;
|
|
6622
|
+
styleTextElement(element, textStyle, position) {
|
|
6623
|
+
const style2 = element.style;
|
|
6736
6624
|
style2.position = "absolute";
|
|
6737
|
-
style2.
|
|
6738
|
-
style2.
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
style: style2,
|
|
6750
|
-
minZoom,
|
|
6751
|
-
opacity,
|
|
6752
|
-
hitDetectionEnabled
|
|
6753
|
-
}),
|
|
6754
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6755
|
-
[features, minZoom, opacity, hitDetectionEnabled]
|
|
6756
|
-
);
|
|
6757
|
-
registerLayer(layer);
|
|
6758
|
-
hooks.useEffect(() => {
|
|
6759
|
-
layer.style = style2;
|
|
6760
|
-
}, [style2]);
|
|
6761
|
-
return null;
|
|
6762
|
-
}
|
|
6763
|
-
/**
|
|
6764
|
-
* @param {import("../Feature").Feature[]} features
|
|
6765
|
-
* @param {VectorLayerOptions} options
|
|
6766
|
-
*/
|
|
6767
|
-
static with(features, options) {
|
|
6768
|
-
const source = new VectorSource({ features });
|
|
6769
|
-
return new VectorLayer({ source, ...options });
|
|
6770
|
-
}
|
|
6771
|
-
/**
|
|
6772
|
-
* @param {Object} params
|
|
6773
|
-
* @param {VectorSource} params.source
|
|
6774
|
-
* @param {Style | (() => Style)} [params.style=undefined]
|
|
6775
|
-
* @param {number} [params.minZoom=0]
|
|
6776
|
-
* @param {number} [params.opacity=1]
|
|
6777
|
-
* @param {boolean} [params.hitDetectionEnabled=false]
|
|
6778
|
-
*/
|
|
6779
|
-
constructor({
|
|
6780
|
-
source,
|
|
6781
|
-
style: style2,
|
|
6782
|
-
minZoom = 0,
|
|
6783
|
-
opacity = 1,
|
|
6784
|
-
hitDetectionEnabled = true
|
|
6785
|
-
}) {
|
|
6786
|
-
this.dispatcher = new Dispatcher(this);
|
|
6787
|
-
this.renderer = new VectorLayerRenderer(this);
|
|
6788
|
-
this.source = source;
|
|
6789
|
-
this._style = style2;
|
|
6790
|
-
this.minZoom = minZoom;
|
|
6791
|
-
this.opacity = opacity;
|
|
6792
|
-
this.hitDetectionEnabled = hitDetectionEnabled;
|
|
6793
|
-
}
|
|
6794
|
-
get source() {
|
|
6795
|
-
return this._source;
|
|
6625
|
+
style2.transform = `translate(-50%, -50%)`;
|
|
6626
|
+
style2.left = position.left;
|
|
6627
|
+
style2.top = position.top;
|
|
6628
|
+
style2.textAlign = "center";
|
|
6629
|
+
style2.whiteSpace = "nowrap";
|
|
6630
|
+
style2.fontFamily = textStyle.fontFamily;
|
|
6631
|
+
style2.fontSize = textStyle.fontSize;
|
|
6632
|
+
style2.fontWeight = textStyle.fontWeight;
|
|
6633
|
+
style2.lineHeight = textStyle.lineHeight;
|
|
6634
|
+
style2.color = textStyle.color;
|
|
6635
|
+
style2.textShadow = textStyle.textShadow;
|
|
6636
|
+
style2.padding = `${textPadding.top}px ${textPadding.right}px ${textPadding.bottom}px ${textPadding.left}px`;
|
|
6796
6637
|
}
|
|
6797
|
-
|
|
6798
|
-
if (
|
|
6799
|
-
|
|
6638
|
+
getElementBBox(element, position) {
|
|
6639
|
+
if (!element.parentElement) {
|
|
6640
|
+
document.body.appendChild(element);
|
|
6800
6641
|
}
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6642
|
+
const { width, height } = element.getBoundingClientRect();
|
|
6643
|
+
if (element.parentElement !== this._element) {
|
|
6644
|
+
element.remove();
|
|
6645
|
+
}
|
|
6646
|
+
return {
|
|
6647
|
+
minX: Math.floor(position.x) - width / 2,
|
|
6648
|
+
minY: Math.floor(position.y) - height / 2,
|
|
6649
|
+
maxX: Math.ceil(position.x + width / 2),
|
|
6650
|
+
maxY: Math.ceil(position.y + height / 2)
|
|
6651
|
+
};
|
|
6806
6652
|
}
|
|
6807
|
-
|
|
6808
|
-
|
|
6653
|
+
getCollisionBoxElement(bbox) {
|
|
6654
|
+
const element = document.createElement("div");
|
|
6655
|
+
const style2 = element.style;
|
|
6656
|
+
style2.position = "absolute";
|
|
6657
|
+
style2.left = `${bbox.minX}px`;
|
|
6658
|
+
style2.top = `${bbox.minY}px`;
|
|
6659
|
+
style2.width = `${bbox.maxX - bbox.minX}px`;
|
|
6660
|
+
style2.height = `${bbox.maxY - bbox.minY}px`;
|
|
6661
|
+
style2.border = "2px solid black";
|
|
6662
|
+
return element;
|
|
6809
6663
|
}
|
|
6810
|
-
|
|
6811
|
-
|
|
6664
|
+
}
|
|
6665
|
+
class Style {
|
|
6666
|
+
constructor(properties) {
|
|
6667
|
+
this.stroke = properties == null ? void 0 : properties.stroke;
|
|
6668
|
+
this.fill = properties == null ? void 0 : properties.fill;
|
|
6669
|
+
this.text = properties == null ? void 0 : properties.text;
|
|
6812
6670
|
}
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6671
|
+
clone() {
|
|
6672
|
+
return new Style({
|
|
6673
|
+
stroke: this.stroke,
|
|
6674
|
+
fill: this.fill,
|
|
6675
|
+
text: this.text
|
|
6817
6676
|
});
|
|
6818
|
-
return defaultStyle;
|
|
6819
6677
|
}
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6678
|
+
}
|
|
6679
|
+
function toRgba(color2, opacity = 1) {
|
|
6680
|
+
color2 = color2.replace(/\s+/g, "").toLowerCase();
|
|
6681
|
+
if (color2.startsWith("#")) {
|
|
6682
|
+
color2 = color2.replace(/^#/, "");
|
|
6683
|
+
if (color2.length === 3) {
|
|
6684
|
+
color2 = color2.split("").map((char) => char + char).join("");
|
|
6685
|
+
}
|
|
6686
|
+
let r = parseInt(color2.substring(0, 2), 16);
|
|
6687
|
+
let g = parseInt(color2.substring(2, 4), 16);
|
|
6688
|
+
let b = parseInt(color2.substring(4, 6), 16);
|
|
6689
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
6823
6690
|
}
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6691
|
+
let rgbaMatch = color2.match(/^rgba?\((\d+),(\d+),(\d+)(?:,(\d+(\.\d+)?))?\)$/);
|
|
6692
|
+
if (rgbaMatch) {
|
|
6693
|
+
let r = parseInt(rgbaMatch[1], 10);
|
|
6694
|
+
let g = parseInt(rgbaMatch[2], 10);
|
|
6695
|
+
let b = parseInt(rgbaMatch[3], 10);
|
|
6696
|
+
let a = rgbaMatch[4] !== void 0 ? parseFloat(rgbaMatch[4]) : opacity;
|
|
6697
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
6830
6698
|
}
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
this._extent = extent;
|
|
6840
|
-
return extent;
|
|
6699
|
+
throw new Error("Unsupported color format");
|
|
6700
|
+
}
|
|
6701
|
+
class Stroke {
|
|
6702
|
+
constructor(options) {
|
|
6703
|
+
this.color = (options == null ? void 0 : options.color) || "#121212";
|
|
6704
|
+
this.width = (options == null ? void 0 : options.width) || 0.5;
|
|
6705
|
+
this.opacity = (options == null ? void 0 : options.opacity) || 1;
|
|
6706
|
+
this._getRgba = memoise(toRgba);
|
|
6841
6707
|
}
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
return this.source.getFeaturesAtCoordinate(coordinate);
|
|
6708
|
+
getRgba() {
|
|
6709
|
+
return this._getRgba(this.color, this.opacity);
|
|
6845
6710
|
}
|
|
6846
|
-
|
|
6847
|
-
|
|
6711
|
+
}
|
|
6712
|
+
class Fill {
|
|
6713
|
+
constructor(options) {
|
|
6714
|
+
this.color = (options == null ? void 0 : options.color) || "#CCC";
|
|
6715
|
+
this.opacity = (options == null ? void 0 : options.opacity) || 1;
|
|
6716
|
+
this._getRgba = memoise(toRgba);
|
|
6717
|
+
}
|
|
6718
|
+
getRgba() {
|
|
6719
|
+
return this._getRgba(this.color, this.opacity);
|
|
6848
6720
|
}
|
|
6849
6721
|
}
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
);
|
|
6722
|
+
class Text {
|
|
6723
|
+
constructor(options) {
|
|
6724
|
+
this.content = options == null ? void 0 : options.content;
|
|
6725
|
+
this.fontFamily = (options == null ? void 0 : options.fontFamily) || "var(--text-sans)";
|
|
6726
|
+
this.fontSize = (options == null ? void 0 : options.fontSize) || "17px";
|
|
6727
|
+
this.fontWeight = (options == null ? void 0 : options.fontWeight) || "400";
|
|
6728
|
+
this.lineHeight = (options == null ? void 0 : options.lineHeight) || 1.3;
|
|
6729
|
+
this.color = (options == null ? void 0 : options.color) || "#121212";
|
|
6730
|
+
this.textShadow = (options == null ? void 0 : options.textShadow) || "1px 1px 0px #f6f6f6, -1px -1px 0px #f6f6f6, -1px 1px 0px #f6f6f6, 1px -1px #f6f6f6";
|
|
6855
6731
|
}
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
const newGeometry = newGeometries[e];
|
|
6865
|
-
if (currentGeometry.type !== "Polygon" || newGeometry.type !== "Polygon") {
|
|
6866
|
-
throw new Error("interpolateFeatures expects only Polygon geometry");
|
|
6867
|
-
}
|
|
6868
|
-
const shapeInterpolator = interpolate2(
|
|
6869
|
-
currentGeometries[e].getOuterRing(),
|
|
6870
|
-
newGeometries[e].getOuterRing(),
|
|
6871
|
-
{ string: false }
|
|
6872
|
-
);
|
|
6873
|
-
geometryInterpolators.push({
|
|
6874
|
-
type: "default",
|
|
6875
|
-
interpolator: shapeInterpolator
|
|
6876
|
-
});
|
|
6877
|
-
}
|
|
6878
|
-
} else if (currentGeometries.length === 1 && newGeometries.length > 1) {
|
|
6879
|
-
const separationInterpolator = separate(
|
|
6880
|
-
currentGeometries[0].getOuterRing(),
|
|
6881
|
-
newGeometries.map((geometry) => geometry.getOuterRing()),
|
|
6882
|
-
{ string: false, single: true }
|
|
6883
|
-
);
|
|
6884
|
-
geometryInterpolators.push({
|
|
6885
|
-
type: "separate",
|
|
6886
|
-
interpolator: separationInterpolator
|
|
6887
|
-
});
|
|
6888
|
-
} else if (currentGeometries.length > 1 && newGeometries.length === 1) {
|
|
6889
|
-
const combinationInterpolator = combine(
|
|
6890
|
-
currentGeometries.map((geometry) => geometry.getOuterRing()),
|
|
6891
|
-
newGeometries[0].getOuterRing(),
|
|
6892
|
-
{ string: false, single: true }
|
|
6893
|
-
);
|
|
6894
|
-
geometryInterpolators.push({
|
|
6895
|
-
type: "combine",
|
|
6896
|
-
interpolator: combinationInterpolator
|
|
6897
|
-
});
|
|
6898
|
-
} else {
|
|
6899
|
-
throw new Error(
|
|
6900
|
-
`Encountered an unexpected number of geometries: ${currentGeometries.length} and ${newGeometries.length}`
|
|
6901
|
-
);
|
|
6732
|
+
}
|
|
6733
|
+
class TinyQueue {
|
|
6734
|
+
constructor(data = [], compare = defaultCompare) {
|
|
6735
|
+
this.data = data;
|
|
6736
|
+
this.length = this.data.length;
|
|
6737
|
+
this.compare = compare;
|
|
6738
|
+
if (this.length > 0) {
|
|
6739
|
+
for (let i = (this.length >> 1) - 1; i >= 0; i--) this._down(i);
|
|
6902
6740
|
}
|
|
6903
|
-
featureInterpolators.push(geometryInterpolators);
|
|
6904
6741
|
}
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6742
|
+
push(item) {
|
|
6743
|
+
this.data.push(item);
|
|
6744
|
+
this.length++;
|
|
6745
|
+
this._up(this.length - 1);
|
|
6746
|
+
}
|
|
6747
|
+
pop() {
|
|
6748
|
+
if (this.length === 0) return void 0;
|
|
6749
|
+
const top = this.data[0];
|
|
6750
|
+
const bottom = this.data.pop();
|
|
6751
|
+
this.length--;
|
|
6752
|
+
if (this.length > 0) {
|
|
6753
|
+
this.data[0] = bottom;
|
|
6754
|
+
this._down(0);
|
|
6908
6755
|
}
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6756
|
+
return top;
|
|
6757
|
+
}
|
|
6758
|
+
peek() {
|
|
6759
|
+
return this.data[0];
|
|
6760
|
+
}
|
|
6761
|
+
_up(pos) {
|
|
6762
|
+
const { data, compare } = this;
|
|
6763
|
+
const item = data[pos];
|
|
6764
|
+
while (pos > 0) {
|
|
6765
|
+
const parent = pos - 1 >> 1;
|
|
6766
|
+
const current = data[parent];
|
|
6767
|
+
if (compare(item, current) >= 0) break;
|
|
6768
|
+
data[pos] = current;
|
|
6769
|
+
pos = parent;
|
|
6770
|
+
}
|
|
6771
|
+
data[pos] = item;
|
|
6772
|
+
}
|
|
6773
|
+
_down(pos) {
|
|
6774
|
+
const { data, compare } = this;
|
|
6775
|
+
const halfLength = this.length >> 1;
|
|
6776
|
+
const item = data[pos];
|
|
6777
|
+
while (pos < halfLength) {
|
|
6778
|
+
let left = (pos << 1) + 1;
|
|
6779
|
+
let best = data[left];
|
|
6780
|
+
const right = left + 1;
|
|
6781
|
+
if (right < this.length && compare(data[right], best) < 0) {
|
|
6782
|
+
left = right;
|
|
6783
|
+
best = data[right];
|
|
6935
6784
|
}
|
|
6936
|
-
|
|
6937
|
-
|
|
6785
|
+
if (compare(best, item) >= 0) break;
|
|
6786
|
+
data[pos] = best;
|
|
6787
|
+
pos = left;
|
|
6938
6788
|
}
|
|
6939
|
-
|
|
6940
|
-
}
|
|
6789
|
+
data[pos] = item;
|
|
6790
|
+
}
|
|
6941
6791
|
}
|
|
6942
|
-
function
|
|
6943
|
-
|
|
6944
|
-
firstStyle.fill,
|
|
6945
|
-
secondStyle.fill,
|
|
6946
|
-
interpolateColors,
|
|
6947
|
-
interpolateNumbers
|
|
6948
|
-
);
|
|
6949
|
-
const strokeInterpolator = interpolateStroke(
|
|
6950
|
-
firstStyle.stroke,
|
|
6951
|
-
secondStyle.stroke,
|
|
6952
|
-
interpolateColors,
|
|
6953
|
-
interpolateNumbers
|
|
6954
|
-
);
|
|
6955
|
-
return (t) => {
|
|
6956
|
-
return new Style({
|
|
6957
|
-
fill: fillInterpolator(t),
|
|
6958
|
-
stroke: strokeInterpolator(t)
|
|
6959
|
-
});
|
|
6960
|
-
};
|
|
6792
|
+
function defaultCompare(a, b) {
|
|
6793
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
6961
6794
|
}
|
|
6962
|
-
function
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
);
|
|
6967
|
-
|
|
6968
|
-
(
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6795
|
+
function knn(tree, x, y, n2, predicate, maxDistance) {
|
|
6796
|
+
let node = tree.data;
|
|
6797
|
+
const result = [];
|
|
6798
|
+
const toBBox = tree.toBBox;
|
|
6799
|
+
const queue = new TinyQueue(void 0, compareDist);
|
|
6800
|
+
while (node) {
|
|
6801
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
6802
|
+
const child = node.children[i];
|
|
6803
|
+
const dist = boxDist(x, y, node.leaf ? toBBox(child) : child);
|
|
6804
|
+
{
|
|
6805
|
+
queue.push({
|
|
6806
|
+
node: child,
|
|
6807
|
+
isItem: node.leaf,
|
|
6808
|
+
dist
|
|
6809
|
+
});
|
|
6810
|
+
}
|
|
6811
|
+
}
|
|
6812
|
+
while (queue.length && queue.peek().isItem) {
|
|
6813
|
+
const candidate = queue.pop().node;
|
|
6814
|
+
if (!predicate || predicate(candidate))
|
|
6815
|
+
result.push(candidate);
|
|
6816
|
+
if (result.length === n2) return result;
|
|
6817
|
+
}
|
|
6818
|
+
node = queue.pop();
|
|
6819
|
+
if (node) node = node.node;
|
|
6820
|
+
}
|
|
6821
|
+
return result;
|
|
6977
6822
|
}
|
|
6978
|
-
function
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
);
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6823
|
+
function compareDist(a, b) {
|
|
6824
|
+
return a.dist - b.dist;
|
|
6825
|
+
}
|
|
6826
|
+
function boxDist(x, y, box) {
|
|
6827
|
+
const dx = axisDist(x, box.minX, box.maxX), dy = axisDist(y, box.minY, box.maxY);
|
|
6828
|
+
return dx * dx + dy * dy;
|
|
6829
|
+
}
|
|
6830
|
+
function axisDist(k, min, max) {
|
|
6831
|
+
return k < min ? min - k : k <= max ? 0 : k - max;
|
|
6832
|
+
}
|
|
6833
|
+
class VectorSource {
|
|
6834
|
+
constructor({ features }) {
|
|
6835
|
+
this.dispatcher = new Dispatcher(this);
|
|
6836
|
+
this._featuresRtree = new RBush();
|
|
6837
|
+
this.setFeatures(features);
|
|
6838
|
+
}
|
|
6839
|
+
tearDown() {
|
|
6840
|
+
this.dispatcher = null;
|
|
6841
|
+
}
|
|
6842
|
+
getFeatures() {
|
|
6843
|
+
return this._features;
|
|
6844
|
+
}
|
|
6845
|
+
getFeaturesAtCoordinate(coordinate) {
|
|
6846
|
+
const [lon, lat] = coordinate;
|
|
6847
|
+
const features = knn(
|
|
6848
|
+
this._featuresRtree,
|
|
6849
|
+
lon,
|
|
6850
|
+
lat,
|
|
6851
|
+
10,
|
|
6852
|
+
(d2) => d2.feature.containsCoordinate(coordinate)
|
|
6853
|
+
).map((d2) => {
|
|
6854
|
+
const midX = d2.minX + (d2.minX + d2.maxX) / 2;
|
|
6855
|
+
const midY = d2.minY + (d2.minY + d2.maxY) / 2;
|
|
6856
|
+
d2.distance = Math.hypot(midX - lon, midY - lat);
|
|
6857
|
+
return d2;
|
|
6996
6858
|
});
|
|
6997
|
-
|
|
6859
|
+
features.sort((a, b) => a.distance - b.distance);
|
|
6860
|
+
return features.map((d2) => d2.feature);
|
|
6861
|
+
}
|
|
6862
|
+
getFeaturesInExtent(extent) {
|
|
6863
|
+
const [minX, minY, maxX, maxY] = extent;
|
|
6864
|
+
return this._featuresRtree.search({ minX, minY, maxX, maxY }).map((d2) => d2.feature);
|
|
6865
|
+
}
|
|
6866
|
+
setFeatures(features) {
|
|
6867
|
+
this._featuresRtree.clear();
|
|
6868
|
+
for (const feature of features) {
|
|
6869
|
+
const [minX, minY, maxX, maxY] = feature.getExtent();
|
|
6870
|
+
this._featuresRtree.insert({
|
|
6871
|
+
minX: Math.floor(minX),
|
|
6872
|
+
minY: Math.floor(minY),
|
|
6873
|
+
maxX: Math.ceil(maxX),
|
|
6874
|
+
maxY: Math.ceil(maxY),
|
|
6875
|
+
feature
|
|
6876
|
+
});
|
|
6877
|
+
}
|
|
6878
|
+
this._features = features;
|
|
6879
|
+
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
6880
|
+
}
|
|
6998
6881
|
}
|
|
6999
|
-
class
|
|
6882
|
+
class TextLayer {
|
|
6883
|
+
/** @param {TextLayerComponentProps} props */
|
|
6884
|
+
static Component({
|
|
6885
|
+
features,
|
|
6886
|
+
style: style2,
|
|
6887
|
+
minZoom,
|
|
6888
|
+
opacity,
|
|
6889
|
+
declutter,
|
|
6890
|
+
drawCollisionBoxes
|
|
6891
|
+
}) {
|
|
6892
|
+
const { registerLayer } = hooks.useContext(MapContext);
|
|
6893
|
+
const layer = hooks.useMemo(
|
|
6894
|
+
() => TextLayer.with(features, {
|
|
6895
|
+
style: style2,
|
|
6896
|
+
minZoom,
|
|
6897
|
+
opacity,
|
|
6898
|
+
declutter,
|
|
6899
|
+
drawCollisionBoxes
|
|
6900
|
+
}),
|
|
6901
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6902
|
+
[features, minZoom, opacity, declutter, drawCollisionBoxes]
|
|
6903
|
+
);
|
|
6904
|
+
registerLayer(layer);
|
|
6905
|
+
hooks.useEffect(() => {
|
|
6906
|
+
layer.style = style2;
|
|
6907
|
+
}, [style2]);
|
|
6908
|
+
return null;
|
|
6909
|
+
}
|
|
6910
|
+
/**
|
|
6911
|
+
* @param {import("../Feature").Feature[]} features
|
|
6912
|
+
* @param {TextLayerOptions} options
|
|
6913
|
+
*/
|
|
6914
|
+
static with(features, options) {
|
|
6915
|
+
const source = new VectorSource({ features });
|
|
6916
|
+
return new TextLayer({ source, ...options });
|
|
6917
|
+
}
|
|
7000
6918
|
/**
|
|
7001
|
-
* Represents a feature on the map
|
|
7002
6919
|
* @constructor
|
|
7003
|
-
* @param {Object}
|
|
7004
|
-
* @
|
|
7005
|
-
* @
|
|
7006
|
-
* @
|
|
7007
|
-
* @
|
|
6920
|
+
* @param {Object} params
|
|
6921
|
+
* @param {VectorSource} params.source
|
|
6922
|
+
* @param {Style | (() => Style)} [params.style=undefined]
|
|
6923
|
+
* @param {number} [params.minZoom=0]
|
|
6924
|
+
* @param {number} [params.opacity=1]
|
|
6925
|
+
* @param {boolean} [params.declutter=true]
|
|
6926
|
+
* @param {boolean} [params.drawCollisionBoxes=false]
|
|
7008
6927
|
*/
|
|
7009
|
-
constructor({
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
6928
|
+
constructor({
|
|
6929
|
+
source,
|
|
6930
|
+
style: style2,
|
|
6931
|
+
minZoom = 0,
|
|
6932
|
+
opacity = 1,
|
|
6933
|
+
declutter = true,
|
|
6934
|
+
drawCollisionBoxes = false
|
|
6935
|
+
}) {
|
|
6936
|
+
this.source = source;
|
|
6937
|
+
this._style = style2;
|
|
6938
|
+
this.minZoom = minZoom;
|
|
6939
|
+
this.opacity = opacity;
|
|
6940
|
+
this.declutter = declutter;
|
|
6941
|
+
this.drawCollisionBoxes = drawCollisionBoxes;
|
|
6942
|
+
this.renderer = new TextLayerRenderer(this);
|
|
6943
|
+
this.dispatcher = new Dispatcher(this);
|
|
6944
|
+
}
|
|
6945
|
+
tearDown() {
|
|
6946
|
+
this.dispatcher = null;
|
|
6947
|
+
}
|
|
6948
|
+
get style() {
|
|
6949
|
+
if (this._style) return this._style;
|
|
6950
|
+
const defaultStyle = new Style({
|
|
6951
|
+
text: new Text()
|
|
6952
|
+
});
|
|
6953
|
+
return defaultStyle;
|
|
6954
|
+
}
|
|
6955
|
+
set style(style2) {
|
|
6956
|
+
this._style = style2;
|
|
6957
|
+
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
7015
6958
|
}
|
|
7016
6959
|
getExtent() {
|
|
7017
6960
|
if (this._extent) return this._extent;
|
|
7018
|
-
const
|
|
7019
|
-
|
|
7020
|
-
|
|
6961
|
+
const features = this.source.getFeatures();
|
|
6962
|
+
const extent = features.reduce((combinedExtent, feature) => {
|
|
6963
|
+
const featureExtent = feature.getExtent();
|
|
6964
|
+
if (!combinedExtent) return featureExtent;
|
|
6965
|
+
return combineExtents(featureExtent, combinedExtent);
|
|
7021
6966
|
}, null);
|
|
7022
6967
|
this._extent = extent;
|
|
7023
6968
|
return extent;
|
|
7024
6969
|
}
|
|
7025
|
-
setgeometries(geometries) {
|
|
7026
|
-
this.geometries = geometries;
|
|
7027
|
-
this._extent = void 0;
|
|
7028
|
-
}
|
|
7029
|
-
getProjectedGeometries(projection) {
|
|
7030
|
-
return this.geometries.map(
|
|
7031
|
-
(d2) => d2.getProjected(projection, projection.revision)
|
|
7032
|
-
);
|
|
7033
|
-
}
|
|
7034
6970
|
getStyleFunction() {
|
|
7035
6971
|
const style2 = this.style;
|
|
7036
|
-
if (!style2) return null;
|
|
7037
6972
|
if (typeof style2 === "function") return style2;
|
|
7038
6973
|
return () => {
|
|
7039
6974
|
return style2;
|
|
7040
6975
|
};
|
|
7041
6976
|
}
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
6977
|
+
renderFrame(frameState, targetElement) {
|
|
6978
|
+
return this.renderer.renderFrame(frameState, targetElement);
|
|
6979
|
+
}
|
|
6980
|
+
}
|
|
6981
|
+
class VectorLayerRenderer {
|
|
6982
|
+
constructor(layer) {
|
|
6983
|
+
this.layer = layer;
|
|
6984
|
+
this.featureRenderer = new FeatureRenderer();
|
|
6985
|
+
}
|
|
6986
|
+
renderFrame(frameState, targetElement) {
|
|
6987
|
+
if (this.layer.opacity === 0) return targetElement;
|
|
6988
|
+
const { projection, sizeInPixels, visibleExtent, transform } = frameState.viewState;
|
|
6989
|
+
const container2 = this.getOrCreateContainer(targetElement, sizeInPixels);
|
|
6990
|
+
const context = container2.firstElementChild.getContext("2d");
|
|
6991
|
+
context.save();
|
|
6992
|
+
context.translate(transform.x, transform.y);
|
|
6993
|
+
context.scale(transform.k, transform.k);
|
|
6994
|
+
context.lineJoin = "round";
|
|
6995
|
+
context.lineCap = "round";
|
|
6996
|
+
context.globalAlpha = this.layer.opacity;
|
|
6997
|
+
const source = this.layer.source;
|
|
6998
|
+
const features = source.getFeaturesInExtent(visibleExtent);
|
|
6999
|
+
for (const feature of features) {
|
|
7000
|
+
const styleFunction2 = feature.getStyleFunction() || this.layer.getStyleFunction();
|
|
7001
|
+
const featureStyle = styleFunction2(feature);
|
|
7002
|
+
if ((featureStyle == null ? void 0 : featureStyle.stroke) || (featureStyle == null ? void 0 : featureStyle.fill)) {
|
|
7003
|
+
context.save();
|
|
7004
|
+
this.featureRenderer.setStyle(featureStyle);
|
|
7005
|
+
this.featureRenderer.render(frameState, feature, context);
|
|
7006
|
+
context.restore();
|
|
7049
7007
|
}
|
|
7050
7008
|
}
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
}
|
|
7061
|
-
/**
|
|
7062
|
-
* Returns the geometries as a GeoJSON object
|
|
7063
|
-
* @returns {Object} The GeoJSON representation of the geometries
|
|
7064
|
-
*/
|
|
7065
|
-
getGeoJSON() {
|
|
7066
|
-
const geometries = this.geometries.map((d2) => d2.getGeoJSON());
|
|
7067
|
-
if (geometries.length === 1) return geometries[0];
|
|
7068
|
-
return {
|
|
7069
|
-
type: "Feature",
|
|
7070
|
-
geometry: this._getGeometryGeoJSON(),
|
|
7071
|
-
properties: this.properties
|
|
7072
|
-
};
|
|
7009
|
+
if (Object.prototype.hasOwnProperty.call(projection, "getCompositionBorders")) {
|
|
7010
|
+
context.beginPath();
|
|
7011
|
+
context.lineWidth = 1 / transform.k;
|
|
7012
|
+
context.strokeStyle = "#999";
|
|
7013
|
+
projection.drawCompositionBorders(context);
|
|
7014
|
+
context.stroke();
|
|
7015
|
+
}
|
|
7016
|
+
context.restore();
|
|
7017
|
+
return container2;
|
|
7073
7018
|
}
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
if (
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
} else
|
|
7084
|
-
|
|
7085
|
-
type: "MultiLineString",
|
|
7086
|
-
coordinates: geometries.map((d2) => d2.coordinates)
|
|
7087
|
-
};
|
|
7088
|
-
} else if (geometries[0].type === "Point") {
|
|
7089
|
-
return {
|
|
7090
|
-
type: "MultiPoint",
|
|
7091
|
-
coordinates: geometries.map((d2) => d2.coordinates)
|
|
7092
|
-
};
|
|
7019
|
+
getOrCreateContainer(targetElement, sizeInPixels) {
|
|
7020
|
+
let container2 = null;
|
|
7021
|
+
let containerReused = false;
|
|
7022
|
+
let canvas = targetElement && targetElement.firstElementChild;
|
|
7023
|
+
if (canvas instanceof HTMLCanvasElement) {
|
|
7024
|
+
container2 = targetElement;
|
|
7025
|
+
containerReused = true;
|
|
7026
|
+
} else if (this._container) {
|
|
7027
|
+
container2 = this._container;
|
|
7028
|
+
} else {
|
|
7029
|
+
container2 = this.createContainer();
|
|
7093
7030
|
}
|
|
7094
|
-
|
|
7031
|
+
if (!containerReused) {
|
|
7032
|
+
const canvas2 = container2.firstElementChild;
|
|
7033
|
+
canvas2.width = sizeInPixels[0];
|
|
7034
|
+
canvas2.height = sizeInPixels[1];
|
|
7035
|
+
}
|
|
7036
|
+
this._container = container2;
|
|
7037
|
+
return container2;
|
|
7038
|
+
}
|
|
7039
|
+
createContainer() {
|
|
7040
|
+
const container2 = document.createElement("div");
|
|
7041
|
+
container2.className = "gv-map-layer";
|
|
7042
|
+
let style2 = container2.style;
|
|
7043
|
+
style2.position = "absolute";
|
|
7044
|
+
style2.width = "100%";
|
|
7045
|
+
style2.height = "100%";
|
|
7046
|
+
const canvas = document.createElement("canvas");
|
|
7047
|
+
style2 = canvas.style;
|
|
7048
|
+
style2.position = "absolute";
|
|
7049
|
+
style2.width = "100%";
|
|
7050
|
+
style2.height = "100%";
|
|
7051
|
+
container2.appendChild(canvas);
|
|
7052
|
+
return container2;
|
|
7095
7053
|
}
|
|
7096
7054
|
}
|
|
7097
|
-
class
|
|
7098
|
-
/**
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7055
|
+
class VectorLayer {
|
|
7056
|
+
/** @param {VectorLayerComponentProps} props */
|
|
7057
|
+
static Component({
|
|
7058
|
+
features: featureCollection,
|
|
7059
|
+
style: style2,
|
|
7060
|
+
minZoom,
|
|
7061
|
+
opacity,
|
|
7062
|
+
hitDetectionEnabled = true
|
|
7063
|
+
}) {
|
|
7064
|
+
const { registerLayer } = hooks.useContext(MapContext);
|
|
7065
|
+
const layer = hooks.useMemo(
|
|
7066
|
+
() => {
|
|
7067
|
+
const features = featureCollection instanceof FeatureCollection ? featureCollection.features : (
|
|
7068
|
+
/** @type {import("../Feature").Feature[]} */
|
|
7069
|
+
featureCollection
|
|
7070
|
+
);
|
|
7071
|
+
return VectorLayer.with(features, {
|
|
7072
|
+
style: style2,
|
|
7073
|
+
minZoom,
|
|
7074
|
+
opacity,
|
|
7075
|
+
hitDetectionEnabled
|
|
7076
|
+
});
|
|
7077
|
+
},
|
|
7078
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
7079
|
+
[featureCollection, minZoom, opacity, hitDetectionEnabled]
|
|
7080
|
+
);
|
|
7081
|
+
registerLayer(layer);
|
|
7082
|
+
hooks.useEffect(() => {
|
|
7083
|
+
layer.style = style2;
|
|
7084
|
+
}, [style2]);
|
|
7085
|
+
return null;
|
|
7111
7086
|
}
|
|
7112
7087
|
/**
|
|
7113
|
-
*
|
|
7114
|
-
* @
|
|
7115
|
-
* @param {import("../projection").Projection} projection - The projection to use for the geometry
|
|
7116
|
-
* @returns {Object} A GeoJSON representation of the projected geometry
|
|
7117
|
-
* @private
|
|
7088
|
+
* @param {import("../Feature").Feature[]} features
|
|
7089
|
+
* @param {VectorLayerOptions} options
|
|
7118
7090
|
*/
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7091
|
+
static with(features, options) {
|
|
7092
|
+
const source = new VectorSource({ features });
|
|
7093
|
+
return new VectorLayer({ source, ...options });
|
|
7122
7094
|
}
|
|
7123
7095
|
/**
|
|
7124
|
-
*
|
|
7125
|
-
* @
|
|
7096
|
+
* @param {Object} params
|
|
7097
|
+
* @param {VectorSource} params.source
|
|
7098
|
+
* @param {Style | (() => Style)} [params.style=undefined]
|
|
7099
|
+
* @param {number} [params.minZoom=0]
|
|
7100
|
+
* @param {number} [params.opacity=1]
|
|
7101
|
+
* @param {boolean} [params.hitDetectionEnabled=true]
|
|
7126
7102
|
*/
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7103
|
+
constructor({
|
|
7104
|
+
source,
|
|
7105
|
+
style: style2,
|
|
7106
|
+
minZoom = 0,
|
|
7107
|
+
opacity = 1,
|
|
7108
|
+
hitDetectionEnabled = true
|
|
7109
|
+
}) {
|
|
7110
|
+
this.dispatcher = new Dispatcher(this);
|
|
7111
|
+
this.renderer = new VectorLayerRenderer(this);
|
|
7112
|
+
this.source = source;
|
|
7113
|
+
this._style = style2;
|
|
7114
|
+
this.minZoom = minZoom;
|
|
7115
|
+
this.opacity = opacity;
|
|
7116
|
+
this.hitDetectionEnabled = hitDetectionEnabled;
|
|
7132
7117
|
}
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
constructor({ type = "LineString", extent, coordinates }) {
|
|
7136
|
-
super({ type, extent, coordinates });
|
|
7118
|
+
get source() {
|
|
7119
|
+
return this._source;
|
|
7137
7120
|
}
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
projected.push(projection(point));
|
|
7121
|
+
set source(source) {
|
|
7122
|
+
if (this._source && source !== this._source) {
|
|
7123
|
+
this._source.tearDown();
|
|
7142
7124
|
}
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7125
|
+
this._source = source;
|
|
7126
|
+
source.on(MapEvent.CHANGE, () => {
|
|
7127
|
+
this._extent = null;
|
|
7128
|
+
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
7129
|
+
});
|
|
7147
7130
|
}
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
constructor({ type = "Polygon", extent, coordinates }) {
|
|
7151
|
-
super({ type, extent, coordinates });
|
|
7131
|
+
setRawProjection(projection) {
|
|
7132
|
+
this.projection = projection;
|
|
7152
7133
|
}
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
return {
|
|
7171
|
-
|
|
7172
|
-
coordinates: projected
|
|
7134
|
+
tearDown() {
|
|
7135
|
+
this.dispatcher = null;
|
|
7136
|
+
}
|
|
7137
|
+
get style() {
|
|
7138
|
+
if (this._style) return this._style;
|
|
7139
|
+
const defaultStyle = new Style({
|
|
7140
|
+
stroke: new Stroke()
|
|
7141
|
+
});
|
|
7142
|
+
return defaultStyle;
|
|
7143
|
+
}
|
|
7144
|
+
set style(style2) {
|
|
7145
|
+
this._style = style2;
|
|
7146
|
+
this.dispatcher.dispatch(MapEvent.CHANGE);
|
|
7147
|
+
}
|
|
7148
|
+
getStyleFunction() {
|
|
7149
|
+
const style2 = this.style;
|
|
7150
|
+
if (typeof style2 === "function") return style2;
|
|
7151
|
+
return () => {
|
|
7152
|
+
return style2;
|
|
7173
7153
|
};
|
|
7174
7154
|
}
|
|
7175
|
-
|
|
7176
|
-
return this.
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7155
|
+
getExtent() {
|
|
7156
|
+
if (this._extent) return this._extent;
|
|
7157
|
+
const features = this.source.getFeatures();
|
|
7158
|
+
const extent = features.reduce((combinedExtent, feature) => {
|
|
7159
|
+
const featureExtent = feature.getExtent();
|
|
7160
|
+
if (!combinedExtent) return featureExtent;
|
|
7161
|
+
return combineExtents(featureExtent, combinedExtent);
|
|
7162
|
+
}, null);
|
|
7163
|
+
this._extent = extent;
|
|
7164
|
+
return extent;
|
|
7180
7165
|
}
|
|
7181
|
-
|
|
7182
|
-
this.
|
|
7166
|
+
findFeatures(coordinate) {
|
|
7167
|
+
if (!this.hitDetectionEnabled) return;
|
|
7168
|
+
return this.source.getFeaturesAtCoordinate(coordinate);
|
|
7183
7169
|
}
|
|
7184
|
-
|
|
7185
|
-
return
|
|
7186
|
-
extent: this.extent,
|
|
7187
|
-
coordinates: JSON.parse(JSON.stringify(this.coordinates))
|
|
7188
|
-
});
|
|
7170
|
+
renderFrame(frameState, targetElement) {
|
|
7171
|
+
return this.renderer.renderFrame(frameState, targetElement);
|
|
7189
7172
|
}
|
|
7190
7173
|
}
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
_getProjected(projection) {
|
|
7197
|
-
return {
|
|
7198
|
-
type: this.type,
|
|
7199
|
-
coordinates: projection(this.coordinates)
|
|
7200
|
-
};
|
|
7174
|
+
function interpolateFeatures(currentFeatures, newFeatures, { interpolate: interpolate2, separate, combine }) {
|
|
7175
|
+
if (currentFeatures.length !== newFeatures.length) {
|
|
7176
|
+
throw new Error(
|
|
7177
|
+
"interpolateFeatures expects an equal number of features for start and end"
|
|
7178
|
+
);
|
|
7201
7179
|
}
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
const
|
|
7206
|
-
|
|
7207
|
-
if (
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
if (!featureObject) {
|
|
7214
|
-
continue;
|
|
7215
|
-
}
|
|
7216
|
-
features.push(featureObject);
|
|
7217
|
-
}
|
|
7218
|
-
} else if (geoJSONObject["type"] === "Feature") {
|
|
7219
|
-
features = [this.readFeatureFromObject(geoJSONObject)];
|
|
7220
|
-
} else if (Array.isArray(geoJSONObject)) {
|
|
7221
|
-
features = [];
|
|
7222
|
-
for (let i = 0, ii = geoJSONObject.length; i < ii; ++i) {
|
|
7223
|
-
const featureObject = this.readFeatureFromObject(geoJSONObject[i]);
|
|
7224
|
-
if (!featureObject) {
|
|
7225
|
-
continue;
|
|
7180
|
+
const featureInterpolators = [];
|
|
7181
|
+
for (let i = 0; i < currentFeatures.length; i++) {
|
|
7182
|
+
const geometryInterpolators = [];
|
|
7183
|
+
const currentGeometries = currentFeatures[i].geometries;
|
|
7184
|
+
const newGeometries = newFeatures[i].geometries;
|
|
7185
|
+
if (newGeometries.length === currentGeometries.length) {
|
|
7186
|
+
for (let e = 0; e < currentGeometries.length; e++) {
|
|
7187
|
+
const currentGeometry = currentGeometries[e];
|
|
7188
|
+
const newGeometry = newGeometries[e];
|
|
7189
|
+
if (currentGeometry.type !== "Polygon" || newGeometry.type !== "Polygon") {
|
|
7190
|
+
throw new Error("interpolateFeatures expects only Polygon geometry");
|
|
7226
7191
|
}
|
|
7227
|
-
|
|
7192
|
+
const shapeInterpolator = interpolate2(
|
|
7193
|
+
currentGeometries[e].getOuterRing(),
|
|
7194
|
+
newGeometries[e].getOuterRing(),
|
|
7195
|
+
{ string: false }
|
|
7196
|
+
);
|
|
7197
|
+
geometryInterpolators.push({
|
|
7198
|
+
type: "default",
|
|
7199
|
+
interpolator: shapeInterpolator
|
|
7200
|
+
});
|
|
7228
7201
|
}
|
|
7202
|
+
} else if (currentGeometries.length === 1 && newGeometries.length > 1) {
|
|
7203
|
+
const separationInterpolator = separate(
|
|
7204
|
+
currentGeometries[0].getOuterRing(),
|
|
7205
|
+
newGeometries.map((geometry) => geometry.getOuterRing()),
|
|
7206
|
+
{ string: false, single: true }
|
|
7207
|
+
);
|
|
7208
|
+
geometryInterpolators.push({
|
|
7209
|
+
type: "separate",
|
|
7210
|
+
interpolator: separationInterpolator
|
|
7211
|
+
});
|
|
7212
|
+
} else if (currentGeometries.length > 1 && newGeometries.length === 1) {
|
|
7213
|
+
const combinationInterpolator = combine(
|
|
7214
|
+
currentGeometries.map((geometry) => geometry.getOuterRing()),
|
|
7215
|
+
newGeometries[0].getOuterRing(),
|
|
7216
|
+
{ string: false, single: true }
|
|
7217
|
+
);
|
|
7218
|
+
geometryInterpolators.push({
|
|
7219
|
+
type: "combine",
|
|
7220
|
+
interpolator: combinationInterpolator
|
|
7221
|
+
});
|
|
7229
7222
|
} else {
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
features = [feature];
|
|
7234
|
-
} catch {
|
|
7235
|
-
console.warn("Unable to interpret GeoJSON:", geoJSONObject);
|
|
7236
|
-
return;
|
|
7237
|
-
}
|
|
7223
|
+
throw new Error(
|
|
7224
|
+
`Encountered an unexpected number of geometries: ${currentGeometries.length} and ${newGeometries.length}`
|
|
7225
|
+
);
|
|
7238
7226
|
}
|
|
7239
|
-
|
|
7227
|
+
featureInterpolators.push(geometryInterpolators);
|
|
7240
7228
|
}
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
return new Feature({
|
|
7245
|
-
id: geoJSONObject["id"],
|
|
7246
|
-
geometries,
|
|
7247
|
-
properties: geoJSONObject["properties"]
|
|
7248
|
-
});
|
|
7229
|
+
return (t) => {
|
|
7230
|
+
if (t >= 1) {
|
|
7231
|
+
return newFeatures;
|
|
7249
7232
|
}
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
const
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7233
|
+
const features = [];
|
|
7234
|
+
for (let i = 0; i < featureInterpolators.length; i++) {
|
|
7235
|
+
const feature = newFeatures[i].clone();
|
|
7236
|
+
const geometries = [];
|
|
7237
|
+
const geometryInterpolators = featureInterpolators[i];
|
|
7238
|
+
for (const [
|
|
7239
|
+
index,
|
|
7240
|
+
{ type, interpolator }
|
|
7241
|
+
] of geometryInterpolators.entries()) {
|
|
7242
|
+
let geometry = feature.geometries[index].clone();
|
|
7243
|
+
let interpolated;
|
|
7244
|
+
switch (type) {
|
|
7245
|
+
case "separate":
|
|
7246
|
+
case "combine":
|
|
7247
|
+
interpolated = interpolator(t);
|
|
7248
|
+
interpolated.forEach((d2) => {
|
|
7249
|
+
const polygon = geometry.clone();
|
|
7250
|
+
polygon.setCoordinates([d2]);
|
|
7251
|
+
geometries.push(polygon);
|
|
7252
|
+
});
|
|
7253
|
+
break;
|
|
7254
|
+
default:
|
|
7255
|
+
geometry.setOuterRing(interpolator(t));
|
|
7256
|
+
geometries.push(geometry);
|
|
7257
|
+
break;
|
|
7258
|
+
}
|
|
7271
7259
|
}
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
geometries.push(point);
|
|
7260
|
+
feature.setGeometry(geometries);
|
|
7261
|
+
features.push(feature);
|
|
7275
7262
|
}
|
|
7276
|
-
return
|
|
7277
|
-
}
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7263
|
+
return features;
|
|
7264
|
+
};
|
|
7265
|
+
}
|
|
7266
|
+
function interpolateStyles(firstStyle, secondStyle, interpolateColors, interpolateNumbers) {
|
|
7267
|
+
const fillInterpolator = interpolateFill(
|
|
7268
|
+
firstStyle.fill,
|
|
7269
|
+
secondStyle.fill,
|
|
7270
|
+
interpolateColors,
|
|
7271
|
+
interpolateNumbers
|
|
7272
|
+
);
|
|
7273
|
+
const strokeInterpolator = interpolateStroke(
|
|
7274
|
+
firstStyle.stroke,
|
|
7275
|
+
secondStyle.stroke,
|
|
7276
|
+
interpolateColors,
|
|
7277
|
+
interpolateNumbers
|
|
7278
|
+
);
|
|
7279
|
+
return (t) => {
|
|
7280
|
+
return new Style({
|
|
7281
|
+
fill: fillInterpolator(t),
|
|
7282
|
+
stroke: strokeInterpolator(t)
|
|
7283
|
+
});
|
|
7284
|
+
};
|
|
7285
|
+
}
|
|
7286
|
+
function interpolateFill(fillA, fillB, interpolateColors, interpolateNumbers) {
|
|
7287
|
+
const colorInterpolator = interpolateColors(
|
|
7288
|
+
(fillA == null ? void 0 : fillA.color) ?? "transparent",
|
|
7289
|
+
(fillB == null ? void 0 : fillB.color) ?? "transparent"
|
|
7290
|
+
);
|
|
7291
|
+
const opacityInterpolator = interpolateNumbers(
|
|
7292
|
+
(fillA == null ? void 0 : fillA.opacity) ?? 1,
|
|
7293
|
+
(fillB == null ? void 0 : fillB.opacity) ?? 1
|
|
7294
|
+
);
|
|
7295
|
+
return (t) => {
|
|
7296
|
+
return new Fill({
|
|
7297
|
+
color: colorInterpolator(t),
|
|
7298
|
+
opacity: opacityInterpolator(t)
|
|
7299
|
+
});
|
|
7300
|
+
};
|
|
7301
|
+
}
|
|
7302
|
+
function interpolateStroke(strokeA, strokeB, interpolateColors, interpolateNumbers) {
|
|
7303
|
+
const colorInterpolator = interpolateColors(
|
|
7304
|
+
(strokeA == null ? void 0 : strokeA.color) ?? "transparent",
|
|
7305
|
+
(strokeB == null ? void 0 : strokeB.color) ?? "transparent"
|
|
7306
|
+
);
|
|
7307
|
+
const opacityInterpolator = interpolateNumbers(
|
|
7308
|
+
(strokeA == null ? void 0 : strokeA.opacity) ?? 1,
|
|
7309
|
+
(strokeB == null ? void 0 : strokeB.opacity) ?? 1
|
|
7310
|
+
);
|
|
7311
|
+
const widthInterpolator = interpolateNumbers(
|
|
7312
|
+
(strokeA == null ? void 0 : strokeA.width) ?? 1,
|
|
7313
|
+
(strokeB == null ? void 0 : strokeB.width) ?? 1
|
|
7314
|
+
);
|
|
7315
|
+
return (t) => {
|
|
7316
|
+
return new Stroke({
|
|
7317
|
+
color: colorInterpolator(t),
|
|
7318
|
+
opacity: opacityInterpolator(t),
|
|
7319
|
+
width: widthInterpolator(t)
|
|
7320
|
+
});
|
|
7321
|
+
};
|
|
7290
7322
|
}
|
|
7291
7323
|
function useWindowSize() {
|
|
7292
7324
|
const [windowSize, setWindowSize] = hooks.useState(() => {
|
|
@@ -7725,6 +7757,8 @@
|
|
|
7725
7757
|
exports2.ControlChange = ControlChange;
|
|
7726
7758
|
exports2.Dispatcher = Dispatcher;
|
|
7727
7759
|
exports2.Dropdown = Dropdown;
|
|
7760
|
+
exports2.Feature = Feature;
|
|
7761
|
+
exports2.FeatureCollection = FeatureCollection;
|
|
7728
7762
|
exports2.Fill = Fill;
|
|
7729
7763
|
exports2.FirstPastThePostWaffle = FirstPastThePostWaffle;
|
|
7730
7764
|
exports2.GeoJSON = GeoJSON;
|