stipple-maplibre 0.2.0 → 0.3.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/README.md +25 -7
- package/dist/index.d.ts +33 -2
- package/dist/index.global.js +78 -0
- package/dist/index.js +78 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ and provides the corresponding `fill-pattern` value.
|
|
|
66
66
|
</td>
|
|
67
67
|
<td align="center" width="25%">
|
|
68
68
|
<img src="./assets/readme/example-custom-svg.png" alt="Polygon filled with a custom SVG motif" width="100%"><br>
|
|
69
|
-
<sub><em>
|
|
69
|
+
<sub><em>Custom</em></sub>
|
|
70
70
|
</td>
|
|
71
71
|
</tr>
|
|
72
72
|
</table>
|
|
@@ -227,12 +227,30 @@ The playground can export:
|
|
|
227
227
|
|
|
228
228
|
- ready-to-use MapLibre code;
|
|
229
229
|
- a reusable Stipple configuration;
|
|
230
|
-
- a
|
|
231
|
-
|
|
230
|
+
- a static bundle containing style layers, generated pattern images, and an
|
|
231
|
+
integration helper.
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
The copied code uses `addPatternFill`, which waits for the map style, installs
|
|
234
|
+
the generated textures, adapts the exported layers to an existing source, and
|
|
235
|
+
adds them in order:
|
|
236
|
+
|
|
237
|
+
```js
|
|
238
|
+
import { addPatternFill } from "stipple-maplibre";
|
|
239
|
+
|
|
240
|
+
await addPatternFill(map, {
|
|
241
|
+
sourceId: "my-polygons",
|
|
242
|
+
sourceLayer: null, // Use the source-layer name for vector tiles.
|
|
243
|
+
pattern: exportedPattern,
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The source must already exist in the map. An optional `beforeId` places the
|
|
248
|
+
pattern layers below an existing label or symbol layer. The returned
|
|
249
|
+
`layerIds` list contains every layer added to the map.
|
|
250
|
+
|
|
251
|
+
For lower-level, code-driven styles, `buildStyleFragment` creates the
|
|
252
|
+
background, pattern, and outline layers together. The resulting style metadata
|
|
253
|
+
carries the pattern recipe. `installPatternFills` reads those recipes and
|
|
236
254
|
installs every texture the map needs:
|
|
237
255
|
|
|
238
256
|
```js
|
|
@@ -321,7 +339,7 @@ in Node.
|
|
|
321
339
|
|
|
322
340
|
## Project status
|
|
323
341
|
|
|
324
|
-
Version `0.
|
|
342
|
+
Version `0.3.0` is available on
|
|
325
343
|
[npm](https://www.npmjs.com/package/stipple-maplibre). The whole-symbol
|
|
326
344
|
scatter API is the only part currently marked experimental.
|
|
327
345
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Map } from 'maplibre-gl';
|
|
1
|
+
import { Map, LayerSpecification } from 'maplibre-gl';
|
|
2
2
|
|
|
3
3
|
type PatternType = "solid" | "stipple" | "hachures" | "cross" | "grid" | "dots";
|
|
4
4
|
/** Tile edge length in px. MapLibre does not require power-of-two fill-pattern images. Larger tiles read as a lower-density pattern. */
|
|
@@ -396,6 +396,37 @@ interface StyleLike {
|
|
|
396
396
|
*/
|
|
397
397
|
declare function installPatternFills(map: Map, style: StyleLike): Promise<void>;
|
|
398
398
|
|
|
399
|
+
interface PatternFillLayerTemplate {
|
|
400
|
+
id: string;
|
|
401
|
+
type: LayerSpecification["type"];
|
|
402
|
+
metadata?: Record<string, unknown>;
|
|
403
|
+
[key: string]: unknown;
|
|
404
|
+
}
|
|
405
|
+
interface PatternFillFragment {
|
|
406
|
+
layers: PatternFillLayerTemplate[];
|
|
407
|
+
}
|
|
408
|
+
interface AddPatternFillOptions {
|
|
409
|
+
/** Id of a source that already exists in the map. */
|
|
410
|
+
sourceId: string;
|
|
411
|
+
/** Omit or use null for GeoJSON. Required for vector tile sources. */
|
|
412
|
+
sourceLayer?: string | null;
|
|
413
|
+
/** Insert every generated layer immediately before this existing layer. */
|
|
414
|
+
beforeId?: string;
|
|
415
|
+
/** Source-neutral layer templates exported by Stipple. */
|
|
416
|
+
pattern: PatternFillFragment;
|
|
417
|
+
}
|
|
418
|
+
interface AddedPatternFill {
|
|
419
|
+
layerIds: string[];
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Installs a Stipple pattern export on an existing MapLibre source.
|
|
423
|
+
*
|
|
424
|
+
* The helper waits for the style, resolves the source placeholders, installs
|
|
425
|
+
* every generated texture, then adds the exported background, fill, and
|
|
426
|
+
* outline layers in order.
|
|
427
|
+
*/
|
|
428
|
+
declare function addPatternFill(map: Map, options: AddPatternFillOptions): Promise<AddedPatternFill>;
|
|
429
|
+
|
|
399
430
|
interface ObservePatternFillsOptions {
|
|
400
431
|
/** Defaults to `map.getStyle()`. Useful when metadata is stored separately. */
|
|
401
432
|
getStyle?: () => StyleLike;
|
|
@@ -602,4 +633,4 @@ interface InstallSvgIconScatterOptions {
|
|
|
602
633
|
*/
|
|
603
634
|
declare function installSvgIconScatter(map: Map, options: InstallSvgIconScatterOptions): Promise<void>;
|
|
604
635
|
|
|
605
|
-
export { type BackgroundFillConfig, type BuildStyleFragmentOptions, type FontPatternDefinition, type FontPatternOptions, type GeoJsonPolygonImport, type GeometricPatternDefinition, type GeometricPatternType, type HachureAngle, type IconScaleMode, type ImportedPolygonFeature, type InstallSvgIconScatterOptions, type MakeTileOptions, type ObservePatternFillsOptions, type OutlineConfig, PATTERN_METADATA_KEY, type PatternDefinition, type PatternFillConfig, type PatternFillObserver, type PatternMetadataV1, type PatternScaleMode, type PatternScaleOptions, type PatternScaleResult, type PatternType, type PatternVariant, type PointFeature, type PointFeatureCollection, type PolygonGeometry, type Ring, type ScatterIconPointsOptions, type ScatterPointsOptions, type ScatteredPoint, type ScreenPatternPhase, type StyleLike, type SvgDistributionMode, type SvgPatternDefinition, type SvgPatternOptions, type SvgScatterLayoutOptions, type SvgStampPlacement, type SyncPatternTextureOptions, type TileContext, type TileImage, type TileSize, buildStyleFragment, createFontPatternDefinition, createFontPatternTile, createMiniContext, createSvgPatternDefinition, createSvgScatterLayout, createSvgScatterTile, hashStringToSeed, importGeoJsonPolygons, installFontPatternFill, installPatternFills, installSvgIconScatter, installSvgPatternFill, makeTile, mulberry32, observePatternFills, parsePatternDefinition, parsePatternMetadata, patternDefinitionId, scalePatternForZoom, scatterIconPoints, scatterPointsInPolygon, screenPatternPhase, serializePatternDefinition, syncPatternTexture };
|
|
636
|
+
export { type AddPatternFillOptions, type AddedPatternFill, type BackgroundFillConfig, type BuildStyleFragmentOptions, type FontPatternDefinition, type FontPatternOptions, type GeoJsonPolygonImport, type GeometricPatternDefinition, type GeometricPatternType, type HachureAngle, type IconScaleMode, type ImportedPolygonFeature, type InstallSvgIconScatterOptions, type MakeTileOptions, type ObservePatternFillsOptions, type OutlineConfig, PATTERN_METADATA_KEY, type PatternDefinition, type PatternFillConfig, type PatternFillFragment, type PatternFillLayerTemplate, type PatternFillObserver, type PatternMetadataV1, type PatternScaleMode, type PatternScaleOptions, type PatternScaleResult, type PatternType, type PatternVariant, type PointFeature, type PointFeatureCollection, type PolygonGeometry, type Ring, type ScatterIconPointsOptions, type ScatterPointsOptions, type ScatteredPoint, type ScreenPatternPhase, type StyleLike, type SvgDistributionMode, type SvgPatternDefinition, type SvgPatternOptions, type SvgScatterLayoutOptions, type SvgStampPlacement, type SyncPatternTextureOptions, type TileContext, type TileImage, type TileSize, addPatternFill, buildStyleFragment, createFontPatternDefinition, createFontPatternTile, createMiniContext, createSvgPatternDefinition, createSvgScatterLayout, createSvgScatterTile, hashStringToSeed, importGeoJsonPolygons, installFontPatternFill, installPatternFills, installSvgIconScatter, installSvgPatternFill, makeTile, mulberry32, observePatternFills, parsePatternDefinition, parsePatternMetadata, patternDefinitionId, scalePatternForZoom, scatterIconPoints, scatterPointsInPolygon, screenPatternPhase, serializePatternDefinition, syncPatternTexture };
|
package/dist/index.global.js
CHANGED
|
@@ -22,6 +22,7 @@ var MaplibrePatternFills = (() => {
|
|
|
22
22
|
var src_exports = {};
|
|
23
23
|
__export(src_exports, {
|
|
24
24
|
PATTERN_METADATA_KEY: () => PATTERN_METADATA_KEY,
|
|
25
|
+
addPatternFill: () => addPatternFill,
|
|
25
26
|
buildStyleFragment: () => buildStyleFragment,
|
|
26
27
|
createFontPatternDefinition: () => createFontPatternDefinition,
|
|
27
28
|
createFontPatternTile: () => createFontPatternTile,
|
|
@@ -1480,6 +1481,83 @@ var MaplibrePatternFills = (() => {
|
|
|
1480
1481
|
await Promise.all(pending);
|
|
1481
1482
|
}
|
|
1482
1483
|
|
|
1484
|
+
// src/maplibre/addPatternFill.ts
|
|
1485
|
+
function nonEmptyString2(value, name) {
|
|
1486
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1487
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
async function waitForStyle(map) {
|
|
1491
|
+
if (map.getStyle()) return;
|
|
1492
|
+
await new Promise((resolve) => {
|
|
1493
|
+
map.once("style.load", () => resolve());
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
async function addPatternFill(map, options) {
|
|
1497
|
+
nonEmptyString2(options.sourceId, "sourceId");
|
|
1498
|
+
if (options.sourceLayer !== void 0 && options.sourceLayer !== null) {
|
|
1499
|
+
nonEmptyString2(options.sourceLayer, "sourceLayer");
|
|
1500
|
+
}
|
|
1501
|
+
if (options.beforeId !== void 0) {
|
|
1502
|
+
nonEmptyString2(options.beforeId, "beforeId");
|
|
1503
|
+
}
|
|
1504
|
+
if (!options.pattern || !Array.isArray(options.pattern.layers)) {
|
|
1505
|
+
throw new TypeError("pattern.layers must be an array");
|
|
1506
|
+
}
|
|
1507
|
+
if (options.pattern.layers.length === 0) {
|
|
1508
|
+
throw new RangeError("pattern.layers must contain at least one layer");
|
|
1509
|
+
}
|
|
1510
|
+
await waitForStyle(map);
|
|
1511
|
+
if (!map.getSource(options.sourceId)) {
|
|
1512
|
+
throw new Error(`MapLibre source "${options.sourceId}" was not found`);
|
|
1513
|
+
}
|
|
1514
|
+
if (options.beforeId && !map.getLayer(options.beforeId)) {
|
|
1515
|
+
throw new Error(`MapLibre layer "${options.beforeId}" was not found`);
|
|
1516
|
+
}
|
|
1517
|
+
const layers = options.pattern.layers.map((template, index) => {
|
|
1518
|
+
if (!template || typeof template !== "object") {
|
|
1519
|
+
throw new TypeError(`pattern.layers[${index}] must be an object`);
|
|
1520
|
+
}
|
|
1521
|
+
nonEmptyString2(template.id, `pattern.layers[${index}].id`);
|
|
1522
|
+
nonEmptyString2(template.type, `pattern.layers[${index}].type`);
|
|
1523
|
+
const layer = {
|
|
1524
|
+
...template,
|
|
1525
|
+
id: template.id.split("<source>").join(options.sourceId),
|
|
1526
|
+
source: options.sourceId
|
|
1527
|
+
};
|
|
1528
|
+
if (options.sourceLayer === void 0 || options.sourceLayer === null) {
|
|
1529
|
+
delete layer["source-layer"];
|
|
1530
|
+
} else {
|
|
1531
|
+
layer["source-layer"] = options.sourceLayer;
|
|
1532
|
+
}
|
|
1533
|
+
return layer;
|
|
1534
|
+
});
|
|
1535
|
+
const layerIds = layers.map((layer) => layer.id);
|
|
1536
|
+
const uniqueIds = new Set(layerIds);
|
|
1537
|
+
if (uniqueIds.size !== layerIds.length) {
|
|
1538
|
+
throw new Error("Pattern fill contains duplicate layer ids");
|
|
1539
|
+
}
|
|
1540
|
+
for (const layerId of layerIds) {
|
|
1541
|
+
if (map.getLayer(layerId)) {
|
|
1542
|
+
throw new Error(`MapLibre layer "${layerId}" already exists`);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
await installPatternFills(map, { layers });
|
|
1546
|
+
const addedLayerIds = [];
|
|
1547
|
+
try {
|
|
1548
|
+
for (const layer of layers) {
|
|
1549
|
+
map.addLayer(layer, options.beforeId);
|
|
1550
|
+
addedLayerIds.push(layer.id);
|
|
1551
|
+
}
|
|
1552
|
+
} catch (error) {
|
|
1553
|
+
for (const layerId of addedLayerIds.reverse()) {
|
|
1554
|
+
if (map.getLayer(layerId)) map.removeLayer(layerId);
|
|
1555
|
+
}
|
|
1556
|
+
throw error;
|
|
1557
|
+
}
|
|
1558
|
+
return { layerIds };
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1483
1561
|
// src/maplibre/observePatternFills.ts
|
|
1484
1562
|
function observePatternFills(map, options = {}) {
|
|
1485
1563
|
const getStyle = options.getStyle ?? (() => map.getStyle());
|
package/dist/index.js
CHANGED
|
@@ -1429,6 +1429,83 @@ async function installPatternFills(map, style) {
|
|
|
1429
1429
|
await Promise.all(pending);
|
|
1430
1430
|
}
|
|
1431
1431
|
|
|
1432
|
+
// src/maplibre/addPatternFill.ts
|
|
1433
|
+
function nonEmptyString2(value, name) {
|
|
1434
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1435
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
async function waitForStyle(map) {
|
|
1439
|
+
if (map.getStyle()) return;
|
|
1440
|
+
await new Promise((resolve) => {
|
|
1441
|
+
map.once("style.load", () => resolve());
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
async function addPatternFill(map, options) {
|
|
1445
|
+
nonEmptyString2(options.sourceId, "sourceId");
|
|
1446
|
+
if (options.sourceLayer !== void 0 && options.sourceLayer !== null) {
|
|
1447
|
+
nonEmptyString2(options.sourceLayer, "sourceLayer");
|
|
1448
|
+
}
|
|
1449
|
+
if (options.beforeId !== void 0) {
|
|
1450
|
+
nonEmptyString2(options.beforeId, "beforeId");
|
|
1451
|
+
}
|
|
1452
|
+
if (!options.pattern || !Array.isArray(options.pattern.layers)) {
|
|
1453
|
+
throw new TypeError("pattern.layers must be an array");
|
|
1454
|
+
}
|
|
1455
|
+
if (options.pattern.layers.length === 0) {
|
|
1456
|
+
throw new RangeError("pattern.layers must contain at least one layer");
|
|
1457
|
+
}
|
|
1458
|
+
await waitForStyle(map);
|
|
1459
|
+
if (!map.getSource(options.sourceId)) {
|
|
1460
|
+
throw new Error(`MapLibre source "${options.sourceId}" was not found`);
|
|
1461
|
+
}
|
|
1462
|
+
if (options.beforeId && !map.getLayer(options.beforeId)) {
|
|
1463
|
+
throw new Error(`MapLibre layer "${options.beforeId}" was not found`);
|
|
1464
|
+
}
|
|
1465
|
+
const layers = options.pattern.layers.map((template, index) => {
|
|
1466
|
+
if (!template || typeof template !== "object") {
|
|
1467
|
+
throw new TypeError(`pattern.layers[${index}] must be an object`);
|
|
1468
|
+
}
|
|
1469
|
+
nonEmptyString2(template.id, `pattern.layers[${index}].id`);
|
|
1470
|
+
nonEmptyString2(template.type, `pattern.layers[${index}].type`);
|
|
1471
|
+
const layer = {
|
|
1472
|
+
...template,
|
|
1473
|
+
id: template.id.split("<source>").join(options.sourceId),
|
|
1474
|
+
source: options.sourceId
|
|
1475
|
+
};
|
|
1476
|
+
if (options.sourceLayer === void 0 || options.sourceLayer === null) {
|
|
1477
|
+
delete layer["source-layer"];
|
|
1478
|
+
} else {
|
|
1479
|
+
layer["source-layer"] = options.sourceLayer;
|
|
1480
|
+
}
|
|
1481
|
+
return layer;
|
|
1482
|
+
});
|
|
1483
|
+
const layerIds = layers.map((layer) => layer.id);
|
|
1484
|
+
const uniqueIds = new Set(layerIds);
|
|
1485
|
+
if (uniqueIds.size !== layerIds.length) {
|
|
1486
|
+
throw new Error("Pattern fill contains duplicate layer ids");
|
|
1487
|
+
}
|
|
1488
|
+
for (const layerId of layerIds) {
|
|
1489
|
+
if (map.getLayer(layerId)) {
|
|
1490
|
+
throw new Error(`MapLibre layer "${layerId}" already exists`);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
await installPatternFills(map, { layers });
|
|
1494
|
+
const addedLayerIds = [];
|
|
1495
|
+
try {
|
|
1496
|
+
for (const layer of layers) {
|
|
1497
|
+
map.addLayer(layer, options.beforeId);
|
|
1498
|
+
addedLayerIds.push(layer.id);
|
|
1499
|
+
}
|
|
1500
|
+
} catch (error) {
|
|
1501
|
+
for (const layerId of addedLayerIds.reverse()) {
|
|
1502
|
+
if (map.getLayer(layerId)) map.removeLayer(layerId);
|
|
1503
|
+
}
|
|
1504
|
+
throw error;
|
|
1505
|
+
}
|
|
1506
|
+
return { layerIds };
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1432
1509
|
// src/maplibre/observePatternFills.ts
|
|
1433
1510
|
function observePatternFills(map, options = {}) {
|
|
1434
1511
|
const getStyle = options.getStyle ?? (() => map.getStyle());
|
|
@@ -1734,6 +1811,7 @@ async function installSvgIconScatter(map, options) {
|
|
|
1734
1811
|
}
|
|
1735
1812
|
export {
|
|
1736
1813
|
PATTERN_METADATA_KEY,
|
|
1814
|
+
addPatternFill,
|
|
1737
1815
|
buildStyleFragment,
|
|
1738
1816
|
createFontPatternDefinition,
|
|
1739
1817
|
createFontPatternTile,
|
package/package.json
CHANGED