Atlaslog
Atlaslog / Examples / deck.gl / Aggregation Transition
deck.gl · Runnable Example

Aggregation Transition

Runnable deck.gl example: Aggregation Transition. 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-aggregation-transition.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/deckgl-aggregation-transition.html
<!--
  示例:deck.gl 聚合过渡
  要点:两套不同半径的 HexagonLayer 交叉淡入淡出,实现聚合粒度的平滑切换
  依赖: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{flex:0 0 auto;padding:8px 12px;background:#161b22;border-bottom:1px solid #252c36;
       display:flex;gap:10px;align-items:center;font-size:12px;color:#8b93a1;flex-wrap:wrap;
       position:relative;z-index:5}
  .bar b{color:#58a6ff;font-weight:600}
  .bar button{font:inherit;font-size:12px;padding:3px 10px;border-radius:5px;cursor:pointer;
              border:1px solid #303845;background:#1d2531;color:#c8d2e0}
  .bar button:hover{background:#253040}
  .bar button.on{background:#2c4a7a;border-color:#4f8ad6;color:#dfe9ff}
  .bar .sep{width:1px;height:18px;background:#2a313c;margin:0 4px}
  .progress{position:relative;flex:0 0 120px;height:4px;background:#242c38;border-radius:2px;
            overflow:hidden}
  .progress i{position:absolute;left:0;top:0;bottom:0;width:0;background:#4f9ef8;
              border-radius:2px}
  #cv{flex:1 1 auto;min-height:0;width:100%}
</style>
</head>
<body>
<div class="bar">
  <span>点数 <b id="n">—</b></span>
  <span class="sep"></span>
  <button data-level="fine" class="on">细网格 800 m</button>
  <button data-level="coarse">粗网格 2.2 km</button>
  <span class="progress"><i id="bar"></i></span>
  <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 hubs = [
    [121.470, 31.232, 0.20],
    [121.600, 31.100, 0.16],
    [121.335, 31.300, 0.14],
    [121.470, 31.360, 0.12],
    [121.390, 31.080, 0.18]
  ];

  var points = [];
  for (var i = 0; i < 50000; i++) {
    var h = hubs[i % hubs.length];
    var r = Math.sqrt(Math.random()) * h[2] * 2.2;
    var a = Math.random() * Math.PI * 2;
    var plng = h[0] + Math.cos(a) * r;
    var plat = h[1] + Math.sin(a) * r * 0.82;
    /* 权重随与主中心距离平滑衰减,相邻单元的统计值才不会跳变 */
    var dx = (plng - 121.47) / 0.22;
    var dy = (plat - 31.23) / 0.14;
    points.push({
      lng: plng,
      lat: plat,
      w: 0.55 + 2.8 * Math.exp(-(dx * dx + dy * dy))
    });
  }

  document.getElementById('n').textContent = points.length.toLocaleString();

  var colorRange = [
    [16, 30, 62, 165],
    [30, 84, 140, 190],
    [40, 148, 176, 205],
    [132, 202, 150, 220],
    [248, 206, 92, 235],
    [238, 104, 50, 250]
  ];

  /* blend = 0 细网格全显,1 粗网格全显 */
  var blend = 0;
  var from = 0;
  var target = 0;
  var animStart = 0;
  var duration = 800;
  var animating = false;

  function hexLayer(id, radius, opacity, active) {
    return new deck.HexagonLayer({
      id: id,
      data: points,
      getPosition: function (d) { return [d.lng, d.lat]; },
      radius: radius,
      coverage: 0.9,
      extruded: true,
      elevationScale: 1,
      getColorWeight: function (d) { return d.w; },
      colorAggregation: 'MEAN',
      getElevationWeight: function (d) { return d.w; },
      elevationAggregation: 'SUM',
      colorRange: colorRange,
      upperPercentile: 100,
      opacity: opacity,
      /* 完全透明的图层仍会写深度缓冲,隐藏它才能避免遮住另一层 */
      visible: opacity > 0.01,
      material: { ambient: 0.5, diffuse: 0.72, shininess: 18 },
      pickable: active
    });
  }

  function buildLayers() {
    return [
      hexLayer('hex-coarse', 2200, blend, blend >= 0.5),
      hexLayer('hex-fine', 800, 1 - blend, blend < 0.5)
    ];
  }

  var deckgl = new deck.Deck({
    canvas: 'cv',
    width: '100%',
    height: '100%',
    initialViewState: {
      longitude: 121.46,
      latitude: 31.21,
      zoom: 10.3,
      pitch: 42,
      bearing: -8,
      maxPitch: 68
    },
    controller: true,
    layers: buildLayers(),
    getTooltip: function (info) {
      if (!info.object) return null;
      var tag = info.layer && info.layer.id === 'hex-coarse' ? '粗网格' : '细网格';
      return tag + ' · ' + info.object.count + ' 点 · 权重和 ' +
        Math.round(info.object.elevationValue);
    }
  });

  function easeInOut(t) {
    return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
  }

  var progress = document.getElementById('bar');

  function frame(now) {
    if (animating) {
      var t = Math.min(1, (now - animStart) / duration);
      blend = from + (target - from) * easeInOut(t);
      progress.style.width = Math.round(blend * 100) + '%';
      deckgl.setProps({ layers: buildLayers() });
      if (t >= 1) {
        blend = target;
        animating = false;
      }
    }
    requestAnimationFrame(frame);
  }
  requestAnimationFrame(frame);

  function setBlend(v, btn) {
    from = blend;
    target = v;
    animStart = performance.now();
    animating = true;

    var buttons = document.querySelectorAll('[data-level]');
    for (var i = 0; i < buttons.length; i++) {
      buttons[i].classList.toggle('on', buttons[i] === btn);
    }
  }

  var buttons = document.querySelectorAll('[data-level]');
  for (var b = 0; b < buttons.length; b++) {
    buttons[b].addEventListener('click', function (e) {
      var level = e.currentTarget.getAttribute('data-level');
      setBlend(level === 'fine' ? 0 : 1, e.currentTarget);
    });
  }

  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 · EXAMPLEAnimation Frame deck.gl · EXAMPLEArc deck.gl · EXAMPLEArc Curve