Atlaslog
Atlaslog / Examples / OpenLayers / Utfgrid
OpenLayers · Runnable Example

Utfgrid

Runnable OpenLayers example: Utfgrid. 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 OpenLayers examples
/demos/openlayers-utfgrid.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/openlayers-utfgrid.html
<!--
  示例:OpenLayers UTFGrid 属性查询
  要点:UTFGrid 瓦片携带网格属性,指针位置直接查出区域信息,不产生要素渲染开销
  依赖:OpenLayers 10.3.1 · 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>UTFGrid 属性查询</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@10.3.1/ol.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:10px;align-items:center;flex-wrap:wrap;font-size:12px;color:#58606e}
  .bar label{display:flex;gap:5px;align-items:center;cursor:pointer}
  .bar select,.bar input[type=range]{font-size:12px}
  .bar .val{font-family:ui-monospace,Consolas,monospace;color:#1f5fd0;min-width:44px}
  .bar .sep{width:1px;height:16px;background:#d8dce2}
  #map{flex:1 1 auto;min-height:0;background:#eef0f3}
  #map{position:relative}
  .gridinfo{position:absolute;visibility:hidden;padding:6px 10px;border-radius:4px;background:rgba(22,24,29,.9);
            color:#fff;font-size:12px;line-height:1.5;pointer-events:none;transform:translate(14px,14px);max-width:220px}
</style>
</head>
<body>
<div class="bar">
  <span>悬停查看 UTFGrid 返回的属性</span>
  <span class="sep"></span>
  <span id="info">—</span>
</div>
<div id="map">
  <div id="gridinfo" class="gridinfo"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/ol@10.3.1/dist/ol.js"></script>
<script>
(function () {
  'use strict';

  if (typeof ol === 'undefined') {
    document.getElementById('map').textContent = 'OpenLayers 加载失败,请检查能否访问 cdn.jsdelivr.net';
    return;
  }


  var REGIONS = [
    {box: [115.80, 39.50, 116.25, 39.85], name: '西南片区', note: '含丰台、房山方向'},
    {box: [116.25, 39.50, 116.70, 39.85], name: '东南片区', note: '含大兴、亦庄方向'},
    {box: [115.80, 39.85, 116.25, 40.20], name: '西北片区', note: '含海淀、石景山方向'},
    {box: [116.25, 39.85, 116.70, 40.20], name: '东北片区', note: '含朝阳、顺义方向'}
  ];

  var regionFeatures = REGIONS.map(function (region) {
    var b = region.box;
    return new ol.Feature({
      geometry: new ol.geom.Polygon([[
        ol.proj.fromLonLat([b[0], b[1]]),
        ol.proj.fromLonLat([b[2], b[1]]),
        ol.proj.fromLonLat([b[2], b[3]]),
        ol.proj.fromLonLat([b[0], b[3]]),
        ol.proj.fromLonLat([b[0], b[1]])
      ]]),
      name: region.name
    });
  });

  var regionLayer = new ol.layer.Vector({
    source: new ol.source.Vector({features: regionFeatures}),
    style: new ol.style.Style({
      fill: new ol.style.Fill({color: 'rgba(46, 125, 50, 0.12)'}),
      stroke: new ol.style.Stroke({color: 'rgba(46, 125, 50, 0.65)', width: 1}),
      text: new ol.style.Text({
        text: '',
        font: '12px sans-serif'
      })
    })
  });

  regionLayer.setStyle(function (feature) {
    return new ol.style.Style({
      fill: new ol.style.Fill({color: 'rgba(46, 125, 50, 0.12)'}),
      stroke: new ol.style.Stroke({color: 'rgba(46, 125, 50, 0.65)', width: 1}),
      text: new ol.style.Text({
        text: feature.get('name'),
        font: '500 12px sans-serif',
        fill: new ol.style.Fill({color: 'rgba(27, 94, 32, 0.85)'}),
        stroke: new ol.style.Stroke({color: '#ffffff', width: 3})
      })
    });
  });

  var gridSource = new ol.source.UTFGrid({
    tileJSON: {
      tilejson: '3.0.0',
      grids: ['placeholder'],
      minzoom: 0,
      maxzoom: 18,
      bounds: [-180, -85.0511, 180, 85.0511]
    },
    preemptive: true
  });

  function encodeIndex(index) {
    var code = index + 32;
    if (code >= 35) {
      ++code;
    }
    if (code >= 93) {
      ++code;
    }
    return String.fromCharCode(code);
  }

  function regionAt(lonlat) {
    for (var i = 0; i < REGIONS.length; ++i) {
      var b = REGIONS[i].box;
      if (lonlat[0] >= b[0] && lonlat[0] <= b[2] &&
          lonlat[1] >= b[1] && lonlat[1] <= b[3]) {
        return i + 1;
      }
    }
    return 0;
  }

  function gridUrl(tileCoord) {
    var gridSize = 32;
    var extent = gridSource.tileGrid.getTileCoordExtent(tileCoord);
    var keys = [''];
    var data = {};
    REGIONS.forEach(function (region, i) {
      keys.push(String(i + 1));
      data[String(i + 1)] = {name: region.name, note: region.note};
    });

    var rows = [];
    for (var row = 0; row < gridSize; ++row) {
      var line = '';
      for (var col = 0; col < gridSize; ++col) {
        var x = extent[0] + (col + 0.5) / gridSize * (extent[2] - extent[0]);
        var y = extent[3] - (row + 0.5) / gridSize * (extent[3] - extent[1]);
        line += encodeIndex(regionAt(ol.proj.toLonLat([x, y])));
      }
      rows.push(line);
    }

    return 'data:application/json;charset=utf-8,' + encodeURIComponent(
      JSON.stringify({grid: rows, keys: keys, data: data})
    );
  }

  gridSource.tileUrlFunction_ = gridUrl;

  var gridLayer = new ol.layer.Tile({source: gridSource});

  var map = new ol.Map({
    target: 'map',
    layers: [
      new ol.layer.Tile({source: new ol.source.XYZ({url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', attributions: 'Tiles © Esri'}), opacity: 0.55}),
      regionLayer,
      gridLayer
    ],
    view: new ol.View({
      center: ol.proj.fromLonLat([116.25, 39.85]),
      zoom: 10
    })
  });

  var infoElement = document.getElementById('gridinfo');
  var overlay = new ol.Overlay({
    element: infoElement,
    offset: [0, 0],
    stopEvent: false
  });
  map.addOverlay(overlay);

  var view = map.getView();

  var gridTiles = {};

  function gridTileFor(coordinate) {
    var z = gridSource.tileGrid.getZForResolution(view.getResolution(), 0);
    var tileCoord = gridSource.tileGrid.getTileCoordForCoordAndZ(coordinate, z);
    var key = tileCoord.join('/');
    var tile = gridTiles[key];
    if (!tile) {
      tile = gridSource.getTile(tileCoord[0], tileCoord[1], tileCoord[2], 1, gridSource.getProjection());
      gridTiles[key] = tile;
      tile.load();
    }
    return tile;
  }

  function showAt(coordinate) {
    var tile = gridTileFor(coordinate);

    function apply() {
      var data = tile.getData(coordinate);
      if (data) {
        infoElement.innerHTML = '<strong>' + data.name + '</strong><br>' + data.note;
        infoElement.style.visibility = 'visible';
        overlay.setPosition(coordinate);
        map.getTargetElement().style.cursor = 'pointer';
        document.getElementById('info').textContent = data.name;
      } else if (tile.getState() >= 2) {
        infoElement.style.visibility = 'hidden';
        overlay.setPosition(undefined);
        map.getTargetElement().style.cursor = '';
        document.getElementById('info').textContent = '—';
      }
    }

    tile.__apply = apply;
    if (!tile.__wired) {
      tile.__wired = true;
      tile.addEventListener('change', function () {
        if (tile.__apply) {
          tile.__apply();
        }
      });
    }
    apply();
  }

  map.on('pointermove', function (evt) {
    if (evt.dragging) {
      return;
    }
    showAt(map.getEventCoordinate(evt.originalEvent));
  });

  map.on('click', function (evt) {
    showAt(evt.coordinate);
  });

})();
</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 OpenLayers examples

OpenLayers · EXAMPLEVector Esri OpenLayers · EXAMPLEVector Esri Edit OpenLayers · EXAMPLEVector Label Decluttering