@mailwoman/cartographer 1.0.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 +3 -0
- package/base/buildings.ts +124 -0
- package/base/composition.ts +119 -0
- package/base/index.ts +10 -0
- package/base/layers.ts +52 -0
- package/base/terrain.ts +33 -0
- package/base/theme.ts +118 -0
- package/bdc/index.ts +395 -0
- package/coverage/index.ts +89 -0
- package/hspa/index.ts +20 -0
- package/index.ts +12 -0
- package/out/base/buildings.d.ts +11 -0
- package/out/base/buildings.d.ts.map +1 -0
- package/out/base/buildings.js +109 -0
- package/out/base/buildings.js.map +1 -0
- package/out/base/composition.d.ts +33 -0
- package/out/base/composition.d.ts.map +1 -0
- package/out/base/composition.js +86 -0
- package/out/base/composition.js.map +1 -0
- package/out/base/index.d.ts +10 -0
- package/out/base/index.d.ts.map +1 -0
- package/out/base/index.js +10 -0
- package/out/base/index.js.map +1 -0
- package/out/base/layers.d.ts +9 -0
- package/out/base/layers.d.ts.map +1 -0
- package/out/base/layers.js +49 -0
- package/out/base/layers.js.map +1 -0
- package/out/base/terrain.d.ts +20 -0
- package/out/base/terrain.d.ts.map +1 -0
- package/out/base/terrain.js +29 -0
- package/out/base/terrain.js.map +1 -0
- package/out/base/theme.d.ts +20 -0
- package/out/base/theme.d.ts.map +1 -0
- package/out/base/theme.js +103 -0
- package/out/base/theme.js.map +1 -0
- package/out/bdc/index.d.ts +27 -0
- package/out/bdc/index.d.ts.map +1 -0
- package/out/bdc/index.js +344 -0
- package/out/bdc/index.js.map +1 -0
- package/out/coverage/index.d.ts +58 -0
- package/out/coverage/index.d.ts.map +1 -0
- package/out/coverage/index.js +77 -0
- package/out/coverage/index.js.map +1 -0
- package/out/hspa/index.d.ts +12 -0
- package/out/hspa/index.d.ts.map +1 -0
- package/out/hspa/index.js +18 -0
- package/out/hspa/index.js.map +1 -0
- package/out/index.d.ts +12 -0
- package/out/index.d.ts.map +1 -0
- package/out/index.js +12 -0
- package/out/index.js.map +1 -0
- package/out/race-dots/index.d.ts +61 -0
- package/out/race-dots/index.d.ts.map +1 -0
- package/out/race-dots/index.js +59 -0
- package/out/race-dots/index.js.map +1 -0
- package/out/styles/index.d.ts +8 -0
- package/out/styles/index.d.ts.map +1 -0
- package/out/styles/index.js +8 -0
- package/out/styles/index.js.map +1 -0
- package/out/styles/layers.d.ts +33 -0
- package/out/styles/layers.d.ts.map +1 -0
- package/out/styles/layers.js +108 -0
- package/out/styles/layers.js.map +1 -0
- package/out/styles/sources.d.ts +22 -0
- package/out/styles/sources.d.ts.map +1 -0
- package/out/styles/sources.js +12 -0
- package/out/styles/sources.js.map +1 -0
- package/out/tiger/index.d.ts +11 -0
- package/out/tiger/index.d.ts.map +1 -0
- package/out/tiger/index.js +64 -0
- package/out/tiger/index.js.map +1 -0
- package/out/tiles/api.d.ts +20 -0
- package/out/tiles/api.d.ts.map +1 -0
- package/out/tiles/api.js +41 -0
- package/out/tiles/api.js.map +1 -0
- package/out/tiles/coords.d.ts +16 -0
- package/out/tiles/coords.d.ts.map +1 -0
- package/out/tiles/coords.js +34 -0
- package/out/tiles/coords.js.map +1 -0
- package/out/tiles/index.d.ts +9 -0
- package/out/tiles/index.d.ts.map +1 -0
- package/out/tiles/index.js +9 -0
- package/out/tiles/index.js.map +1 -0
- package/out/tiles/schema.d.ts +41 -0
- package/out/tiles/schema.d.ts.map +1 -0
- package/out/tiles/schema.js +7 -0
- package/out/tiles/schema.js.map +1 -0
- package/out/tsconfig.tsbuildinfo +1 -0
- package/package.json +46 -0
- package/race-dots/index.ts +68 -0
- package/styles/index.ts +8 -0
- package/styles/layers.ts +148 -0
- package/styles/sources.ts +26 -0
- package/tiger/index.ts +71 -0
- package/tiles/api.ts +53 -0
- package/tiles/coords.ts +46 -0
- package/tiles/index.ts +9 -0
- package/tiles/schema.ts +42 -0
- package/tsconfig.json +22 -0
- package/typedoc.json +4 -0
package/bdc/index.ts
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software.
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { TIGERLevel } from "@mailwoman/tiger"
|
|
8
|
+
import {
|
|
9
|
+
type CircleLayerSpecification,
|
|
10
|
+
type FillExtrusionLayerSpecification,
|
|
11
|
+
type FillLayerSpecification,
|
|
12
|
+
type HeatmapLayerSpecification,
|
|
13
|
+
type LineLayerSpecification,
|
|
14
|
+
type SymbolLayerSpecification,
|
|
15
|
+
} from "@maplibre/maplibre-gl-style-spec"
|
|
16
|
+
import { interpolateTurbo } from "d3-scale-chromatic"
|
|
17
|
+
import { type LayerSpecificationListInput } from "../styles/layers.js"
|
|
18
|
+
import { TileSetSourceID } from "../styles/sources.js"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Identifier for the Broadband Data Collection tile set.
|
|
22
|
+
*/
|
|
23
|
+
export const BDCTileSetID = TileSetSourceID("bdc")
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Broadband Data Collection layer specifications.
|
|
27
|
+
*
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export type BDCLayerSpecificationInput = LayerSpecificationListInput<
|
|
31
|
+
| FillLayerSpecification
|
|
32
|
+
| LineLayerSpecification
|
|
33
|
+
| CircleLayerSpecification
|
|
34
|
+
| HeatmapLayerSpecification
|
|
35
|
+
| SymbolLayerSpecification
|
|
36
|
+
| FillExtrusionLayerSpecification
|
|
37
|
+
>
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Base specification for a Broadband Data Collection layer.
|
|
41
|
+
*
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export type BaseBDCLayerSpecification<T> = T extends BDCLayerSpecificationInput
|
|
45
|
+
? Omit<T, "source-layer" | "source">
|
|
46
|
+
: never
|
|
47
|
+
|
|
48
|
+
function createBDCBlockLayer<T extends BDCLayerSpecificationInput>(spec: BaseBDCLayerSpecification<T>): T {
|
|
49
|
+
return {
|
|
50
|
+
...spec,
|
|
51
|
+
id: `bdc_${TIGERLevel.Block}_${spec.id}`,
|
|
52
|
+
source: BDCTileSetID,
|
|
53
|
+
"source-layer": `bdc_${TIGERLevel.Block}`,
|
|
54
|
+
minzoom: 12,
|
|
55
|
+
} as unknown as T
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createBDCTractLayer<T extends BDCLayerSpecificationInput>(spec: BaseBDCLayerSpecification<T>): T {
|
|
59
|
+
return {
|
|
60
|
+
...spec,
|
|
61
|
+
id: `bdc_${TIGERLevel.Tract}_${spec.id}`,
|
|
62
|
+
source: BDCTileSetID,
|
|
63
|
+
"source-layer": `bdc_${TIGERLevel.Tract}`,
|
|
64
|
+
maxzoom: 12,
|
|
65
|
+
minzoom: 9,
|
|
66
|
+
} as unknown as T
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function createBDCCountyLayer<T extends BDCLayerSpecificationInput>(spec: BaseBDCLayerSpecification<T>): T {
|
|
70
|
+
return {
|
|
71
|
+
...spec,
|
|
72
|
+
id: `bdc_${TIGERLevel.County}_${spec.id}`,
|
|
73
|
+
source: BDCTileSetID,
|
|
74
|
+
"source-layer": `bdc_${TIGERLevel.County}`,
|
|
75
|
+
maxzoom: 9,
|
|
76
|
+
minzoom: 2,
|
|
77
|
+
} as unknown as T
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createBDCLayer<T extends BDCLayerSpecificationInput>(spec: BaseBDCLayerSpecification<T>): T[] {
|
|
81
|
+
return [createBDCBlockLayer(spec), createBDCTractLayer(spec), createBDCCountyLayer(spec)] as T[]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const GIGABIT_BROADBAND_SPEED = 1000
|
|
85
|
+
|
|
86
|
+
export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
|
|
87
|
+
{
|
|
88
|
+
afterID: "earth",
|
|
89
|
+
// metadata: {
|
|
90
|
+
// queryable: false,
|
|
91
|
+
// },
|
|
92
|
+
id: "blocks-underserved",
|
|
93
|
+
layout: {
|
|
94
|
+
visibility: "none",
|
|
95
|
+
},
|
|
96
|
+
"source-layer": `bdc_${TIGERLevel.Block}`,
|
|
97
|
+
source: BDCTileSetID,
|
|
98
|
+
type: "fill",
|
|
99
|
+
filter: [
|
|
100
|
+
// ---
|
|
101
|
+
"all",
|
|
102
|
+
["in", 50, ["get", "technology_codes"]], // Fiber only
|
|
103
|
+
[">", ["get", "land_area_sqm"], 0],
|
|
104
|
+
// ["==", ["get", "UR"], "R"],
|
|
105
|
+
],
|
|
106
|
+
paint: {
|
|
107
|
+
// "fill-extrusion-height": [
|
|
108
|
+
// // Our extrusion height represents the magnitude of broadband underservice,
|
|
109
|
+
// // e.g. How many people are underserved per square meter of land area.
|
|
110
|
+
// "let",
|
|
111
|
+
// "population_density",
|
|
112
|
+
// ["/", ["to-number", ["get", "population"]], ["to-number", ["get", "land_area_sqm"]]],
|
|
113
|
+
// ["*", ["var", "population_density"], 10000],
|
|
114
|
+
// ],
|
|
115
|
+
"fill-color": "hsl(60deg, 100%, 50%)",
|
|
116
|
+
"fill-opacity": [
|
|
117
|
+
// Underserved areas are emphasized to their level importance,
|
|
118
|
+
// relative to the impact of the underservice.
|
|
119
|
+
"let",
|
|
120
|
+
"internet_speed_impact",
|
|
121
|
+
["/", ["to-number", ["get", "average_download_speed"]], GIGABIT_BROADBAND_SPEED],
|
|
122
|
+
[
|
|
123
|
+
// ---
|
|
124
|
+
"interpolate",
|
|
125
|
+
["linear"],
|
|
126
|
+
["var", "internet_speed_impact"],
|
|
127
|
+
0,
|
|
128
|
+
0.1,
|
|
129
|
+
1,
|
|
130
|
+
0.5,
|
|
131
|
+
],
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
// layout: {
|
|
135
|
+
// visibility: "none",
|
|
136
|
+
// },
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
{
|
|
140
|
+
afterID: "blocks-underserved",
|
|
141
|
+
id: "bdc-boundary-blocks",
|
|
142
|
+
layout: {
|
|
143
|
+
visibility: "none",
|
|
144
|
+
},
|
|
145
|
+
metadata: {
|
|
146
|
+
queryable: false,
|
|
147
|
+
},
|
|
148
|
+
"source-layer": `bdc_${TIGERLevel.Block}`,
|
|
149
|
+
source: BDCTileSetID,
|
|
150
|
+
type: "line",
|
|
151
|
+
// filter: [">=", ["get", "ALAND"], 0],
|
|
152
|
+
minzoom: 9,
|
|
153
|
+
paint: {
|
|
154
|
+
"line-color": "#000",
|
|
155
|
+
"line-width": 1,
|
|
156
|
+
"line-dasharray": [2, 2],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
afterID: "blocks-underserved",
|
|
161
|
+
metadata: {
|
|
162
|
+
queryable: false,
|
|
163
|
+
},
|
|
164
|
+
id: "blocks-underserved-ratio-label",
|
|
165
|
+
"source-layer": `bdc_${TIGERLevel.Block}`,
|
|
166
|
+
source: BDCTileSetID,
|
|
167
|
+
type: "symbol",
|
|
168
|
+
filter: [
|
|
169
|
+
// ---
|
|
170
|
+
"all",
|
|
171
|
+
// ["in", 50, ["get", "technology_codes"]], // Fiber only
|
|
172
|
+
[">", ["get", "land_area_sqm"], 0],
|
|
173
|
+
// ["==", ["get", "UR"], "R"],
|
|
174
|
+
],
|
|
175
|
+
paint: {
|
|
176
|
+
"text-color": "black",
|
|
177
|
+
"text-halo-color": "white",
|
|
178
|
+
"text-halo-width": 1,
|
|
179
|
+
},
|
|
180
|
+
layout: {
|
|
181
|
+
visibility: "none",
|
|
182
|
+
"text-field": [
|
|
183
|
+
"concat",
|
|
184
|
+
["number-format", ["get", "average_download_speed"], { "min-fraction-digits": 0, "max-fraction-digits": 2 }],
|
|
185
|
+
" Mbps",
|
|
186
|
+
],
|
|
187
|
+
"text-size": 10,
|
|
188
|
+
"text-offset": [0, 0],
|
|
189
|
+
"text-anchor": "center",
|
|
190
|
+
"text-font": ["Fira Code Regular"],
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
...createBDCLayer({
|
|
194
|
+
id: "coverage-fiber-label",
|
|
195
|
+
beforeID: "places_subplace",
|
|
196
|
+
filter: [
|
|
197
|
+
// ---
|
|
198
|
+
|
|
199
|
+
"all",
|
|
200
|
+
["==", ["get", "provider_id"], 131425],
|
|
201
|
+
// ["in", 50, ["get", "technology_codes"]],
|
|
202
|
+
],
|
|
203
|
+
type: "symbol",
|
|
204
|
+
layout: {
|
|
205
|
+
visibility: "none",
|
|
206
|
+
"text-field": [
|
|
207
|
+
"concat",
|
|
208
|
+
["number-format", ["get", "average_download_speed"], { "min-fraction-digits": 0, "max-fraction-digits": 2 }],
|
|
209
|
+
" Mbps",
|
|
210
|
+
],
|
|
211
|
+
"text-size": [
|
|
212
|
+
// ---
|
|
213
|
+
"let",
|
|
214
|
+
"multiplier",
|
|
215
|
+
// We scale the text size based on the average download speed.
|
|
216
|
+
// By default, we're no smaller than 14, Any speed above the gigabit threshold
|
|
217
|
+
// acts as a multiplier for the text size.
|
|
218
|
+
// ---
|
|
219
|
+
["/", ["get", "average_download_speed"], GIGABIT_BROADBAND_SPEED / 4],
|
|
220
|
+
["+", 14, ["var", "multiplier"]],
|
|
221
|
+
],
|
|
222
|
+
"text-offset": [0, 0],
|
|
223
|
+
"text-line-height": 1.2,
|
|
224
|
+
"text-pitch-alignment": "viewport",
|
|
225
|
+
"text-variable-anchor": ["center"],
|
|
226
|
+
"text-padding": 10,
|
|
227
|
+
"text-anchor": "center",
|
|
228
|
+
"text-font": ["Fira Code Medium"],
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
paint: {
|
|
232
|
+
"text-halo-width": 2,
|
|
233
|
+
"text-halo-color": [
|
|
234
|
+
// ---
|
|
235
|
+
"interpolate",
|
|
236
|
+
["exponential", 0.5],
|
|
237
|
+
["get", "average_download_speed"],
|
|
238
|
+
GIGABIT_BROADBAND_SPEED / 4,
|
|
239
|
+
"#fff",
|
|
240
|
+
|
|
241
|
+
GIGABIT_BROADBAND_SPEED,
|
|
242
|
+
"#000",
|
|
243
|
+
],
|
|
244
|
+
|
|
245
|
+
"text-color": [
|
|
246
|
+
// ---
|
|
247
|
+
"interpolate",
|
|
248
|
+
["exponential", 0.25],
|
|
249
|
+
["get", "average_download_speed"],
|
|
250
|
+
GIGABIT_BROADBAND_SPEED / 4,
|
|
251
|
+
interpolateTurbo(0),
|
|
252
|
+
|
|
253
|
+
GIGABIT_BROADBAND_SPEED / 2,
|
|
254
|
+
interpolateTurbo(0.25),
|
|
255
|
+
|
|
256
|
+
GIGABIT_BROADBAND_SPEED,
|
|
257
|
+
interpolateTurbo(0.5),
|
|
258
|
+
|
|
259
|
+
GIGABIT_BROADBAND_SPEED * 2,
|
|
260
|
+
interpolateTurbo(0.75),
|
|
261
|
+
|
|
262
|
+
GIGABIT_BROADBAND_SPEED * 4,
|
|
263
|
+
interpolateTurbo(1),
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
}),
|
|
267
|
+
{
|
|
268
|
+
afterID: "blocks-underserved",
|
|
269
|
+
type: "line",
|
|
270
|
+
source: "composite",
|
|
271
|
+
id: "lm-routes",
|
|
272
|
+
paint: {
|
|
273
|
+
"line-color": "#ff009c",
|
|
274
|
+
|
|
275
|
+
"line-width": [
|
|
276
|
+
"interpolate",
|
|
277
|
+
["exponential", 1.6],
|
|
278
|
+
["zoom"],
|
|
279
|
+
// ---
|
|
280
|
+
3,
|
|
281
|
+
0,
|
|
282
|
+
6,
|
|
283
|
+
1.1,
|
|
284
|
+
12,
|
|
285
|
+
1.6,
|
|
286
|
+
15,
|
|
287
|
+
5,
|
|
288
|
+
18,
|
|
289
|
+
15,
|
|
290
|
+
],
|
|
291
|
+
},
|
|
292
|
+
layout: {
|
|
293
|
+
"line-cap": "round",
|
|
294
|
+
},
|
|
295
|
+
"source-layer": "CENTURYLINK_ROUTE",
|
|
296
|
+
},
|
|
297
|
+
...createBDCLayer({
|
|
298
|
+
afterID: "earth",
|
|
299
|
+
id: "coverage-fiber-heat",
|
|
300
|
+
filter: [
|
|
301
|
+
// ---
|
|
302
|
+
|
|
303
|
+
"all",
|
|
304
|
+
["==", ["get", "provider_id"], 131425],
|
|
305
|
+
],
|
|
306
|
+
minzoom: 10,
|
|
307
|
+
type: "heatmap",
|
|
308
|
+
layout: {
|
|
309
|
+
visibility: "none",
|
|
310
|
+
},
|
|
311
|
+
paint: {
|
|
312
|
+
"heatmap-color": [
|
|
313
|
+
// ---
|
|
314
|
+
"interpolate",
|
|
315
|
+
["linear"],
|
|
316
|
+
["heatmap-density"],
|
|
317
|
+
...Array.from({ length: 10 }, (_, i) => {
|
|
318
|
+
return [i / 10, interpolateTurbo(i / 10)] as [number, string]
|
|
319
|
+
}).flat(),
|
|
320
|
+
],
|
|
321
|
+
|
|
322
|
+
"heatmap-radius": [
|
|
323
|
+
// ---
|
|
324
|
+
"interpolate",
|
|
325
|
+
["linear"],
|
|
326
|
+
["zoom"],
|
|
327
|
+
10,
|
|
328
|
+
5,
|
|
329
|
+
15,
|
|
330
|
+
20,
|
|
331
|
+
],
|
|
332
|
+
"heatmap-weight": [
|
|
333
|
+
// ---
|
|
334
|
+
"*",
|
|
335
|
+
["get", "land_area_sqm"],
|
|
336
|
+
0.00001,
|
|
337
|
+
],
|
|
338
|
+
},
|
|
339
|
+
}),
|
|
340
|
+
|
|
341
|
+
{
|
|
342
|
+
maxzoom: 13,
|
|
343
|
+
beforeID: "places_locality",
|
|
344
|
+
type: "circle",
|
|
345
|
+
id: "datacenter-marker",
|
|
346
|
+
source: "composite",
|
|
347
|
+
"source-layer": "DataCentersCombined20220921",
|
|
348
|
+
paint: {
|
|
349
|
+
"circle-color": "red",
|
|
350
|
+
"circle-stroke-color": "hsl(0, 0%, 100%)",
|
|
351
|
+
"circle-stroke-width": 2,
|
|
352
|
+
"circle-radius": ["interpolate", ["linear"], ["zoom"], 2, 3, 12, 5],
|
|
353
|
+
"circle-opacity": ["interpolate", ["linear"], ["zoom"], 2, 0.84, 3, 1, 22, 1],
|
|
354
|
+
},
|
|
355
|
+
layout: {
|
|
356
|
+
visibility: "none",
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
{
|
|
361
|
+
maxzoom: 13,
|
|
362
|
+
minzoom: 8,
|
|
363
|
+
afterID: "datacenter-marker",
|
|
364
|
+
id: "datacenter-label",
|
|
365
|
+
type: "symbol",
|
|
366
|
+
source: "composite",
|
|
367
|
+
"source-layer": "DataCentersCombined20220921",
|
|
368
|
+
layout: {
|
|
369
|
+
// visibility: "none",
|
|
370
|
+
"text-field": ["get", "Category"],
|
|
371
|
+
"text-size": 12,
|
|
372
|
+
"text-anchor": "top",
|
|
373
|
+
"text-offset": [0, 0.5],
|
|
374
|
+
// "text-allow-overlap": true,
|
|
375
|
+
"text-font": ["Fira Code Regular"],
|
|
376
|
+
},
|
|
377
|
+
paint: {
|
|
378
|
+
"text-color": "#fff",
|
|
379
|
+
"text-halo-color": "#fb8429",
|
|
380
|
+
"text-halo-width": 1,
|
|
381
|
+
"text-opacity": [
|
|
382
|
+
// We fade out the outline at higher zoom levels
|
|
383
|
+
"interpolate",
|
|
384
|
+
["linear"],
|
|
385
|
+
["zoom"],
|
|
386
|
+
1,
|
|
387
|
+
0.01,
|
|
388
|
+
6,
|
|
389
|
+
0.5,
|
|
390
|
+
16,
|
|
391
|
+
1,
|
|
392
|
+
],
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software.
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* The "fog of war" address-COVERAGE overlay. An H3 hexbin tileset (built by
|
|
7
|
+
* `scripts/build-coverage-tiles.ts`) shades each area by how much address-point data we hold:
|
|
8
|
+
* covered → clear (the basemap shows through), empty → opaque gray fog. Answers "where do we need
|
|
9
|
+
* more data" at a glance, and reveals the "looks covered until you zoom in, then it goes gray" gaps.
|
|
10
|
+
*
|
|
11
|
+
* Each cell carries TWO baked fog values in [0,1] (0 = covered, 1 = empty), so the same tiles drive
|
|
12
|
+
* either reading without a rebuild:
|
|
13
|
+
* • `fog_opt` — optimistic: partial coverage lifted toward clear, so a region "looks covered" when
|
|
14
|
+
* zoomed out and the gaps only surface on zoom-in.
|
|
15
|
+
* • `fog` — honest: true coverage fraction, so the gap is visible even at low zoom.
|
|
16
|
+
* We expose each as its OWN default-off fill layer (`coverage-opt-fog`, `coverage-honest-fog`) so the
|
|
17
|
+
* demo's LayerToggleControl gives each its own checkbox — pick the reading you want, no extra UI.
|
|
18
|
+
*
|
|
19
|
+
* Served as XYZ vector tiles by the tile worker from `nexus-assets/tiles/coverage-us-v4.pmtiles` (same
|
|
20
|
+
* as `basemap-v4`); the consumer passes its TileJSON URL (`tiles.sister.software/coverage-us-v4.json`)
|
|
21
|
+
* to `createCoverageSource`.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type {
|
|
25
|
+
FillLayerSpecification,
|
|
26
|
+
VectorSourceSpecification,
|
|
27
|
+
} from "@maplibre/maplibre-gl-style-spec"
|
|
28
|
+
import { TileSetSourceID } from "../styles/sources.js"
|
|
29
|
+
|
|
30
|
+
export const CoverageTileSetID = TileSetSourceID("coverage-us-v4")
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The single source-layer the coverage PMTiles ships (see `build-coverage-tiles.ts` → tippecanoe `-l`).
|
|
34
|
+
*/
|
|
35
|
+
export const COVERAGE_SOURCE_LAYER = "coverage"
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Fog tint — a near-black indigo reading as "unknown / unsurveyed". Pushed dark (vs a mid indigo) so it
|
|
39
|
+
* holds contrast over the demo's terrain+hillshade basemap, which is itself dark-green over forest where
|
|
40
|
+
* a lighter fog would simply vanish.
|
|
41
|
+
*/
|
|
42
|
+
export const COVERAGE_FOG_COLOR = "#663399" // Rebecca Purple
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Opacity of a fully-empty (`fog = 1`) cell. Covered cells scale down from here toward transparent.
|
|
46
|
+
*/
|
|
47
|
+
export const COVERAGE_MAX_FOG_OPACITY = 0.9
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Layer IDs, exported so the demo (toggle wiring, imperative add) and tests can reference them.
|
|
51
|
+
*/
|
|
52
|
+
export const CoverageLayerID = {
|
|
53
|
+
optimistic: "coverage-opt-fog",
|
|
54
|
+
honest: "coverage-honest-fog",
|
|
55
|
+
} as const
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build the coverage source spec from the tile worker's TileJSON endpoint
|
|
59
|
+
* (`https://tiles.sister.software/coverage-us-v4.json`).
|
|
60
|
+
*/
|
|
61
|
+
export function createCoverageSource(url: string): VectorSourceSpecification {
|
|
62
|
+
return { type: "vector", url }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function fogFill(id: string, fogProperty: "fog" | "fog_opt"): FillLayerSpecification {
|
|
66
|
+
return {
|
|
67
|
+
id,
|
|
68
|
+
type: "fill",
|
|
69
|
+
source: CoverageTileSetID,
|
|
70
|
+
"source-layer": COVERAGE_SOURCE_LAYER,
|
|
71
|
+
// Default OFF — an overlay, surfaced via the layer toggle, never on by default.
|
|
72
|
+
layout: { visibility: "none" },
|
|
73
|
+
paint: {
|
|
74
|
+
"fill-color": COVERAGE_FOG_COLOR,
|
|
75
|
+
// Opacity tracks the cell's fog value; coalesce guards a missing prop to 0 (fully clear).
|
|
76
|
+
"fill-opacity": ["*", ["coalesce", ["to-number", ["get", fogProperty]], 0], COVERAGE_MAX_FOG_OPACITY],
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The two default-off fog fills (optimistic + honest). Plain MapLibre specs — the demo adds them
|
|
83
|
+
* imperatively on map-load with a `beforeId` of the first symbol layer, so the fog sits beneath place
|
|
84
|
+
* labels but above basemap geometry (roads/water vanish under fog where we have no data).
|
|
85
|
+
*/
|
|
86
|
+
export const CoverageLayers: FillLayerSpecification[] = [
|
|
87
|
+
fogFill(CoverageLayerID.optimistic, "fog_opt"),
|
|
88
|
+
fogFill(CoverageLayerID.honest, "fog"),
|
|
89
|
+
]
|
package/hspa/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software.
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// import { LayerSpecificationListInput } from "../styles/layers.js"
|
|
8
|
+
import { TileSetSourceID } from "../styles/sources.js"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Identifier for the Health Service Provider Access tile set.
|
|
12
|
+
*/
|
|
13
|
+
export const HSPATileSetID = TileSetSourceID("HPSA_PNTPC_SHP_DET_CUR_VX")
|
|
14
|
+
export const MUATileSetID = TileSetSourceID("MUA_CMPPC_SHP_DET_CUR_VX")
|
|
15
|
+
|
|
16
|
+
// export const MUALayers: LayerSpecificationListInput[] = [
|
|
17
|
+
// {
|
|
18
|
+
// "id": ""
|
|
19
|
+
// },
|
|
20
|
+
// ]
|
package/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software.
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export * from "./base/index.js"
|
|
8
|
+
export * from "./bdc/index.js"
|
|
9
|
+
export * from "./hspa/index.js"
|
|
10
|
+
export * from "./styles/index.js"
|
|
11
|
+
export * from "./tiger/index.js"
|
|
12
|
+
export * from "./tiles/index.js"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software.
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
import { type LayerSpecification } from "@maplibre/maplibre-gl-style-spec";
|
|
7
|
+
/**
|
|
8
|
+
* Layer definitions for building data.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BuildingLayers: LayerSpecification[];
|
|
11
|
+
//# sourceMappingURL=buildings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildings.d.ts","sourceRoot":"","sources":["../../base/buildings.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAwC,KAAK,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AAOhH;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,kBAAkB,EA8D9C,CAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software.
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
import {} from "@maplibre/maplibre-gl-style-spec";
|
|
7
|
+
import { interpolateTurbo } from "d3-scale-chromatic";
|
|
8
|
+
import { LayerID } from "../styles/layers.js";
|
|
9
|
+
import { MailwomanBaseTileSetID } from "./theme.js";
|
|
10
|
+
const BuildingLayerID = LayerID.bind(null, "buildings");
|
|
11
|
+
/**
|
|
12
|
+
* Layer definitions for building data.
|
|
13
|
+
*/
|
|
14
|
+
export const BuildingLayers = [
|
|
15
|
+
createBuildingFillStyleLayer({
|
|
16
|
+
id: BuildingLayerID("buildings-extruded"),
|
|
17
|
+
paint: {
|
|
18
|
+
"fill-extrusion-color": [
|
|
19
|
+
// ---
|
|
20
|
+
"interpolate",
|
|
21
|
+
// ["exponential", 0.25],
|
|
22
|
+
["linear"],
|
|
23
|
+
[
|
|
24
|
+
// --
|
|
25
|
+
"coalesce",
|
|
26
|
+
["get", "height"],
|
|
27
|
+
["get", "minheight"],
|
|
28
|
+
10,
|
|
29
|
+
],
|
|
30
|
+
...Array.from({ length: 10 }, (_, i) => {
|
|
31
|
+
const sizeScalingFactor = 250 - 250 / i;
|
|
32
|
+
return [sizeScalingFactor, interpolateTurbo(sizeScalingFactor / 250)];
|
|
33
|
+
}).flat(),
|
|
34
|
+
],
|
|
35
|
+
"fill-extrusion-translate": [0.1, 0.1],
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
{
|
|
39
|
+
id: "basemap-buildings-outline",
|
|
40
|
+
type: "line",
|
|
41
|
+
source: MailwomanBaseTileSetID,
|
|
42
|
+
"source-layer": "buildings",
|
|
43
|
+
minzoom: 11,
|
|
44
|
+
filter: ["==", ["%", ["to-number", ["id"]], 2], 0],
|
|
45
|
+
paint: {
|
|
46
|
+
"line-width": 1,
|
|
47
|
+
"line-color": "hsl(240deg 100% 80%)",
|
|
48
|
+
"line-opacity": ["interpolate", ["linear"], ["zoom"], 11, 0, 20, 1],
|
|
49
|
+
"line-dasharray": [2, 3],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "basemap-buildings-kind",
|
|
54
|
+
type: "symbol",
|
|
55
|
+
source: MailwomanBaseTileSetID,
|
|
56
|
+
"source-layer": "buildings",
|
|
57
|
+
minzoom: 11,
|
|
58
|
+
layout: {
|
|
59
|
+
visibility: "none",
|
|
60
|
+
"text-field": ["to-string", ["id"]],
|
|
61
|
+
"text-offset": [0, 0],
|
|
62
|
+
"text-anchor": "center",
|
|
63
|
+
"text-font": ["Fira Sans Regular"],
|
|
64
|
+
},
|
|
65
|
+
paint: {
|
|
66
|
+
"text-color": "black",
|
|
67
|
+
"text-halo-color": "red",
|
|
68
|
+
"text-halo-width": 1,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
function createBuildingFillStyleLayer(fillStyleSpec) {
|
|
73
|
+
const baseStyle = {
|
|
74
|
+
...fillStyleSpec,
|
|
75
|
+
type: "fill-extrusion",
|
|
76
|
+
source: MailwomanBaseTileSetID,
|
|
77
|
+
"source-layer": "buildings",
|
|
78
|
+
minzoom: 12,
|
|
79
|
+
paint: {
|
|
80
|
+
...fillStyleSpec.paint,
|
|
81
|
+
"fill-extrusion-vertical-gradient": true,
|
|
82
|
+
"fill-extrusion-height": [
|
|
83
|
+
"+",
|
|
84
|
+
[
|
|
85
|
+
// --
|
|
86
|
+
"coalesce",
|
|
87
|
+
["get", "height"],
|
|
88
|
+
["get", "minheight"],
|
|
89
|
+
10,
|
|
90
|
+
],
|
|
91
|
+
fillStyleSpec.heightOffset || 0,
|
|
92
|
+
],
|
|
93
|
+
"fill-extrusion-translate-anchor": "map",
|
|
94
|
+
// "fill-extrusion-opacity": 0.7,
|
|
95
|
+
"fill-extrusion-opacity": [
|
|
96
|
+
// We fade out the outline at higher zoom levels
|
|
97
|
+
"interpolate",
|
|
98
|
+
["linear"],
|
|
99
|
+
["zoom"],
|
|
100
|
+
11,
|
|
101
|
+
0.6,
|
|
102
|
+
16,
|
|
103
|
+
0.95,
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
return baseStyle;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=buildings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildings.js","sourceRoot":"","sources":["../../base/buildings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software.
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*/
|
|
6
|
+
import type { SourceSpecification } from "@maplibre/maplibre-gl-style-spec";
|
|
7
|
+
import type { LightSpecification, SkySpecification, StyleSpecification, TerrainSpecification } from "maplibre-gl";
|
|
8
|
+
import { LayerSpecificationList, type LayerSpecificationListInput, type LayerSpecificationListItem } from "../styles/layers.js";
|
|
9
|
+
import { type TileSetSourceRecord } from "../styles/sources.js";
|
|
10
|
+
export declare function createLightSpec(spec?: Partial<LightSpecification>): LightSpecification;
|
|
11
|
+
export declare function createSkySpec(spec?: Partial<SkySpecification>): SkySpecification;
|
|
12
|
+
export interface StyleSpecificationComposition {
|
|
13
|
+
sources: Record<string, SourceSpecification>;
|
|
14
|
+
layers?: LayerSpecificationListInput[];
|
|
15
|
+
light?: Partial<LightSpecification>;
|
|
16
|
+
sky?: Partial<SkySpecification>;
|
|
17
|
+
terrain?: Partial<TerrainSpecification>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A stateful class for composing a style specification.
|
|
21
|
+
*/
|
|
22
|
+
export declare class StyleSpecificationComposer {
|
|
23
|
+
layersList: LayerSpecificationList;
|
|
24
|
+
light: LightSpecification;
|
|
25
|
+
sky: SkySpecification;
|
|
26
|
+
terrain: TerrainSpecification;
|
|
27
|
+
sources: TileSetSourceRecord;
|
|
28
|
+
constructor(spec: StyleSpecificationComposition);
|
|
29
|
+
get layers(): LayerSpecificationListItem[];
|
|
30
|
+
toJSON(): StyleSpecification;
|
|
31
|
+
toJS(): StyleSpecification;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=composition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.d.ts","sourceRoot":"","sources":["../../base/composition.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAC3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACjH,OAAO,EACN,sBAAsB,EACtB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAQ/D,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAYtF;AAED,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAUhF;AAMD,MAAM,WAAW,6BAA6B;IAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAC5C,MAAM,CAAC,EAAE,2BAA2B,EAAE,CAAA;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACnC,GAAG,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAA;CACvC;AAED;;GAEG;AACH,qBAAa,0BAA0B;IACtC,UAAU,EAAE,sBAAsB,CAAA;IAClC,KAAK,EAAE,kBAAkB,CAAA;IACzB,GAAG,EAAE,gBAAgB,CAAA;IACrB,OAAO,EAAE,oBAAoB,CAAA;IAC7B,OAAO,EAAE,mBAAmB,CAAA;gBAEhB,IAAI,EAAE,6BAA6B;IAsB/C,IAAW,MAAM,IAAI,0BAA0B,EAAE,CAEhD;IAED,MAAM,IAAI,kBAAkB;IAkB5B,IAAI,IAAI,kBAAkB;CAG1B"}
|