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.
single HTML file · CDN dependencies onlyinterface may contain Chinese labels
Source
<!--
示例:大圆航线
核心逻辑: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.