Atlaslog
Atlaslog / Examples / Leaflet / Image Overlay
Leaflet · Runnable Example

Image Overlay

Runnable Leaflet example: Image Overlay. 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-image-overlay.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/leaflet-image-overlay.html
<!--
  示例:图像叠加
  要点:canvas 生成等经纬度栅格图、L.imageOverlay 按 bounds 铺图、setUrl 换帧不闪烁
  依赖:Leaflet 1.9.4 · jsDelivr CDN
-->
<!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 button{font:inherit;font-size:12px;padding:4px 10px;border-radius:4px;cursor:pointer;
       border:1px solid #ccd1d9;background:#fff;color:#16181d}
  .bar button:hover{background:#eef0f3}
  .bar input[type=range]{width:110px;vertical-align:middle}
  .bar b{color:#16181d;font-weight:600}
  #map{flex:1 1 auto;min-height:0}
</style>
</head>
<body>
<div class="bar">
  <button id="frame">换一帧</button>
  <button id="toggle">隐藏叠加</button>
  <label>透明度 <input id="opacity" type="range" min="0" max="1" step="0.05" value="0.65"></label>
  <span id="val">0.65</span>
  <b id="range">bounds 116.28–116.52E / 39.86–39.98N</b>
</div>
<div id="map"></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.92, 116.40], zoom: 11 });

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

  /* 图片四角对应的地理范围:纬度 0.12°、经度 0.24°,约 3:2,与画布比例一致 */
  var bounds = [[39.86, 116.28], [39.98, 116.52]];

  var W = 480;
  var H = 320;
  var canvas = document.createElement('canvas');
  canvas.width = W;
  canvas.height = H;

  function seeded(n) {
    var s = n || 1;
    return function () {
      s = (s * 16807) % 2147483647;
      return (s - 1) / 2147483646;
    };
  }

  /* 画一层「栅格降水」:多个径向渐变斑点叠加,透明度即数值 */
  function paint(frame) {
    var ctx = canvas.getContext('2d');
    var rand = seeded(frame * 97 + 11);
    ctx.clearRect(0, 0, W, H);

    var palette = ['rgba(37,99,235,', 'rgba(14,165,233,', 'rgba(22,163,74,',
                   'rgba(234,179,8,', 'rgba(220,38,38,'];

    for (var i = 0; i < 26; i++) {
      var cx = rand() * W;
      var cy = rand() * H;
      var r = 26 + rand() * 70;
      var color = palette[Math.min(palette.length - 1, Math.floor(rand() * palette.length))];
      var g = ctx.createRadialGradient(cx, cy, 2, cx, cy, r);
      g.addColorStop(0, color + '0.85)');
      g.addColorStop(0.55, color + '0.35)');
      g.addColorStop(1, color + '0)');
      ctx.fillStyle = g;
      ctx.beginPath();
      ctx.arc(cx, cy, r, 0, Math.PI * 2);
      ctx.fill();
    }

    ctx.font = '12px sans-serif';
    ctx.fillStyle = 'rgba(22,24,29,0.55)';
    ctx.fillText('模拟栅格 · 帧 ' + frame, 10, H - 12);
  }

  paint(1);

  var overlay = L.imageOverlay(canvas.toDataURL('image/png'), bounds, {
    opacity: 0.65,
    zIndex: 2,
    interactive: false
  }).addTo(map);

  var frame = 1;
  document.getElementById('frame').addEventListener('click', function () {
    frame += 1;
    paint(frame);
    /* 用 setUrl 换图,DOM 节点复用,不会闪一下白底 */
    overlay.setUrl(canvas.toDataURL('image/png'));
  });

  document.getElementById('opacity').addEventListener('input', function () {
    overlay.setOpacity(Number(this.value));
    document.getElementById('val').textContent = this.value;
  });

  var shown = true;
  document.getElementById('toggle').addEventListener('click', function () {
    shown = !shown;
    if (shown) {
      overlay.addTo(map);
      this.textContent = '隐藏叠加';
    } else {
      map.removeLayer(overlay);
      this.textContent = '显示叠加';
    }
  });

  /* 叠加图不参与交互,点击仍然落到地图上 */
  map.on('click', function (e) {
    console.log('地图点击', e.latlng.lat.toFixed(5), e.latlng.lng.toFixed(5));
  });
})();
</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 · EXAMPLEInertia Leaflet · EXAMPLELayer Panel Leaflet · EXAMPLEMarker Cluster