Atlaslog
Atlaslog / Examples / Leaflet / Popup Position
Leaflet · Runnable Example

Popup Position

Runnable Leaflet example: Popup Position. 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-popup-position.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/leaflet-popup-position.html
<!--
  示例:Popup 定位
  要点:autoPan / keepInView / offset / maxWidth 对边缘气泡的影响、每次按新选项重建气泡
  依赖: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>Popup 定位</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:8px;align-items:center;flex-wrap:wrap;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 button.on{background:#1f5fd0;border-color:#1f5fd0;color:#fff}
  .bar b{color:#16181d;font-weight:600;font-variant-numeric:tabular-nums}
  .bar .sep{width:1px;height:16px;background:#dfe3e9}
  #map{flex:1 1 auto;min-height:0}
  .pin{width:14px;height:14px;border-radius:50%;background:#c2410c;border:2px solid #fff;
    box-shadow:0 0 0 1px rgba(0,0,0,.28)}
  .pop{font-size:12px;line-height:1.6;color:#3b4350}
  .pop h4{margin:0 0 4px;font-size:13px;color:#16181d}
  .pop .kv{color:#58606e}
</style>
</head>
<body>
<div class="bar">
  <button id="pan" class="on">autoPan:开</button>
  <button id="keep">keepInView:关</button>
  <button id="width">宽度 240</button>
  <button id="offset">偏移 -10</button>
  <button data-act="open">打开气泡</button>
  <span class="sep"></span>
  <b id="readout">autoPan ✓ · keepInView ✗ · 240px · [0,-10]</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.907359, 116.391263], 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);

  /* 落点贴住右边缘:气泡必定越界,正好用来看 autoPan 的效果 */
  var edge = map.containerPointToLatLng([map.getSize().x - 36, map.getSize().y / 2]);

  L.marker(edge, {
    icon: L.divIcon({
      className: '',
      html: '<div class="pin"></div>',
      iconSize: [14, 14],
      iconAnchor: [7, 7]
    })
  }).addTo(map);

  var opts = {
    autoPan: true,
    keepInView: false,
    maxWidth: 240,
    minWidth: 120,
    offset: [0, -10],
    closeButton: true
  };

  var popup = null;

  var content =
    '<div class="pop"><h4>王府井步行街监测点</h4>' +
    '<div class="kv">编号 A-0327 · 客流 2.4 万/日</div>' +
    '<div class="kv">设备状态正常,最近上报 8 分钟前</div></div>';

  function readout() {
    document.getElementById('readout').textContent =
      'autoPan ' + (opts.autoPan ? '✓' : '✗') +
      ' · keepInView ' + (opts.keepInView ? '✓' : '✗') +
      ' · ' + opts.maxWidth + 'px' +
      ' · [' + opts.offset[0] + ',' + opts.offset[1] + ']';
  }

  function open() {
    if (popup) map.closePopup(popup);

    /* 气泡选项在打开时读取,改完必须重建 */
    popup = L.popup({
      autoPan: opts.autoPan,
      keepInView: opts.keepInView,
      maxWidth: opts.maxWidth,
      minWidth: opts.minWidth,
      offset: opts.offset,
      closeButton: opts.closeButton,
      autoPanPadding: [20, 20]
    })
      .setLatLng(edge)
      .setContent(content)
      .openOn(map);
  }

  document.getElementById('pan').addEventListener('click', function () {
    opts.autoPan = !opts.autoPan;
    this.textContent = 'autoPan:' + (opts.autoPan ? '开' : '关');
    this.classList.toggle('on', opts.autoPan);
    readout();
    open();
  });

  document.getElementById('keep').addEventListener('click', function () {
    opts.keepInView = !opts.keepInView;
    this.textContent = 'keepInView:' + (opts.keepInView ? '开' : '关');
    this.classList.toggle('on', opts.keepInView);
    readout();
    open();
  });

  var wide = true;
  document.getElementById('width').addEventListener('click', function () {
    wide = !wide;
    opts.maxWidth = wide ? 240 : 110;
    this.textContent = '宽度 ' + opts.maxWidth;
    readout();
    open();
  });

  var far = true;
  document.getElementById('offset').addEventListener('click', function () {
    far = !far;
    opts.offset = far ? [0, -10] : [0, -48];
    this.textContent = '偏移 ' + opts.offset[1];
    readout();
    open();
  });

  document.querySelector('[data-act="open"]').addEventListener('click', open);

  map.on('popupopen', function () {
    console.log('气泡已打开,中心', map.getCenter().lng.toFixed(4));
  });

  /* 打开一次,直接看到边缘定位效果 */
  open();
})();
</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 · EXAMPLEScale Control Leaflet · EXAMPLETile Cache Leaflet · EXAMPLETile Filter