Atlaslog
Atlaslog / Examples / deck.gl / Great Circle
deck.gl · Runnable Example

Great Circle

Runnable deck.gl example: Great Circle. 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 deck.gl examples
/demos/deckgl-great-circle.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/deckgl-great-circle.html
<!--
  示例:大圆航线
  核心逻辑:GreatCircleLayer 把两点之间的最短球面路径画成带色渐变的弧段
  数据:页面内构造的 18 条国际航线与客流权重
  依赖:deck.gl 9.0 · 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;background:#0d1117}
  body{display:flex;flex-direction:column;overflow:hidden;
       font:13px/1.6 -apple-system,"Segoe UI","PingFang SC",sans-serif;color:#e6e8ec}
  .bar{position:relative;z-index:5;flex:0 0 auto;padding:8px 12px;background:#161b22;border-bottom:1px solid #252c36;
       display:flex;gap:14px;align-items:center;font-size:12px;color:#8b93a1;flex-wrap:wrap}
  .bar b{color:#58a6ff;font-weight:600}
  .bar input[type=range]{width:110px}
  #cv{flex:1 1 auto;min-height:0;width:100%}
</style>
</head>
<body>
<div class="bar">
  <span>航线 <b id="n">—</b></span>
  <span>线宽 <b id="wv">2.0</b></span>
  <label><input id="w" type="range" min="0.5" max="6" step="0.5" value="2"> 像素</label>
  <span>悬停查看起降城市</span>
</div>
<canvas id="cv"></canvas>
<script src="https://cdn.jsdelivr.net/npm/deck.gl@9.0.35/dist.min.js"></script>
<script>
(function () {
  'use strict';

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

  var airports = {
    PEK: { name: '北京', pos: [116.39, 39.90] },
    PVG: { name: '上海', pos: [121.47, 31.23] },
    CAN: { name: '广州', pos: [113.26, 23.12] },
    HKG: { name: '香港', pos: [113.91, 22.32] },
    NRT: { name: '东京', pos: [140.39, 35.77] },
    ICN: { name: '首尔', pos: [126.45, 37.46] },
    SIN: { name: '新加坡', pos: [103.99, 1.36] },
    DXB: { name: '迪拜', pos: [55.36, 25.25] },
    FRA: { name: '法兰克福', pos: [8.56, 50.03] },
    LHR: { name: '伦敦', pos: [-0.45, 51.47] },
    CDG: { name: '巴黎', pos: [2.55, 49.01] },
    JFK: { name: '纽约', pos: [-73.78, 40.64] },
    LAX: { name: '洛杉矶', pos: [-118.41, 33.94] },
    SYD: { name: '悉尼', pos: [151.18, -33.95] },
    AKL: { name: '奥克兰', pos: [174.79, -37.01] },
    JNB: { name: '约翰内斯堡', pos: [28.25, -26.14] },
    GRU: { name: '圣保罗', pos: [-46.47, -23.43] },
    SVO: { name: '莫斯科', pos: [37.41, 55.97] }
  };

  /* 每条航线给一个权重,用线宽表现客流大小 */
  var routes = [
    ['PEK', 'LHR', 5], ['PEK', 'CDG', 4], ['PEK', 'FRA', 4.5],
    ['PEK', 'JFK', 5], ['PEK', 'LAX', 5], ['PEK', 'SVO', 3],
    ['PVG', 'NRT', 4], ['PVG', 'ICN', 4], ['PVG', 'SIN', 4.5],
    ['PVG', 'SYD', 3.5], ['PVG', 'DXB', 3], ['CAN', 'SIN', 3],
    ['CAN', 'SYD', 2.5], ['HKG', 'DXB', 3], ['HKG', 'JNB', 2],
    ['PEK', 'GRU', 1.5], ['PVG', 'AKL', 1.5], ['PEK', 'DXB', 3]
  ].map(function (r) {
    return {
      from: airports[r[0]],
      to: airports[r[1]],
      w: r[2]
    };
  });

  document.getElementById('n').textContent = routes.length;

  var glow = new deck.GreatCircleLayer({
    id: 'routes-glow',
    data: routes,
    getSourcePosition: function (d) { return d.from.pos; },
    getTargetPosition: function (d) { return d.to.pos; },
    getSourceColor: [80, 200, 255, 40],
    getTargetColor: [255, 190, 80, 40],
    getWidth: function (d) { return d.w * 3; },
    widthUnits: 'pixels',
    widthMinPixels: 2
  });

  var routesLayer = new deck.GreatCircleLayer({
    id: 'routes',
    data: routes,
    getSourcePosition: function (d) { return d.from.pos; },
    getTargetPosition: function (d) { return d.to.pos; },
    getSourceColor: [80, 200, 255, 220],
    getTargetColor: [255, 190, 80, 230],
    getWidth: function (d) { return d.w; },
    widthUnits: 'pixels',
    widthMinPixels: 1,
    pickable: true
  });

  var deckgl = new deck.Deck({
    canvas: document.getElementById('cv'),
    width: '100%',
    height: '100%',
    initialViewState: {
      longitude: 60,
      latitude: 30,
      zoom: 1.3,
      pitch: 20,
      bearing: 0,
      maxPitch: 60
    },
    controller: true,
    layers: [glow, routesLayer],
    getTooltip: function (info) {
      if (!info.object) return null;
      return info.object.from.name + ' → ' + info.object.to.name +
        ' · 权重 ' + info.object.w;
    }
  });

  document.getElementById('w').addEventListener('input', function () {
    var v = parseFloat(this.value);
    document.getElementById('wv').textContent = v.toFixed(1);
    routesLayer = routesLayer.clone({ getWidth: function (d) { return d.w * v / 2; } });
    glow = glow.clone({ getWidth: function (d) { return d.w * v * 1.5; } });
    deckgl.setProps({ layers: [glow, routesLayer] });
  });

  window.__deck = deckgl;
})();
</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 deck.gl examples

deck.gl · EXAMPLEGrid deck.gl · EXAMPLEGrid Extruded deck.gl · EXAMPLEHeatmap