Atlaslog
Atlaslog / Examples / Leaflet / Layer Panel
Leaflet · Runnable Example

Layer Panel

Runnable Leaflet example: Layer Panel. Open the live demo, read the complete source, and copy the file into your project. No build step or API key.

Open standalone → Chinese notes All Leaflet examples
/demos/leaflet-layer-panel.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/leaflet-layer-panel.html
<!--
  示例:图层控制面板
  要点:四类覆盖物分组、勾选显隐、全选与全不选、面板与地图事件隔离
  依赖:Leaflet 1.9.4 · jsDelivr CDN + Esri 瓦片
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta name="robots" content="noindex,follow">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>图层控制面板</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css">
<style>
  html,body{height:100%;margin:0}
  body{display:flex;flex-direction:column;overflow:hidden;
       font:13px/1.6 -apple-system,"Segoe UI","PingFang SC",sans-serif}
  .bar{flex:0 0 auto;padding:8px 12px;background:#f6f7f9;border-bottom:1px solid #e3e6ea;
       display:flex;gap:10px;align-items:center;font-size:12px;color:#58606e}
  .bar .spacer{flex:1 1 auto}
  #wrap{flex:1 1 auto;position:relative;min-height:0}
  #map{position:absolute;inset:0}

  .panel{position:absolute;top:12px;right:12px;z-index:800;width:190px;
         background:#fff;border-radius:6px;box-shadow:0 2px 10px rgba(0,0,0,.18);
         padding:10px 12px;font-size:12px;color:#16181d}
  .panel h3{margin:0 0 8px;font-size:12px;font-weight:600;color:#58606e;
            letter-spacing:.04em;text-transform:uppercase}
  .panel label{display:flex;align-items:center;gap:8px;padding:4px 0;cursor:pointer}
  .panel label input{margin:0}
  .panel label .n{margin-left:auto;color:#8a919e;font-variant-numeric:tabular-nums}
  .panel .foot{display:flex;gap:6px;margin-top:8px;padding-top:8px;border-top:1px solid #eef0f3}
  .panel .foot button{flex:1;font:inherit;font-size:12px;padding:3px 0;border-radius:4px;
        cursor:pointer;border:1px solid #ccd1d9;background:#f8f9fb;color:#16181d}
  .panel .foot button:hover{background:#eef0f3}

  .pin{width:12px;height:12px;border-radius:50%;border:2px solid #fff;
       box-shadow:0 0 0 1px rgba(0,0,0,.22)}
</style>
</head>
<body>
<div class="bar">
  <span>覆盖物</span>
  <span class="spacer"></span>
  <span id="status"></span>
</div>
<div id="wrap">
  <div id="map"></div>
  <div class="panel">
    <h3>图层</h3>
    <label><input type="checkbox" data-layer="markers" checked> 标记 <span class="n">6</span></label>
    <label><input type="checkbox" data-layer="circles" checked> 圆 <span class="n">2</span></label>
    <label><input type="checkbox" data-layer="polygons" checked> 多边形 <span class="n">2</span></label>
    <label><input type="checkbox" data-layer="lines" checked> 折线 <span class="n">2</span></label>
    <div class="foot">
      <button id="all" type="button">全选</button>
      <button id="none" type="button">全不选</button>
    </div>
  </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
(function () {
  'use strict';

  var map = L.map('map', {
    center: [39.912, 116.400],
    zoom: 13
  });

  L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
    maxZoom: 19,
    attribution: 'Tiles © Esri'
  }).addTo(map);

  var groups = {
    markers: L.layerGroup(),
    circles: L.layerGroup(),
    polygons: L.layerGroup(),
    lines: L.layerGroup()
  };

  var places = [
    ['天安门', 39.907359, 116.391263, '#1f5fd0'],
    ['王府井', 39.914700, 116.410600, '#c2410c'],
    ['前门', 39.899400, 116.397500, '#17694a'],
    ['西单', 39.909700, 116.374200, '#7c3aed'],
    ['东单', 39.908800, 116.418300, '#0e7490'],
    ['崇文门', 39.899900, 116.417200, '#a16207']
  ];

  places.forEach(function (p) {
    L.marker([p[1], p[2]], {
      icon: L.divIcon({
        className: '',
        html: '<div class="pin" style="background:' + p[3] + '"></div>',
        iconSize: [12, 12],
        iconAnchor: [6, 6]
      })
    }).bindPopup('<b>' + p[0] + '</b>').addTo(groups.markers);
  });

  L.circle([39.907359, 116.391263], {
    radius: 1200, color: '#1f5fd0', weight: 1, fillOpacity: 0.08
  }).addTo(groups.circles);

  L.circle([39.914700, 116.410600], {
    radius: 800, color: '#c2410c', weight: 1, fillOpacity: 0.08
  }).addTo(groups.circles);

  L.polygon([
    [39.920, 116.380], [39.920, 116.410], [39.935, 116.410], [39.935, 116.380]
  ], { color: '#7c3aed', weight: 2, fillOpacity: 0.12 }).addTo(groups.polygons);

  L.polygon([
    [39.885, 116.400], [39.885, 116.430], [39.898, 116.430], [39.898, 116.400]
  ], { color: '#17694a', weight: 2, fillOpacity: 0.12 }).addTo(groups.polygons);

  L.polyline([
    [39.885, 116.360], [39.920, 116.375], [39.945, 116.420]
  ], { color: '#0e7490', weight: 3, dashArray: '8 6' }).addTo(groups.lines);

  L.polyline([
    [39.890, 116.440], [39.910, 116.425], [39.935, 116.445]
  ], { color: '#a16207', weight: 3 }).addTo(groups.lines);

  var order = ['markers', 'circles', 'polygons', 'lines'];
  order.forEach(function (key) {
    groups[key].addTo(map);
  });

  var boxes = document.querySelectorAll('.panel input[data-layer]');
  var status = document.getElementById('status');

  function refresh() {
    var visible = 0;
    order.forEach(function (key) {
      if (map.hasLayer(groups[key])) visible++;
    });
    status.textContent = visible + ' / ' + order.length + ' 个覆盖物分组显示中';
  }

  function apply(key, on) {
    if (on) {
      if (!map.hasLayer(groups[key])) groups[key].addTo(map);
    } else {
      if (map.hasLayer(groups[key])) map.removeLayer(groups[key]);
    }
  }

  for (var i = 0; i < boxes.length; i++) {
    boxes[i].addEventListener('change', function () {
      apply(this.getAttribute('data-layer'), this.checked);
      refresh();
    });
  }

  document.getElementById('all').addEventListener('click', function () {
    for (var i = 0; i < boxes.length; i++) boxes[i].checked = true;
    order.forEach(function (key) { apply(key, true); });
    refresh();
  });

  document.getElementById('none').addEventListener('click', function () {
    for (var i = 0; i < boxes.length; i++) boxes[i].checked = false;
    order.forEach(function (key) { apply(key, false); });
    refresh();
  });

  refresh();
})();
</script>
</body>
</html>
Language: the code and this page are in English; the full tutorial and API notes for this example are in Chinese. The demo itself is the authoritative version — it runs exactly as shown.

More Leaflet examples

Leaflet · EXAMPLEMarker Cluster Leaflet · EXAMPLEMarker Leaflet · EXAMPLEMax Bounds