@mailwoman/cartographer 9.4.0 → 10.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.
Files changed (123) hide show
  1. package/lib/base/buildings.ts +3 -4
  2. package/lib/base/composition.ts +23 -13
  3. package/lib/base/layers.ts +9 -3
  4. package/lib/base/theme.ts +22 -13
  5. package/lib/{bdc/index.ts → bdc.ts} +15 -109
  6. package/lib/coverage.ts +73 -0
  7. package/lib/index.ts +6 -6
  8. package/lib/planetary/layers.ts +63 -18
  9. package/lib/planetary/sources.ts +10 -7
  10. package/lib/planetary/style.ts +12 -6
  11. package/lib/{race-dots/index.ts → race-dots.ts} +19 -20
  12. package/lib/styles/fonts.ts +19 -8
  13. package/lib/styles/layers.ts +3 -3
  14. package/lib/styles/sources.ts +4 -3
  15. package/lib/{tiger/index.ts → tiger.ts} +3 -2
  16. package/out/base/buildings.d.ts.map +1 -1
  17. package/out/base/buildings.js +3 -4
  18. package/out/base/buildings.js.map +1 -1
  19. package/out/base/composition.d.ts +18 -8
  20. package/out/base/composition.d.ts.map +1 -1
  21. package/out/base/composition.js +13 -9
  22. package/out/base/composition.js.map +1 -1
  23. package/out/base/layers.d.ts +1 -1
  24. package/out/base/layers.d.ts.map +1 -1
  25. package/out/base/layers.js +9 -3
  26. package/out/base/layers.js.map +1 -1
  27. package/out/base/theme.d.ts +9 -5
  28. package/out/base/theme.d.ts.map +1 -1
  29. package/out/base/theme.js +21 -13
  30. package/out/base/theme.js.map +1 -1
  31. package/out/{base/index.d.ts → base.d.ts} +1 -1
  32. package/out/base.d.ts.map +1 -0
  33. package/out/{base/index.js → base.js} +1 -1
  34. package/out/base.js.map +1 -0
  35. package/out/{bdc/index.d.ts → bdc.d.ts} +8 -7
  36. package/out/bdc.d.ts.map +1 -0
  37. package/out/{bdc/index.js → bdc.js} +9 -102
  38. package/out/bdc.js.map +1 -0
  39. package/out/coverage.d.ts +44 -0
  40. package/out/coverage.d.ts.map +1 -0
  41. package/out/coverage.js +63 -0
  42. package/out/coverage.js.map +1 -0
  43. package/out/{hspa/index.d.ts → hspa.d.ts} +1 -1
  44. package/out/hspa.d.ts.map +1 -0
  45. package/out/{hspa/index.js → hspa.js} +1 -1
  46. package/out/hspa.js.map +1 -0
  47. package/out/index.d.ts +6 -6
  48. package/out/index.d.ts.map +1 -1
  49. package/out/index.js +6 -6
  50. package/out/index.js.map +1 -1
  51. package/out/planetary/layers.d.ts +40 -12
  52. package/out/planetary/layers.d.ts.map +1 -1
  53. package/out/planetary/layers.js +44 -17
  54. package/out/planetary/layers.js.map +1 -1
  55. package/out/planetary/sources.d.ts +7 -6
  56. package/out/planetary/sources.d.ts.map +1 -1
  57. package/out/planetary/sources.js +8 -5
  58. package/out/planetary/sources.js.map +1 -1
  59. package/out/planetary/style.d.ts +7 -4
  60. package/out/planetary/style.d.ts.map +1 -1
  61. package/out/planetary/style.js +5 -4
  62. package/out/planetary/style.js.map +1 -1
  63. package/out/{planetary/index.js → planetary.d.ts} +1 -1
  64. package/out/planetary.d.ts.map +1 -0
  65. package/out/{planetary/index.d.ts → planetary.js} +1 -1
  66. package/out/planetary.js.map +1 -0
  67. package/out/race-dots.d.ts +70 -0
  68. package/out/race-dots.d.ts.map +1 -0
  69. package/out/race-dots.js +69 -0
  70. package/out/race-dots.js.map +1 -0
  71. package/out/styles/fonts.d.ts +17 -8
  72. package/out/styles/fonts.d.ts.map +1 -1
  73. package/out/styles/fonts.js +17 -8
  74. package/out/styles/fonts.js.map +1 -1
  75. package/out/styles/layers.d.ts.map +1 -1
  76. package/out/styles/layers.js +3 -3
  77. package/out/styles/layers.js.map +1 -1
  78. package/out/styles/sources.d.ts.map +1 -1
  79. package/out/styles/sources.js +3 -2
  80. package/out/styles/sources.js.map +1 -1
  81. package/out/{styles/index.d.ts → styles.d.ts} +1 -1
  82. package/out/styles.d.ts.map +1 -0
  83. package/out/{styles/index.js → styles.js} +1 -1
  84. package/out/styles.js.map +1 -0
  85. package/out/{tiger/index.d.ts → tiger.d.ts} +4 -3
  86. package/out/tiger.d.ts.map +1 -0
  87. package/out/{tiger/index.js → tiger.js} +4 -3
  88. package/out/tiger.js.map +1 -0
  89. package/out/tiles/api.d.ts.map +1 -1
  90. package/out/{tiles/index.d.ts → tiles.d.ts} +1 -1
  91. package/out/tiles.d.ts.map +1 -0
  92. package/out/{tiles/index.js → tiles.js} +1 -1
  93. package/out/tiles.js.map +1 -0
  94. package/out/tsconfig.test.tsbuildinfo +1 -1
  95. package/package.json +14 -99
  96. package/lib/coverage/index.ts +0 -88
  97. package/out/base/index.d.ts.map +0 -1
  98. package/out/base/index.js.map +0 -1
  99. package/out/bdc/index.d.ts.map +0 -1
  100. package/out/bdc/index.js.map +0 -1
  101. package/out/coverage/index.d.ts +0 -59
  102. package/out/coverage/index.d.ts.map +0 -1
  103. package/out/coverage/index.js +0 -78
  104. package/out/coverage/index.js.map +0 -1
  105. package/out/hspa/index.d.ts.map +0 -1
  106. package/out/hspa/index.js.map +0 -1
  107. package/out/planetary/index.d.ts.map +0 -1
  108. package/out/planetary/index.js.map +0 -1
  109. package/out/race-dots/index.d.ts +0 -72
  110. package/out/race-dots/index.d.ts.map +0 -1
  111. package/out/race-dots/index.js +0 -70
  112. package/out/race-dots/index.js.map +0 -1
  113. package/out/styles/index.d.ts.map +0 -1
  114. package/out/styles/index.js.map +0 -1
  115. package/out/tiger/index.d.ts.map +0 -1
  116. package/out/tiger/index.js.map +0 -1
  117. package/out/tiles/index.d.ts.map +0 -1
  118. package/out/tiles/index.js.map +0 -1
  119. /package/lib/{base/index.ts → base.ts} +0 -0
  120. /package/lib/{hspa/index.ts → hspa.ts} +0 -0
  121. /package/lib/{planetary/index.ts → planetary.ts} +0 -0
  122. /package/lib/{styles/index.ts → styles.ts} +0 -0
  123. /package/lib/{tiles/index.ts → tiles.ts} +0 -0
@@ -11,7 +11,7 @@ import type {
11
11
  } from "@maplibre/maplibre-gl-style-spec"
12
12
 
13
13
  import { MailwomanBaseTileSetID } from "#base/theme"
14
- import { PROTOMAPS_FONT_REGULAR } from "#styles/fonts"
14
+ import { MAP_FONT_REGULAR } from "#styles/fonts"
15
15
  import { LayerID } from "#styles/layers"
16
16
 
17
17
  const BuildingLayerID = LayerID.bind(null, "buildings")
@@ -80,8 +80,7 @@ export const BuildingLayers: LayerSpecification[] = [
80
80
  "fill-extrusion-vertical-gradient": false,
81
81
  "fill-extrusion-translate-anchor": "map",
82
82
  "fill-extrusion-opacity": 1,
83
- // top of the band = full building height
84
- // "fill-extrusion-height": popHeight(buildingHeight()),
83
+ // top of the band = full building height "fill-extrusion-height": popHeight(buildingHeight()),
85
84
  // // base of the band = full height minus the cap thickness (clamped ≥ 0)
86
85
  // "fill-extrusion-base": popHeight([ "max", [ "-", buildingHeight(), ROOF_CAP ], 0 ]),
87
86
  "fill-extrusion-height": popHeight(["+", buildingHeight(), ROOF_GAP, ROOF_CAP]),
@@ -115,7 +114,7 @@ export const BuildingLayers: LayerSpecification[] = [
115
114
  "text-field": ["to-string", ["id"]],
116
115
  "text-offset": [0, 0],
117
116
  "text-anchor": "center",
118
- "text-font": [PROTOMAPS_FONT_REGULAR],
117
+ "text-font": [MAP_FONT_REGULAR],
119
118
  },
120
119
 
121
120
  paint: {
@@ -16,9 +16,9 @@ import {
16
16
  } from "#styles/layers"
17
17
  import type { TileSetSourceRecord } from "#styles/sources"
18
18
 
19
- //#endregion
19
+ // #endregion
20
20
 
21
- //#region Spec Creators
21
+ // #region Spec Creators
22
22
 
23
23
  export function createLightSpec(spec?: Partial<LightSpecification>): LightSpecification {
24
24
  return {
@@ -46,19 +46,23 @@ export function createSkySpec(spec?: Partial<SkySpecification>): SkySpecificatio
46
46
  }
47
47
  }
48
48
 
49
- //#endregion
49
+ // #endregion
50
50
 
51
- //#region Style Composition
51
+ // #region Style Composition
52
52
 
53
53
  /**
54
- * The glyph host every style composed here reads fonts from. The Protomaps font set, mirrored under the public bucket
55
- * so a style never depends on an upstream host at render time.
54
+ * The glyph host every style composed here reads fonts from.
55
+ *
56
+ * The Protomaps font set, mirrored under the public bucket so a style never
57
+ * depends on an upstream host at render time.
56
58
  */
57
59
  export const PROTOMAPS_GLYPHS_URL = "https://public.mailwoman.ai/protomaps/fonts/{fontstack}/{range}.pbf"
58
60
 
59
61
  /**
60
- * The Earth sprite. It must match the basemap schema version: the v4 sprite carries the icons the v4 theme's layers
61
- * reference by name, so a style over a different basemap version needs a different sprite.
62
+ * The Earth sprite.
63
+ *
64
+ * It must match the basemap schema version: the v4 sprite includes the icons the v4 theme's
65
+ * layers reference by name, so a style over a different basemap version needs a different sprite.
62
66
  */
63
67
  export const PROTOMAPS_SPRITE_URL = "https://public.mailwoman.ai/protomaps/sprites/v4/light"
64
68
 
@@ -69,16 +73,22 @@ export interface StyleSpecificationComposition {
69
73
  sky?: Partial<SkySpecification>
70
74
  terrain?: Partial<TerrainSpecification>
71
75
  /**
72
- * The layer list every `layers` entry inserts into. Earth's basemap layers by default; a body with no roads, water or
73
- * buildings brings its own.
76
+ * The layer list every `layers` entry inserts into.
77
+ *
78
+ * Earth's basemap layers by default.
79
+ * A body with no roads, water or buildings brings its own.
74
80
  */
75
81
  baseLayers?: LayerSpecification[]
76
82
  /**
77
- * The `hillshade` source. Earth's terrarium DEM by default; `null` adds no such source.
83
+ * The `hillshade` source.
84
+ *
85
+ * Earth's terrarium DEM by default; `null` adds no such source.
78
86
  */
79
87
  hillshadeSource?: SourceSpecification | null
80
88
  /**
81
- * The sprite URL. Earth's Protomaps v4 sprite by default; `null` omits the key, for a style with no icons.
89
+ * The sprite URL.
90
+ *
91
+ * Earth's Protomaps v4 sprite by default; `null` omits the key, for a style with no icons.
82
92
  */
83
93
  sprite?: string | null
84
94
  glyphs?: string
@@ -146,4 +156,4 @@ export class StyleSpecificationComposer {
146
156
  }
147
157
  }
148
158
 
149
- //#endregion
159
+ // #endregion
@@ -18,9 +18,15 @@ import { LayerID } from "#styles/layers"
18
18
  export const HillsLayerID = LayerID(HillshadeTileSetID, "hills")
19
19
 
20
20
  /**
21
- * Splits `layers()` into non-label + label groups so building footprints, water outlines, and hillshade sit between
22
- * base geometry and labels. `@protomaps/basemaps@5.x` doesn't expose a `noLabels` helper — `labelsOnly: true` gives
23
- * only the label layers; subtracting that set from the full list yields the non-label group.
21
+ * Splits `layers()` into non-label and label groups.
22
+ *
23
+ * The interval between base geometry and labels holds the footprints.
24
+ * It also holds water outlines and hillshade.
25
+ *
26
+ * `@protomaps/basemaps@5.x` doesn't expose a `noLabels` helper.
27
+ * `labelsOnly: true` gives only the label layers.
28
+ *
29
+ * The full list minus that set yields the non-label group.
24
30
  */
25
31
  const allBaseLayers = layers(MailwomanBaseTileSetID, MailwomanBaseFlavor, { lang: "en" })
26
32
  const labelLayers = layers(MailwomanBaseTileSetID, MailwomanBaseFlavor, { lang: "en", labelsOnly: true })
package/lib/base/theme.ts CHANGED
@@ -6,25 +6,34 @@
6
6
 
7
7
  import { type Flavor, namedFlavor } from "@protomaps/basemaps"
8
8
 
9
+ import { MAP_FONT_ITALIC, MAP_FONT_MEDIUM, MAP_FONT_REGULAR } from "#styles/fonts"
9
10
  import { TileSetSourceID } from "#styles/sources"
10
11
 
11
12
  /**
12
- * Identifier for the Mailwoman base tileset. Matches the R2 object basename (`nexus-assets/tiles/basemap-v4.pmtiles`) —
13
- * `tiles.mailwoman.ai/basemap-v4.json` returns its tilejson, `tiles.mailwoman.ai/basemap-v4/{z}/{x}/{y}.mvt` returns
14
- * vector tiles.
13
+ * Identifier for the Mailwoman base tileset.
14
+ *
15
+ * Matches the R2 object basename (`nexus-assets/tiles/basemap-v4.pmtiles`).
16
+ * `tiles.mailwoman.ai/basemap-v4.json` returns its tilejson,
17
+ * `tiles.mailwoman.ai/basemap-v4/{z}/{x}/{y}.mvt` returns vector tiles.
15
18
  */
16
19
  export const MailwomanBaseTileSetID = TileSetSourceID("basemap-v4")
17
20
 
18
21
  const darkFlavor = namedFlavor("dark")
19
22
 
20
23
  /**
21
- * The Mailwoman theme for Protomaps via MapLibre. Keys follow `@protomaps/basemaps@5.x` which targets the v4 tile
22
- * schema (`["==","kind","..."]` filters), matching the basemap-v4 PMTiles on R2.
24
+ * The Mailwoman theme for Protomaps via MapLibre.
25
+ *
26
+ * Keys follow `@protomaps/basemaps@5.x` which targets the v4 tile schema
27
+ * (`["==","kind","..."]` filters), matching the basemap-v4 PMTiles on R2.
23
28
  */
24
29
  export const MailwomanBaseFlavor: Flavor = {
25
30
  ...darkFlavor,
26
31
 
27
- //#region Base
32
+ regular: MAP_FONT_REGULAR,
33
+ bold: MAP_FONT_MEDIUM,
34
+ italic: MAP_FONT_ITALIC,
35
+
36
+ // #region Base
28
37
  background: "hsl(0deg 10% 5%)",
29
38
  earth: "hsl(0deg 10% 5%)",
30
39
 
@@ -51,8 +60,8 @@ export const MailwomanBaseFlavor: Flavor = {
51
60
  zoo: "#222323",
52
61
  military: "#242323",
53
62
 
54
- //#endregion
55
- //#region Tunnel
63
+ // #endregion
64
+ // #region Tunnel
56
65
  tunnel_other_casing: "#141414",
57
66
  tunnel_minor_casing: "#141414",
58
67
  tunnel_link_casing: "#141414",
@@ -64,10 +73,10 @@ export const MailwomanBaseFlavor: Flavor = {
64
73
  tunnel_major: "#292929",
65
74
  tunnel_highway: "#292929",
66
75
 
67
- //#endregion
76
+ // #endregion
68
77
  buildings: "#111111",
69
78
 
70
- //#region Casing
79
+ // #region Casing
71
80
  minor_service_casing: "#1f1f1f",
72
81
  minor_casing: "#1f1f1f",
73
82
  link_casing: "#1f1f1f",
@@ -83,11 +92,11 @@ export const MailwomanBaseFlavor: Flavor = {
83
92
  highway_casing_early: "#1f1f1f",
84
93
  highway: "hsl(36deg 10% 50%)",
85
94
 
86
- //#endregion
95
+ // #endregion
87
96
  railway: "#000000",
88
97
  boundaries: "hsl(240deg 100% 90%)",
89
98
 
90
- //#region Bridges
99
+ // #region Bridges
91
100
  bridges_other_casing: "#2b2b2b",
92
101
  bridges_minor_casing: "#1f1f1f",
93
102
  bridges_link_casing: "#1f1f1f",
@@ -99,7 +108,7 @@ export const MailwomanBaseFlavor: Flavor = {
99
108
  bridges_major: "#3d3d3d",
100
109
  bridges_highway: "#474747",
101
110
 
102
- //#endregion
111
+ // #endregion
103
112
 
104
113
  ocean_label: "#717784",
105
114
  subplace_label: "hsl(50deg 50% 70%)",
@@ -47,13 +47,14 @@ export type BaseBDCLayerSpecification<T> = T extends BDCLayerSpecificationInput
47
47
  : never
48
48
 
49
49
  /**
50
- * The three builders below take a spec WITHOUT the source fields and return one with them filled in.
50
+ * The three builders below take a spec without the source fields and return one with them filled in.
51
51
  *
52
- * They are not generic, and the assertion each ends with is single rather than through `unknown`, both for the same
53
- * reason: TypeScript cannot verify that `Omit<T, K>` plus the omitted keys reconstitutes `T`, so a builder declared
54
- * `<T>(…): T` can only reach its return type by defeating the checker entirely — which then covers the `id`, `minzoom`
55
- * and `maxzoom` values too. Nothing wanted the narrowing: the sole consumer, {@linkcode BroadbandDataCollectionLayers},
56
- * annotates the union.
52
+ * These are specific assertions.
53
+ * Each avoids `unknown`.
54
+ *
55
+ * TypeScript cannot verify that because TypeScript cannot verify that `Omit<T, K>` plus
56
+ * the omitted keys reconstitutes `T` — a `<T>(…): T` builder could only reach its return
57
+ * type by defeating the checker, covering the `id`, `minzoom` and `maxzoom` values too.
57
58
  */
58
59
  type BDCLayerBuilderInput = BaseBDCLayerSpecification<BDCLayerSpecificationInput>
59
60
 
@@ -101,9 +102,6 @@ const GIGABIT_BROADBAND_SPEED = 1000
101
102
  export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
102
103
  {
103
104
  afterID: "earth",
104
- // metadata: {
105
- // queryable: false,
106
- // },
107
105
  id: "blocks-underserved",
108
106
  layout: {
109
107
  visibility: "none",
@@ -112,43 +110,19 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
112
110
  source: BDCTileSetID,
113
111
  type: "fill",
114
112
  filter: [
115
- // ---
116
113
  "all",
117
114
  ["in", 50, ["get", "technology_codes"]], // Fiber only
118
115
  [">", ["get", "land_area_sqm"], 0],
119
- // ["==", ["get", "UR"], "R"],
120
116
  ],
121
117
  paint: {
122
- // "fill-extrusion-height": [
123
- // // Our extrusion height represents the magnitude of broadband underservice,
124
- // // e.g. How many people are underserved per square meter of land area.
125
- // "let",
126
- // "population_density",
127
- // ["/", ["to-number", ["get", "population"]], ["to-number", ["get", "land_area_sqm"]]],
128
- // ["*", ["var", "population_density"], 10000],
129
- // ],
130
118
  "fill-color": "hsl(60deg, 100%, 50%)",
131
119
  "fill-opacity": [
132
- // Underserved areas are emphasized to their level importance,
133
- // relative to the impact of the underservice.
134
120
  "let",
135
121
  "internet_speed_impact",
136
122
  ["/", ["to-number", ["get", "average_download_speed"]], GIGABIT_BROADBAND_SPEED],
137
- [
138
- // ---
139
- "interpolate",
140
- ["linear"],
141
- ["var", "internet_speed_impact"],
142
- 0,
143
- 0.1,
144
- 1,
145
- 0.5,
146
- ],
123
+ ["interpolate", ["linear"], ["var", "internet_speed_impact"], 0, 0.1, 1, 0.5],
147
124
  ],
148
125
  },
149
- // layout: {
150
- // visibility: "none",
151
- // },
152
126
  },
153
127
 
154
128
  {
@@ -163,7 +137,6 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
163
137
  "source-layer": `bdc_${TIGERLevel.Block}`,
164
138
  source: BDCTileSetID,
165
139
  type: "line",
166
- // filter: [">=", ["get", "ALAND"], 0],
167
140
  minzoom: 9,
168
141
  paint: {
169
142
  "line-color": "#000",
@@ -180,13 +153,7 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
180
153
  "source-layer": `bdc_${TIGERLevel.Block}`,
181
154
  source: BDCTileSetID,
182
155
  type: "symbol",
183
- filter: [
184
- // ---
185
- "all",
186
- // ["in", 50, ["get", "technology_codes"]], // Fiber only
187
- [">", ["get", "land_area_sqm"], 0],
188
- // ["==", ["get", "UR"], "R"],
189
- ],
156
+ filter: ["all", [">", ["get", "land_area_sqm"], 0]],
190
157
  paint: {
191
158
  "text-color": "black",
192
159
  "text-halo-color": "white",
@@ -208,13 +175,7 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
208
175
  ...createBDCLayer({
209
176
  id: "coverage-fiber-label",
210
177
  beforeID: "places_subplace",
211
- filter: [
212
- // ---
213
-
214
- "all",
215
- ["==", ["get", "provider_id"], 131_425],
216
- // ["in", 50, ["get", "technology_codes"]],
217
- ],
178
+ filter: ["all", ["==", ["get", "provider_id"], 131_425]],
218
179
  type: "symbol",
219
180
  layout: {
220
181
  visibility: "none",
@@ -224,13 +185,8 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
224
185
  " Mbps",
225
186
  ],
226
187
  "text-size": [
227
- // ---
228
188
  "let",
229
189
  "multiplier",
230
- // We scale the text size based on the average download speed.
231
- // By default, we're no smaller than 14, Any speed above the gigabit threshold
232
- // acts as a multiplier for the text size.
233
- // ---
234
190
  ["/", ["get", "average_download_speed"], GIGABIT_BROADBAND_SPEED / 4],
235
191
  ["+", 14, ["var", "multiplier"]],
236
192
  ],
@@ -246,7 +202,6 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
246
202
  paint: {
247
203
  "text-halo-width": 2,
248
204
  "text-halo-color": [
249
- // ---
250
205
  "interpolate",
251
206
  ["exponential", 0.5],
252
207
  ["get", "average_download_speed"],
@@ -258,7 +213,6 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
258
213
  ],
259
214
 
260
215
  "text-color": [
261
- // ---
262
216
  "interpolate",
263
217
  ["exponential", 0.25],
264
218
  ["get", "average_download_speed"],
@@ -287,22 +241,7 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
287
241
  paint: {
288
242
  "line-color": "#ff009c",
289
243
 
290
- "line-width": [
291
- "interpolate",
292
- ["exponential", 1.6],
293
- ["zoom"],
294
- // ---
295
- 3,
296
- 0,
297
- 6,
298
- 1.1,
299
- 12,
300
- 1.6,
301
- 15,
302
- 5,
303
- 18,
304
- 15,
305
- ],
244
+ "line-width": ["interpolate", ["exponential", 1.6], ["zoom"], 3, 0, 6, 1.1, 12, 1.6, 15, 5, 18, 15],
306
245
  },
307
246
  layout: {
308
247
  "line-cap": "round",
@@ -312,12 +251,7 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
312
251
  ...createBDCLayer({
313
252
  afterID: "earth",
314
253
  id: "coverage-fiber-heat",
315
- filter: [
316
- // ---
317
-
318
- "all",
319
- ["==", ["get", "provider_id"], 131_425],
320
- ],
254
+ filter: ["all", ["==", ["get", "provider_id"], 131_425]],
321
255
  minzoom: 10,
322
256
  type: "heatmap",
323
257
  layout: {
@@ -325,7 +259,6 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
325
259
  },
326
260
  paint: {
327
261
  "heatmap-color": [
328
- // ---
329
262
  "interpolate",
330
263
  ["linear"],
331
264
  ["heatmap-density"],
@@ -334,22 +267,8 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
334
267
  }).flat(),
335
268
  ],
336
269
 
337
- "heatmap-radius": [
338
- // ---
339
- "interpolate",
340
- ["linear"],
341
- ["zoom"],
342
- 10,
343
- 5,
344
- 15,
345
- 20,
346
- ],
347
- "heatmap-weight": [
348
- // ---
349
- "*",
350
- ["get", "land_area_sqm"],
351
- 0.00001,
352
- ],
270
+ "heatmap-radius": ["interpolate", ["linear"], ["zoom"], 10, 5, 15, 20],
271
+ "heatmap-weight": ["*", ["get", "land_area_sqm"], 0.00001],
353
272
  },
354
273
  }),
355
274
 
@@ -381,30 +300,17 @@ export const BroadbandDataCollectionLayers: BDCLayerSpecificationInput[] = [
381
300
  source: "composite",
382
301
  "source-layer": "DataCentersCombined20220921",
383
302
  layout: {
384
- // visibility: "none",
385
303
  "text-field": ["get", "Category"],
386
304
  "text-size": 12,
387
305
  "text-anchor": "top",
388
306
  "text-offset": [0, 0.5],
389
- // "text-allow-overlap": true,
390
307
  "text-font": ["Fira Code Regular"],
391
308
  },
392
309
  paint: {
393
310
  "text-color": "#fff",
394
311
  "text-halo-color": "#fb8429",
395
312
  "text-halo-width": 1,
396
- "text-opacity": [
397
- // We fade out the outline at higher zoom levels
398
- "interpolate",
399
- ["linear"],
400
- ["zoom"],
401
- 1,
402
- 0.01,
403
- 6,
404
- 0.5,
405
- 16,
406
- 1,
407
- ],
313
+ "text-opacity": ["interpolate", ["linear"], ["zoom"], 1, 0.01, 6, 0.5, 16, 1],
408
314
  },
409
315
  },
410
316
  ]
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @copyright Sister Software.
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Address-coverage overlays rendered from the `mailwoman coverage build` H3 tile set. Each cell
7
+ * supplies optimistic (`fog_opt`) and observed-coverage (`fog`) values. The demo exposes both as
8
+ * default-off layers. Tiles are served from `coverage-v5.pmtiles`.
9
+ */
10
+
11
+ import type { FillLayerSpecification, VectorSourceSpecification } from "@maplibre/maplibre-gl-style-spec"
12
+
13
+ import { TileSetSourceID } from "#styles/sources"
14
+
15
+ /**
16
+ * MapLibre source ID for the v5 coverage tiles.
17
+ * Keep it aligned with the archive and layer specs.
18
+ */
19
+ export const CoverageTileSetID = TileSetSourceID("coverage-v5")
20
+
21
+ /**
22
+ * Source-layer name stored in the coverage archive.
23
+ */
24
+ export const COVERAGE_SOURCE_LAYER = "coverage"
25
+
26
+ /**
27
+ * Near-black indigo used to mark unknown or unsurveyed areas.
28
+ */
29
+ export const COVERAGE_FOG_COLOR = "#663399" // Rebecca Purple
30
+
31
+ /**
32
+ * Maximum opacity for an uncovered cell.
33
+ */
34
+ export const COVERAGE_MAX_FOG_OPACITY = 0.9
35
+
36
+ /**
37
+ * IDs for the optimistic and observed-coverage layers.
38
+ */
39
+ export const CoverageLayerID = {
40
+ optimistic: "coverage-opt-fog",
41
+ honest: "coverage-honest-fog",
42
+ } as const
43
+
44
+ /**
45
+ * Create a vector source from its TileJSON URL.
46
+ */
47
+ export function createCoverageSource(url: string): VectorSourceSpecification {
48
+ return { type: "vector", url }
49
+ }
50
+
51
+ function fogFill(id: string, fogProperty: "fog" | "fog_opt"): FillLayerSpecification {
52
+ return {
53
+ id,
54
+ type: "fill",
55
+ source: CoverageTileSetID,
56
+ "source-layer": COVERAGE_SOURCE_LAYER,
57
+ // Keep coverage overlays hidden until selected.
58
+ layout: { visibility: "none" },
59
+ paint: {
60
+ "fill-color": COVERAGE_FOG_COLOR,
61
+ // Rows without coverage values render as clear.
62
+ "fill-opacity": ["*", ["coalesce", ["to-number", ["get", fogProperty]], 0], COVERAGE_MAX_FOG_OPACITY],
63
+ },
64
+ }
65
+ }
66
+
67
+ /**
68
+ * The two hidden fog layers, added beneath place labels by the demo.
69
+ */
70
+ export const CoverageLayers: FillLayerSpecification[] = [
71
+ fogFill(CoverageLayerID.optimistic, "fog_opt"),
72
+ fogFill(CoverageLayerID.honest, "fog"),
73
+ ]
package/lib/index.ts CHANGED
@@ -4,9 +4,9 @@
4
4
  * @author Teffen Ellis, et al.
5
5
  */
6
6
 
7
- export * from "#base/index"
8
- export * from "#bdc/index"
9
- export * from "#hspa/index"
10
- export * from "#styles/index"
11
- export * from "#tiger/index"
12
- export * from "#tiles/index"
7
+ export * from "#base"
8
+ export * from "#bdc"
9
+ export * from "#hspa"
10
+ export * from "#styles"
11
+ export * from "#tiger"
12
+ export * from "#tiles"