maplibre-gl-layer-control 0.4.0 → 0.5.1

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 CHANGED
@@ -11,6 +11,7 @@ A comprehensive layer control for MapLibre GL with advanced styling capabilities
11
11
  - ✅ **Auto-detection** - Automatically detects layer properties (opacity, visibility) and generates friendly names
12
12
  - ✅ **Layer visibility toggle** - Checkbox control for each layer
13
13
  - ✅ **Layer opacity control** - Smooth opacity slider with type-aware property mapping
14
+ - ✅ **Layer symbols** - Visual type indicators (colored shapes) next to layer names, auto-detected from layer paint properties
14
15
  - ✅ **Resizable panel** - Adjustable panel width (240-420px) with keyboard support
15
16
  - ✅ **Advanced style editor** - Per-layer-type styling controls:
16
17
  - **Fill layers**: color, opacity, outline-color
@@ -153,8 +154,11 @@ function MapComponent() {
153
154
  | `panelWidth` | `number` | `320` | Initial panel width in pixels |
154
155
  | `panelMinWidth` | `number` | `240` | Minimum panel width |
155
156
  | `panelMaxWidth` | `number` | `420` | Maximum panel width |
157
+ | `panelMaxHeight` | `number` | `600` | Maximum panel height (scrollable when exceeded) |
156
158
  | `showStyleEditor` | `boolean` | `true` | Show gear icon for style editor |
157
159
  | `showOpacitySlider` | `boolean` | `true` | Show opacity slider for layers |
160
+ | `showLayerSymbol` | `boolean` | `true` | Show layer type symbols (colored icons) next to layer names |
161
+ | `excludeDrawnLayers` | `boolean` | `true` | Exclude layers from drawing libraries (Geoman, Mapbox GL Draw, etc.) |
158
162
 
159
163
  ### LayerState
160
164
 
@@ -175,6 +179,33 @@ See the [examples](./examples) folder for complete working examples:
175
179
  - **[background-legend](./examples/background-legend)** - Background layer visibility control
176
180
  - **[react](./examples/react)** - React integration example
177
181
 
182
+ ### Layer Symbols
183
+
184
+ The layer control displays visual symbols (colored icons) next to each layer name to indicate the layer type. Symbols are automatically generated based on the layer's type and paint properties:
185
+
186
+ | Layer Type | Symbol |
187
+ |------------|--------|
188
+ | `fill` | Colored rectangle with border |
189
+ | `line` | Horizontal line |
190
+ | `circle` | Colored circle |
191
+ | `symbol` | Marker/pin icon |
192
+ | `raster` | Gradient rectangle |
193
+ | `heatmap` | Orange-red gradient |
194
+ | `hillshade` | Gray gradient |
195
+ | `fill-extrusion` | 3D rectangle |
196
+ | `background` | Rectangle with inner border |
197
+ | Background group | Stacked layers icon |
198
+
199
+ The symbol color is automatically extracted from the layer's paint properties (e.g., `fill-color`, `line-color`, `circle-color`). If a color cannot be determined, a neutral gray is used.
200
+
201
+ To disable layer symbols:
202
+
203
+ ```typescript
204
+ const layerControl = new LayerControl({
205
+ showLayerSymbol: false
206
+ });
207
+ ```
208
+
178
209
  ### Background Layer Legend
179
210
 
180
211
  When using the `layers` option to specify specific layers, all other layers are grouped under a "Background" entry. The Background layer includes a **gear icon** that opens a detailed legend panel showing:
package/dist/index.cjs CHANGED
@@ -168,6 +168,258 @@ function formatNumericValue(value, step) {
168
168
  function clamp(value, min, max) {
169
169
  return Math.max(min, Math.min(max, value));
170
170
  }
171
+ const COLOR_PROPERTY_MAP = {
172
+ fill: ["fill-color", "fill-outline-color"],
173
+ line: ["line-color"],
174
+ circle: ["circle-color", "circle-stroke-color"],
175
+ symbol: ["icon-color", "text-color"],
176
+ background: ["background-color"],
177
+ heatmap: ["heatmap-color"],
178
+ "fill-extrusion": ["fill-extrusion-color"]
179
+ };
180
+ function extractColorFromExpression(expression) {
181
+ if (!Array.isArray(expression) || expression.length === 0) return null;
182
+ for (const item of expression) {
183
+ if (typeof item === "string") {
184
+ if (item.startsWith("#") || item.startsWith("rgb") || item.startsWith("hsl")) {
185
+ return normalizeColor(item);
186
+ }
187
+ } else if (Array.isArray(item)) {
188
+ const result = extractColorFromExpression(item);
189
+ if (result) return result;
190
+ }
191
+ }
192
+ return null;
193
+ }
194
+ function getLayerColor(map, layerId, layerType) {
195
+ var _a;
196
+ const propertyNames = COLOR_PROPERTY_MAP[layerType];
197
+ if (!propertyNames) return null;
198
+ for (const propertyName of propertyNames) {
199
+ try {
200
+ const runtimeColor = map.getPaintProperty(layerId, propertyName);
201
+ if (runtimeColor) {
202
+ if (typeof runtimeColor === "string") {
203
+ return normalizeColor(runtimeColor);
204
+ }
205
+ if (Array.isArray(runtimeColor)) {
206
+ const extracted = extractColorFromExpression(runtimeColor);
207
+ if (extracted) return extracted;
208
+ }
209
+ }
210
+ } catch {
211
+ }
212
+ const style = map.getStyle();
213
+ const layer = (_a = style == null ? void 0 : style.layers) == null ? void 0 : _a.find(
214
+ (l) => l.id === layerId
215
+ );
216
+ if (layer && "paint" in layer && layer.paint) {
217
+ const paintColor = layer.paint[propertyName];
218
+ if (paintColor) {
219
+ if (typeof paintColor === "string") {
220
+ return normalizeColor(paintColor);
221
+ }
222
+ if (Array.isArray(paintColor)) {
223
+ const extracted = extractColorFromExpression(paintColor);
224
+ if (extracted) return extracted;
225
+ }
226
+ }
227
+ }
228
+ }
229
+ return null;
230
+ }
231
+ function getLayerColorFromSpec(layer) {
232
+ const propertyNames = COLOR_PROPERTY_MAP[layer.type];
233
+ if (!propertyNames) return null;
234
+ for (const propertyName of propertyNames) {
235
+ if ("paint" in layer && layer.paint) {
236
+ const paintColor = layer.paint[propertyName];
237
+ if (paintColor) {
238
+ if (typeof paintColor === "string") {
239
+ return normalizeColor(paintColor);
240
+ }
241
+ if (Array.isArray(paintColor)) {
242
+ const extracted = extractColorFromExpression(paintColor);
243
+ if (extracted) return extracted;
244
+ }
245
+ }
246
+ }
247
+ }
248
+ return null;
249
+ }
250
+ function darkenColor(hexColor, amount) {
251
+ let hex = hexColor.replace("#", "");
252
+ if (hex.length === 3) {
253
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
254
+ }
255
+ const r = Math.max(
256
+ 0,
257
+ parseInt(hex.slice(0, 2), 16) - Math.round(255 * amount)
258
+ );
259
+ const g = Math.max(
260
+ 0,
261
+ parseInt(hex.slice(2, 4), 16) - Math.round(255 * amount)
262
+ );
263
+ const b = Math.max(
264
+ 0,
265
+ parseInt(hex.slice(4, 6), 16) - Math.round(255 * amount)
266
+ );
267
+ return rgbToHex(r, g, b);
268
+ }
269
+ function createFillSymbol(size, color) {
270
+ const padding = 2;
271
+ const borderColor = darkenColor(color, 0.3);
272
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
273
+ <rect x="${padding}" y="${padding}" width="${size - padding * 2}" height="${size - padding * 2}"
274
+ fill="${color}" stroke="${borderColor}" stroke-width="1" rx="1"/>
275
+ </svg>`;
276
+ }
277
+ function createLineSymbol(size, color, strokeWidth = 2) {
278
+ const y = size / 2;
279
+ const padding = 2;
280
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
281
+ <line x1="${padding}" y1="${y}" x2="${size - padding}" y2="${y}"
282
+ stroke="${color}" stroke-width="${strokeWidth}" stroke-linecap="round"/>
283
+ </svg>`;
284
+ }
285
+ function createCircleSymbol(size, color) {
286
+ const cx = size / 2;
287
+ const cy = size / 2;
288
+ const r = size / 2 - 3;
289
+ const borderColor = darkenColor(color, 0.3);
290
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
291
+ <circle cx="${cx}" cy="${cy}" r="${r}" fill="${color}"
292
+ stroke="${borderColor}" stroke-width="1"/>
293
+ </svg>`;
294
+ }
295
+ function createMarkerSymbol(size, color) {
296
+ const borderColor = darkenColor(color, 0.3);
297
+ const cx = size / 2;
298
+ const pinWidth = size * 0.5;
299
+ const pinHeight = size * 0.7;
300
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
301
+ <path d="M${cx} ${size - 2}
302
+ L${cx - pinWidth / 2} ${size - pinHeight}
303
+ A${pinWidth / 2} ${pinWidth / 2} 0 1 1 ${cx + pinWidth / 2} ${size - pinHeight}
304
+ Z"
305
+ fill="${color}" stroke="${borderColor}" stroke-width="1"/>
306
+ <circle cx="${cx}" cy="${size - pinHeight - pinWidth / 4}" r="${pinWidth / 5}" fill="white"/>
307
+ </svg>`;
308
+ }
309
+ function createRasterSymbol(size) {
310
+ const padding = 2;
311
+ const id = `rasterGrad_${Math.random().toString(36).slice(2, 9)}`;
312
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
313
+ <defs>
314
+ <linearGradient id="${id}" x1="0%" y1="0%" x2="100%" y2="100%">
315
+ <stop offset="0%" stop-color="#e0e0e0"/>
316
+ <stop offset="50%" stop-color="#808080"/>
317
+ <stop offset="100%" stop-color="#404040"/>
318
+ </linearGradient>
319
+ </defs>
320
+ <rect x="${padding}" y="${padding}" width="${size - padding * 2}" height="${size - padding * 2}"
321
+ fill="url(#${id})" rx="1"/>
322
+ </svg>`;
323
+ }
324
+ function createBackgroundSymbol(size, color) {
325
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
326
+ <rect x="1" y="1" width="${size - 2}" height="${size - 2}" fill="${color}" rx="2"/>
327
+ <rect x="3" y="3" width="${size - 6}" height="${size - 6}" fill="none"
328
+ stroke="white" stroke-width="1" stroke-opacity="0.5" rx="1"/>
329
+ </svg>`;
330
+ }
331
+ function createHeatmapSymbol(size) {
332
+ const padding = 2;
333
+ const id = `heatmapGrad_${Math.random().toString(36).slice(2, 9)}`;
334
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
335
+ <defs>
336
+ <radialGradient id="${id}" cx="50%" cy="50%" r="50%">
337
+ <stop offset="0%" stop-color="#ffff00"/>
338
+ <stop offset="50%" stop-color="#ff8800"/>
339
+ <stop offset="100%" stop-color="#ff0000"/>
340
+ </radialGradient>
341
+ </defs>
342
+ <rect x="${padding}" y="${padding}" width="${size - padding * 2}" height="${size - padding * 2}"
343
+ fill="url(#${id})" rx="1"/>
344
+ </svg>`;
345
+ }
346
+ function createHillshadeSymbol(size) {
347
+ const padding = 2;
348
+ const id = `hillshadeGrad_${Math.random().toString(36).slice(2, 9)}`;
349
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
350
+ <defs>
351
+ <linearGradient id="${id}" x1="0%" y1="0%" x2="100%" y2="100%">
352
+ <stop offset="0%" stop-color="#ffffff"/>
353
+ <stop offset="100%" stop-color="#666666"/>
354
+ </linearGradient>
355
+ </defs>
356
+ <rect x="${padding}" y="${padding}" width="${size - padding * 2}" height="${size - padding * 2}"
357
+ fill="url(#${id})" rx="1"/>
358
+ </svg>`;
359
+ }
360
+ function createFillExtrusionSymbol(size, color) {
361
+ const borderColor = darkenColor(color, 0.3);
362
+ const topColor = color;
363
+ const sideColor = darkenColor(color, 0.2);
364
+ const depth = 3;
365
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
366
+ <polygon points="${2 + depth},2 ${size - 2},2 ${size - 2},${size - 2 - depth} ${size - 2 - depth},${size - 2} 2,${size - 2} 2,${2 + depth}"
367
+ fill="${topColor}" stroke="${borderColor}" stroke-width="1"/>
368
+ <polygon points="2,${2 + depth} ${2 + depth},2 ${2 + depth},${size - 2 - depth} 2,${size - 2}"
369
+ fill="${sideColor}" stroke="${borderColor}" stroke-width="0.5"/>
370
+ <polygon points="${2 + depth},${size - 2 - depth} ${size - 2},${size - 2 - depth} ${size - 2 - depth},${size - 2} 2,${size - 2}"
371
+ fill="${sideColor}" stroke="${borderColor}" stroke-width="0.5"/>
372
+ </svg>`;
373
+ }
374
+ function createDefaultSymbol(size, color) {
375
+ const padding = 2;
376
+ const borderColor = darkenColor(color, 0.3);
377
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
378
+ <rect x="${padding}" y="${padding}" width="${size - padding * 2}" height="${size - padding * 2}"
379
+ fill="${color}" stroke="${borderColor}" stroke-width="1"/>
380
+ </svg>`;
381
+ }
382
+ function createStackedLayersSymbol(size) {
383
+ const colors = ["#a8d4a8", "#8ec4e8", "#d4c4a8"];
384
+ const borderColor = "#666666";
385
+ return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
386
+ <rect x="4" y="1" width="${size - 6}" height="${size - 6}" fill="${colors[2]}" stroke="${borderColor}" stroke-width="0.75" rx="1"/>
387
+ <rect x="2" y="3" width="${size - 6}" height="${size - 6}" fill="${colors[1]}" stroke="${borderColor}" stroke-width="0.75" rx="1"/>
388
+ <rect x="0" y="5" width="${size - 6}" height="${size - 6}" fill="${colors[0]}" stroke="${borderColor}" stroke-width="0.75" rx="1"/>
389
+ </svg>`;
390
+ }
391
+ function createLayerSymbolSVG(layerType, color, options = {}) {
392
+ const size = options.size || 16;
393
+ const strokeWidth = options.strokeWidth || 2;
394
+ const fillColor = color || "#888888";
395
+ switch (layerType) {
396
+ case "fill":
397
+ return createFillSymbol(size, fillColor);
398
+ case "line":
399
+ return createLineSymbol(size, fillColor, strokeWidth);
400
+ case "circle":
401
+ return createCircleSymbol(size, fillColor);
402
+ case "symbol":
403
+ return createMarkerSymbol(size, fillColor);
404
+ case "raster":
405
+ return createRasterSymbol(size);
406
+ case "background":
407
+ return createBackgroundSymbol(size, fillColor);
408
+ case "heatmap":
409
+ return createHeatmapSymbol(size);
410
+ case "hillshade":
411
+ return createHillshadeSymbol(size);
412
+ case "fill-extrusion":
413
+ return createFillExtrusionSymbol(size, fillColor);
414
+ case "background-group":
415
+ return createStackedLayersSymbol(size);
416
+ default:
417
+ return createDefaultSymbol(size, fillColor);
418
+ }
419
+ }
420
+ function createBackgroundGroupSymbolSVG(size = 16) {
421
+ return createStackedLayersSymbol(size);
422
+ }
171
423
  class LayerControl {
172
424
  constructor(options = {}) {
173
425
  __publicField(this, "map");
@@ -181,8 +433,11 @@ class LayerControl {
181
433
  // Panel width management
182
434
  __publicField(this, "minPanelWidth");
183
435
  __publicField(this, "maxPanelWidth");
436
+ __publicField(this, "maxPanelHeight");
184
437
  __publicField(this, "showStyleEditor");
185
438
  __publicField(this, "showOpacitySlider");
439
+ __publicField(this, "showLayerSymbol");
440
+ __publicField(this, "excludeDrawnLayers");
186
441
  __publicField(this, "widthSliderEl", null);
187
442
  __publicField(this, "widthThumbEl", null);
188
443
  __publicField(this, "widthValueEl", null);
@@ -193,8 +448,11 @@ class LayerControl {
193
448
  __publicField(this, "widthFrame", null);
194
449
  this.minPanelWidth = options.panelMinWidth || 240;
195
450
  this.maxPanelWidth = options.panelMaxWidth || 420;
451
+ this.maxPanelHeight = options.panelMaxHeight || 600;
196
452
  this.showStyleEditor = options.showStyleEditor !== false;
197
453
  this.showOpacitySlider = options.showOpacitySlider !== false;
454
+ this.showLayerSymbol = options.showLayerSymbol !== false;
455
+ this.excludeDrawnLayers = options.excludeDrawnLayers !== false;
198
456
  this.state = {
199
457
  collapsed: options.collapsed !== false,
200
458
  panelWidth: options.panelWidth || 320,
@@ -250,6 +508,10 @@ class LayerControl {
250
508
  allLayerIds.forEach((layerId) => {
251
509
  const layer = this.map.getLayer(layerId);
252
510
  if (!layer) return;
511
+ if (this.excludeDrawnLayers && this.isDrawnLayer(layerId)) {
512
+ backgroundLayerIds.push(layerId);
513
+ return;
514
+ }
253
515
  const sourceId = layer.source;
254
516
  if (!sourceId || originalSourceIds.has(sourceId)) {
255
517
  backgroundLayerIds.push(layerId);
@@ -375,6 +637,28 @@ class LayerControl {
375
637
  name = name.replace(/\b\w/g, (char) => char.toUpperCase());
376
638
  return name || layerId;
377
639
  }
640
+ /**
641
+ * Check if a layer ID belongs to a drawing library (Geoman, Mapbox GL Draw, etc.)
642
+ * @param layerId The layer ID to check
643
+ * @returns true if the layer is from a drawing library
644
+ */
645
+ isDrawnLayer(layerId) {
646
+ const drawnLayerPatterns = [
647
+ /^gm[-_\s]/i,
648
+ // Geoman (gm-main-*, gm_*, Gm Temporary...)
649
+ /^gl-draw[-_]/i,
650
+ // Mapbox GL Draw
651
+ /^mapbox-gl-draw[-_]/i,
652
+ // Mapbox GL Draw alternative
653
+ /^terra-draw[-_]/i,
654
+ // Terra Draw
655
+ /^maplibre-gl-draw[-_]/i,
656
+ // MapLibre GL Draw
657
+ /^draw[-_]layer/i
658
+ // Generic draw layers
659
+ ];
660
+ return drawnLayerPatterns.some((pattern) => pattern.test(layerId));
661
+ }
378
662
  /**
379
663
  * Create the main container element
380
664
  */
@@ -404,6 +688,7 @@ class LayerControl {
404
688
  const panel = document.createElement("div");
405
689
  panel.className = "layer-control-panel";
406
690
  panel.style.width = `${this.state.panelWidth}px`;
691
+ panel.style.maxHeight = `${this.maxPanelHeight}px`;
407
692
  if (!this.state.collapsed) {
408
693
  panel.classList.add("expanded");
409
694
  }
@@ -739,6 +1024,17 @@ class LayerControl {
739
1024
  name.textContent = state.name || layerId;
740
1025
  name.title = state.name || layerId;
741
1026
  row.appendChild(checkbox);
1027
+ if (this.showLayerSymbol) {
1028
+ if (layerId === "Background") {
1029
+ const symbol = this.createBackgroundGroupSymbol();
1030
+ row.appendChild(symbol);
1031
+ } else {
1032
+ const symbol = this.createLayerSymbol(layerId);
1033
+ if (symbol) {
1034
+ row.appendChild(symbol);
1035
+ }
1036
+ }
1037
+ }
742
1038
  row.appendChild(name);
743
1039
  if (this.showOpacitySlider) {
744
1040
  const opacity = document.createElement("input");
@@ -775,6 +1071,50 @@ class LayerControl {
775
1071
  item.appendChild(row);
776
1072
  this.panel.appendChild(item);
777
1073
  }
1074
+ /**
1075
+ * Create a symbol element for a layer
1076
+ * @param layerId The layer ID
1077
+ * @returns The symbol HTML element, or null if layer not found
1078
+ */
1079
+ createLayerSymbol(layerId) {
1080
+ const layer = this.map.getLayer(layerId);
1081
+ if (!layer) return null;
1082
+ const layerType = layer.type;
1083
+ const color = getLayerColor(this.map, layerId, layerType);
1084
+ const svgMarkup = createLayerSymbolSVG(layerType, color);
1085
+ const symbolContainer = document.createElement("span");
1086
+ symbolContainer.className = "layer-control-symbol";
1087
+ symbolContainer.innerHTML = svgMarkup;
1088
+ symbolContainer.title = `Layer type: ${layerType}`;
1089
+ return symbolContainer;
1090
+ }
1091
+ /**
1092
+ * Create a symbol element for a background layer
1093
+ * @param layer The layer specification
1094
+ * @returns The symbol HTML element
1095
+ */
1096
+ createBackgroundLayerSymbol(layer) {
1097
+ const color = getLayerColorFromSpec(layer);
1098
+ const svgMarkup = createLayerSymbolSVG(layer.type, color, { size: 14 });
1099
+ const symbolContainer = document.createElement("span");
1100
+ symbolContainer.className = "background-legend-layer-symbol";
1101
+ symbolContainer.innerHTML = svgMarkup;
1102
+ symbolContainer.title = `Layer type: ${layer.type}`;
1103
+ return symbolContainer;
1104
+ }
1105
+ /**
1106
+ * Create a symbol element for the Background layer group
1107
+ * Shows a stacked layers icon to represent multiple background layers
1108
+ * @returns The symbol HTML element
1109
+ */
1110
+ createBackgroundGroupSymbol() {
1111
+ const svgMarkup = createBackgroundGroupSymbolSVG(16);
1112
+ const symbolContainer = document.createElement("span");
1113
+ symbolContainer.className = "layer-control-symbol";
1114
+ symbolContainer.innerHTML = svgMarkup;
1115
+ symbolContainer.title = "Background layers";
1116
+ return symbolContainer;
1117
+ }
778
1118
  /**
779
1119
  * Toggle layer visibility
780
1120
  */
@@ -1015,6 +1355,9 @@ class LayerControl {
1015
1355
  const styleLayers = this.map.getStyle().layers || [];
1016
1356
  styleLayers.forEach((layer) => {
1017
1357
  if (!this.isUserAddedLayer(layer.id)) {
1358
+ if (this.excludeDrawnLayers && this.isDrawnLayer(layer.id)) {
1359
+ return;
1360
+ }
1018
1361
  if (this.state.onlyRenderedFilter && !this.isLayerRendered(layer.id)) {
1019
1362
  return;
1020
1363
  }
@@ -1039,6 +1382,12 @@ class LayerControl {
1039
1382
  typeIndicator.className = "background-legend-layer-type";
1040
1383
  typeIndicator.textContent = layer.type;
1041
1384
  layerRow.appendChild(checkbox);
1385
+ if (this.showLayerSymbol) {
1386
+ const symbol = this.createBackgroundLayerSymbol(layer);
1387
+ if (symbol) {
1388
+ layerRow.appendChild(symbol);
1389
+ }
1390
+ }
1042
1391
  layerRow.appendChild(name);
1043
1392
  layerRow.appendChild(typeIndicator);
1044
1393
  container.appendChild(layerRow);
@@ -1528,6 +1877,9 @@ class LayerControl {
1528
1877
  const layer = this.map.getLayer(layerId);
1529
1878
  if (layer) {
1530
1879
  if (isAutoDetectMode) {
1880
+ if (this.excludeDrawnLayers && this.isDrawnLayer(layerId)) {
1881
+ return;
1882
+ }
1531
1883
  const sourceId = layer.source;
1532
1884
  if (!sourceId || originalSourceIds.has(sourceId)) {
1533
1885
  return;
@@ -1579,7 +1931,12 @@ class LayerControl {
1579
1931
  }
1580
1932
  exports.LayerControl = LayerControl;
1581
1933
  exports.clamp = clamp;
1934
+ exports.createBackgroundGroupSymbolSVG = createBackgroundGroupSymbolSVG;
1935
+ exports.createLayerSymbolSVG = createLayerSymbolSVG;
1936
+ exports.darkenColor = darkenColor;
1582
1937
  exports.formatNumericValue = formatNumericValue;
1938
+ exports.getLayerColor = getLayerColor;
1939
+ exports.getLayerColorFromSpec = getLayerColorFromSpec;
1583
1940
  exports.getLayerOpacity = getLayerOpacity;
1584
1941
  exports.getLayerType = getLayerType;
1585
1942
  exports.isStyleableLayerType = isStyleableLayerType;