Atlaslog
Atlaslog / Examples / OpenLayers / Mapbox Style
OpenLayers · Runnable Example

Mapbox Style

Runnable OpenLayers example: Mapbox Style. 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-mapbox-style.htmlLIVE
single HTML file · CDN dependencies onlyinterface may contain Chinese labels

Source

demos/openlayers-mapbox-style.html
<!--
  示例:Mapbox 样式表达式
  要点:interpolate 按属性插值颜色,step 按缩放级别切换线宽
  依赖: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>Mapbox 样式表达式</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;color:#16181d}
  .bar{flex:0 0 auto;padding:8px 12px;background:#f6f7f9;border-bottom:1px solid #e3e6ea;
       display:flex;gap:16px;align-items:center;font-size:12px;color:#58606e;flex-wrap:wrap}
  .bar b{color:#16181d;font-weight:600}
  #map{flex:1 1 auto;min-height:0;background:#eef0f3}
</style>
</head>
<body>
<div class="bar">
  <span>当前缩放:<b id="z">—</b></span>
  <span>把地图缩放到 9 级以下、13 级以上,对比道路线宽变化</span>
</div>
<div id="map"></div>
<script src="https://cdn.jsdelivr.net/npm/ol@10.3.1/dist/ol.js"></script>
<script>
(function () {
  'use strict';
  if (!window.ol) {
    document.getElementById('map').textContent = 'OpenLayers 加载失败,请检查 cdn.jsdelivr.net 是否可访问';
    return;
  }
  var fromLonLat = ol.proj.fromLonLat;

  var data = {
    type: 'FeatureCollection',
    features: [
      { type: 'Feature', properties: { name: '甲区', pop: 2000 },
        geometry: { type: 'Polygon', coordinates: [[[116.29, 39.95], [116.37, 39.95], [116.37, 39.89], [116.29, 39.89], [116.29, 39.95]]] } },
      { type: 'Feature', properties: { name: '乙区', pop: 12000 },
        geometry: { type: 'Polygon', coordinates: [[[116.38, 39.96], [116.46, 39.96], [116.46, 39.895], [116.38, 39.895], [116.38, 39.96]]] } },
      { type: 'Feature', properties: { name: '丙区', pop: 26000 },
        geometry: { type: 'Polygon', coordinates: [[[116.47, 39.945], [116.55, 39.945], [116.55, 39.875], [116.47, 39.875], [116.47, 39.945]]] } },
      { type: 'Feature', properties: { name: '干线', rank: 1 },
        geometry: { type: 'LineString', coordinates: [[116.28, 39.92], [116.40, 39.93], [116.56, 39.91]] } },
      { type: 'Feature', properties: { name: '支线', rank: 2 },
        geometry: { type: 'LineString', coordinates: [[116.31, 39.87], [116.42, 39.895], [116.52, 39.87]] } }
    ]
  };

  /* 样式表达式,语法与 Mapbox Style Spec 一致 */
  var fillExpr = ['interpolate', ['linear'], ['get', 'pop'], 0, '#e8f0fb', 5000, '#7fb0e8', 15000, '#1f5fd0', 26000, '#0b3d91'];
  var lineWidthExpr = ['step', ['zoom'], 1.5, 10, 3, 13, 5.5];

  function parseColor(hex) {
    return [parseInt(hex.substr(1, 2), 16), parseInt(hex.substr(3, 2), 16), parseInt(hex.substr(5, 2), 16)];
  }

  function evalExpr(expr, props) {
    var op = expr[0];

    if (op === 'get') return props[expr[1]];
    if (op === 'zoom') return props.__zoom;
    if (op === 'literal') return expr[1];

    if (op === 'interpolate') {
      var kind = expr[1];
      var input = evalExpr(expr[2], props);
      var stops = expr.slice(3);
      var lo = null, hi = null;
      for (var i = 0; i < stops.length; i += 2) {
        if (stops[i] <= input) lo = [stops[i], stops[i + 1]];
        if (stops[i] >= input && !hi) hi = [stops[i], stops[i + 1]];
      }
      if (!lo) return hi[1];
      if (!hi) return lo[1];
      var f = (input - lo[0]) / Math.max(1e-6, hi[0] - lo[0]);
      if (typeof lo[1] === 'string' && kind[0] === 'linear') {
        var a = parseColor(lo[1]), b = parseColor(hi[1]);
        return 'rgb(' + Math.round(a[0] + (b[0] - a[0]) * f) + ',' +
          Math.round(a[1] + (b[1] - a[1]) * f) + ',' +
          Math.round(a[2] + (b[2] - a[2]) * f) + ')';
      }
      return lo[1] + (hi[1] - lo[1]) * f;
    }

    if (op === 'step') {
      var v = evalExpr(expr[1], props);
      var out = expr[2];
      for (var s = 3; s < expr.length; s += 2) {
        if (v >= expr[s]) out = expr[s + 1];
      }
      return out;
    }

    return null;
  }

  var features = new ol.format.GeoJSON().readFeatures(data, {
    dataProjection: 'EPSG:4326',
    featureProjection: 'EPSG:3857'
  });

  var view = new ol.View({ center: fromLonLat([116.41, 39.915]), zoom: 11 });

  var layer = new ol.layer.Vector({
    source: new ol.source.Vector({ features: features }),
    style: function (feature, resolution) {
      var props = { __zoom: view.getZoomForResolution(resolution) };
      feature.getProperties && Object.keys(feature.getProperties()).forEach(function (k) {
        props[k] = feature.get(k);
      });

      if (feature.getGeometry().getType() === 'Polygon') {
        return new ol.style.Style({
          fill: new ol.style.Fill({ color: evalExpr(fillExpr, props) }),
          stroke: new ol.style.Stroke({ color: 'rgba(11,61,145,0.55)', width: 1 }),
          text: new ol.style.Text({
            text: feature.get('name'),
            font: '500 12px sans-serif',
            fill: new ol.style.Fill({ color: '#16181d' }),
            stroke: new ol.style.Stroke({ color: '#ffffff', width: 3 })
          })
        });
      }

      return new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: feature.get('rank') === 1 ? '#b42318' : '#a9700f',
          width: evalExpr(lineWidthExpr, props)
        })
      });
    }
  });

  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'}) }), layer],
    view: view,
    controls: ol.control.defaults.defaults({ rotate: false })
  });

  function reportZoom() {
    document.getElementById('z').textContent = view.getZoom().toFixed(1);
  }
  map.on('moveend', reportZoom);
  reportZoom();
})();
</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 · EXAMPLEMapbox Vector Layer OpenLayers · EXAMPLEMapbox Vector Tiles OpenLayers · EXAMPLEMapbox Vector Tiles Advanced