Atlaslog
Atlaslog / Examples / Turf.js / Distance
Turf.js · Runnable Example

Distance

Runnable Turf.js example: Distance. 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 Turf.js examples
/demos/turf-distance.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/turf-distance.html
<!--
  示例:两点测距 — 在图上点两个位置,用 turf.distance 算球面距离
  核心逻辑:点击位置反投影成经纬度,分别输出公里与米
  依赖:Turf.js 7 · 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>
<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;color:#16181d;background:#fff}
  .bar{flex:0 0 auto;display:flex;gap:10px;align-items:center;padding:8px 12px;
       background:#f6f7f9;border-bottom:1px solid #e3e6ea;font-size:12px;color:#58606e;flex-wrap:wrap}
  .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}
  .hint{color:#8a929f}
  svg{flex:1 1 auto;min-height:0;width:100%;display:block;background:#fbfcfd;cursor:crosshair}
  .out{flex:0 0 auto;display:flex;gap:20px;flex-wrap:wrap;padding:8px 12px;
       border-top:1px solid #e3e6ea;font-family:ui-monospace,Consolas,monospace;font-size:11.5px;color:#3a4250}
  .out b{font-weight:600;color:#1f5fd0}
</style>
</head>
<body>
<div class="bar">
  <button id="reset">重置</button>
  <span class="hint">在图上点击两个位置,第三次点击重新开始</span>
</div>
<svg id="stage" viewBox="0 0 640 320" preserveAspectRatio="xMidYMid meet"></svg>
<div class="out">
  <span>距离 <b id="d">—</b></span>
  <span>A <span id="pa">—</span></span>
  <span>B <span id="pb">—</span></span>
</div>
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@7/turf.min.js"></script>
<script>
(function () {
  'use strict';

  if (typeof turf === 'undefined') {
    document.body.innerHTML =
      '<div style="padding:24px;color:#b42318">Turf.js 加载失败,请检查能否访问 cdn.jsdelivr.net</div>';
    return;
  }

  var W = 640, H = 320, PAD = 30;
  var BOX = [116.20, 39.75, 116.58, 40.04];
  var stage = document.getElementById('stage');

  function projection(bbox) {
    var kx = Math.cos(((bbox[1] + bbox[3]) / 2) * Math.PI / 180);
    var x0 = bbox[0] * kx, x1 = bbox[2] * kx;
    var y0 = bbox[1], y1 = bbox[3];
    var s = Math.min((W - PAD * 2) / Math.max(x1 - x0, 1e-9),
                     (H - PAD * 2) / Math.max(y1 - y0, 1e-9));
    var ox = (W - (x1 - x0) * s) / 2;
    var oy = (H - (y1 - y0) * s) / 2;

    function to(c) {
      return [(c[0] * kx - x0) * s + ox, (y1 - c[1]) * s + oy];
    }
    to.inverse = function (px, py) {
      return [((px - ox) / s + x0) / kx, y1 - (py - oy) / s];
    };
    return to;
  }

  var pr = projection(BOX);
  var pts = [[116.31, 39.83], [116.48, 39.98]];

  function fmt(c) {
    return c[0].toFixed(5) + ', ' + c[1].toFixed(5);
  }

  function dot(c, color, label) {
    var p = pr(c);
    return '<circle cx="' + p[0].toFixed(1) + '" cy="' + p[1].toFixed(1) +
           '" r="5" fill="' + color + '" stroke="#fff" stroke-width="2"/>' +
           '<text x="' + (p[0] + 9).toFixed(1) + '" y="' + (p[1] - 9).toFixed(1) +
           '" font-size="12" fill="' + color + '">' + label + '</text>';
  }

  function draw() {
    var parts = ['<rect x="0" y="0" width="640" height="320" fill="none" stroke="#e3e6ea"/>'];

    if (pts.length === 2) {
      var a = pr(pts[0]), b = pr(pts[1]);
      var mx = (a[0] + b[0]) / 2, my = (a[1] + b[1]) / 2;
      var km = turf.distance(turf.point(pts[0]), turf.point(pts[1]), { units: 'kilometers' });

      parts.push('<line x1="' + a[0].toFixed(1) + '" y1="' + a[1].toFixed(1) +
                 '" x2="' + b[0].toFixed(1) + '" y2="' + b[1].toFixed(1) +
                 '" stroke="#1f5fd0" stroke-width="2" stroke-dasharray="7 5"/>');
      parts.push('<text x="' + mx.toFixed(1) + '" y="' + (my - 10).toFixed(1) +
                 '" font-size="12" text-anchor="middle" fill="#1f5fd0">' +
                 km.toFixed(2) + ' km</text>');

      document.getElementById('d').textContent =
        km.toFixed(2) + ' km / ' + Math.round(km * 1000) + ' m';
    } else {
      document.getElementById('d').textContent = '—';
    }

    if (pts[0]) parts.push(dot(pts[0], '#1f5fd0', 'A'));
    if (pts[1]) parts.push(dot(pts[1], '#c2410c', 'B'));

    if (!pts.length) {
      parts.push('<text x="320" y="160" font-size="13" text-anchor="middle" fill="#8a929f">点击图上任意位置设置起点</text>');
    }

    stage.innerHTML = parts.join('');
    document.getElementById('pa').textContent = pts[0] ? fmt(pts[0]) : '—';
    document.getElementById('pb').textContent = pts[1] ? fmt(pts[1]) : '—';
  }

  function toView(e) {
    var r = stage.getBoundingClientRect();
    var scale = Math.min(r.width / W, r.height / H);
    var offX = (r.width - W * scale) / 2;
    var offY = (r.height - H * scale) / 2;
    return [(e.clientX - r.left - offX) / scale, (e.clientY - r.top - offY) / scale];
  }

  stage.addEventListener('click', function (e) {
    var v = toView(e);
    var c = pr.inverse(v[0], v[1]);
    c = [
      Math.min(BOX[2], Math.max(BOX[0], c[0])),
      Math.min(BOX[3], Math.max(BOX[1], c[1]))
    ];

    if (pts.length >= 2) {
      pts = [c];
    } else {
      pts.push(c);
    }
    draw();
  });

  document.getElementById('reset').addEventListener('click', function () {
    pts = [[116.31, 39.83], [116.48, 39.98]];
    draw();
  });

  draw();
})();
</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 Turf.js examples

Turf.js · EXAMPLEExplode Turf.js · EXAMPLEGeoJSON Transform Turf.js · EXAMPLEGrid