Inertia
Runnable Leaflet example: Inertia. Open the live demo, read the complete source, and copy the file into your project. No build step or API key.
single HTML file · CDN dependencies onlyinterface may contain Chinese labels
Source
<!--
示例:惯性拖拽
要点:inertia / inertiaDeceleration / inertiaMaxSpeed / easeLinearity 的效果差异、松手后滑行距离测量
依赖: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: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;background:#edf0f4}
#log{position:absolute;left:12px;bottom:12px;z-index:600;background:rgba(22,24,29,.86);
color:#e9edf2;font:11px/1.7 Consolas,monospace;padding:6px 9px;border-radius:5px;
max-width:280px;pointer-events:none}
</style>
</head>
<body>
<div class="bar">
<button data-preset="off">无惯性</button>
<button data-preset="default" class="on">默认</button>
<button data-preset="far">强惯性</button>
<button data-preset="short">短滑行</button>
<span class="sep"></span>
<span>减速 <b id="dec">3400</b> px/s² · 上限 <b id="max">∞</b></span>
</div>
<div id="map"></div>
<div id="log">按住地图快速甩动,松手后观察滑行距离</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,
/* 这三项是 Map 的默认值,上限默认不设,即无穷大 */
inertia: true,
inertiaDeceleration: 3400,
inertiaMaxSpeed: Infinity,
easeLinearity: 0.2
});
L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', {
maxZoom: 19,
attribution: 'Tiles © Esri'
}).addTo(map);
L.rectangle([[39.895, 116.370], [39.920, 116.415]], {
color: '#1f5fd0',
weight: 1,
fillOpacity: 0.06,
interactive: false
}).addTo(map);
var decEl = document.getElementById('dec');
var maxEl = document.getElementById('max');
var logEl = document.getElementById('log');
var flungFrom = null;
map.on('dragend', function () {
/* dragend 在松手瞬间触发,惯性动画随后开始 */
flungFrom = map.getCenter();
});
map.on('moveend', function () {
if (!flungFrom) return;
var dist = map.distance(flungFrom, map.getCenter());
flungFrom = null;
if (dist < 8) {
logEl.textContent = '松手后没有滑行,地图立即停住';
} else {
logEl.textContent = '惯性滑行 ' + Math.round(dist) + ' 米(z' + map.getZoom() + ')';
}
});
var PRESETS = {
off: { inertia: false, decel: 3400, maxSpeed: Infinity, ease: 0.2, label: '无惯性' },
default: { inertia: true, decel: 3400, maxSpeed: Infinity, ease: 0.2, label: '默认' },
far: { inertia: true, decel: 900, maxSpeed: 3200, ease: 0.25, label: '强惯性' },
short: { inertia: true, decel: 6000, maxSpeed: 600, ease: 0.1, label: '短滑行' }
};
function apply(name) {
var p = PRESETS[name];
if (!p) return;
/* 惯性参数在每次松手时从 map.options 读取,运行时改立即生效 */
map.options.inertia = p.inertia;
map.options.inertiaDeceleration = p.decel;
map.options.inertiaMaxSpeed = p.maxSpeed;
map.options.easeLinearity = p.ease;
decEl.textContent = p.decel;
maxEl.textContent = p.maxSpeed === Infinity ? '∞' : p.maxSpeed;
logEl.textContent = '已切换到「' + p.label + '」,甩动地图后看滑行距离';
}
Array.prototype.forEach.call(document.querySelectorAll('[data-preset]'), function (btn) {
btn.addEventListener('click', function () {
Array.prototype.forEach.call(document.querySelectorAll('[data-preset]'), function (b) {
b.classList.remove('on');
});
btn.classList.add('on');
apply(btn.getAttribute('data-preset'));
});
});
})();
</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.