# 一.Tile 瓦片图

前言

OpenLayers 支持从 OSM、Bing、MapBox、Stamen 和其他任何 XYZ 瓦片资源中提取地图瓦片并在前端展示,同时也支持 OGC 的 WMTS 规范的瓦片服务以及 ArcGIS 规范的瓦片服务

# 1.OSM

ol.source.OSM,OpenStreetMap 提供的切片数据,继承自 ol.source.XYZ

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { WebGLTile: TileLayer },
        source: { OSM },
      } = ol;
      new Map({
        target: this.$refs.map,
        layers: [
          new TileLayer({
            source: new OSM(),
          }),
        ],
        view: new View({
          center: [12579156, 3274244],
          zoom: 12,
        }),
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 2.Bing

ol.source.BingMaps ,必应地图的切片数据,继承自 ol.source.TileImage

查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <select ref="layerselect">
      <option value="Aerial">鸟瞰图</option>
      <option value="AerialWithLabelsOnDemand" selected>带标签的鸟瞰图</option>
      <option value="RoadOnDemand">道路</option>
      <option value="CanvasDark">暗色道路</option>
      <option value="OrdnanceSurvey">测量图</option>
    </select>
  </div>
</template>
  
  <script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { BingMaps },
    } = ol;
    const styles = [
      "RoadOnDemand",
      "Aerial",
      "AerialWithLabelsOnDemand",
      "CanvasDark",
      "OrdnanceSurvey",
    ];
    const layers = [];
    let i, ii;
    for (i = 0, ii = styles.length; i < ii; ++i) {
      layers.push(
        new TileLayer({
          visible: false,
          preload: Infinity,
          source: new BingMaps({
            key: mapkeys.BingMaps,
            imagerySet: styles[i],
          }),
        })
      );
    }
    const map = new Map({
      layers: layers,
      target: this.$refs.map,
      view: new View({
        center: [-6655.5402445057125, 6709968.258934638],
        zoom: 13,
      }),
    });
    const select = this.$refs.layerselect;
    function onChange() {
      const style = select.value;
      for (let i = 0, ii = layers.length; i < ii; ++i) {
        layers[i].setVisible(styles[i] === style);
      }
    }
    select.addEventListener("change", onChange);
    onChange();
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 3.Stamen

ol.source.Stamen,Stamen 提供的地图切片数据,继承自 ol.source.XYZ

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { Tile: TileLayer },
        source: { Stamen },
        proj: { fromLonLat },
      } = ol;
      const map = new Map({
        layers: [
          new TileLayer({
            source: new Stamen({
              layer: "watercolor",
            }),
          }),
          new TileLayer({
            source: new Stamen({
              layer: "terrain-labels",
            }),
          }),
        ],
        target: this.$refs.map,
        view: new View({
          center: fromLonLat([114.31, 30.52]),
          zoom: 12,
        }),
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 4.XYZ

ol.source.XYZ,XYZ 格式的切片数据,继承自 ol.source.TileImage

侦听地图 loadstart 和 loadend 事件以在地图顶部显示加载微调器

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { Tile: TileLayer },
        source: { XYZ },
        proj: { fromLonLat },
      } = ol;
      const key = "get_your_own_D6rA4zTHduk6KOKTXzGB";
      const attributions =
        '<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> ' +
        '<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>';
      const map = new Map({
        layers: [
          new TileLayer({
            source: new XYZ({
              attributions: attributions,
              url:
                "https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=" +
                key,
              tileSize: 512,
            }),
          }),
        ],
        target: this.$refs.map,
        view: new View({
          center: fromLonLat([114.31, 30.52]),
          zoom: 12,
        }),
      });
      map.on("loadstart", function () {
        map.getTargetElement().classList.add("spinner");
      });
      map.on("loadend", function () {
        map.getTargetElement().classList.remove("spinner");
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 5.WMTS

天地图使用 wmts 服务

ol.source.WMTS,WMTS 服务提供的切片数据。继承自 ol.source.TileImage

WMTS 提供了一种采用预定义图块方法发布数字地图服务的标准化解决方案。WMTS 弥补了 WMS 不能提供分块地图的不足

WMTS 的目的是,更高效快速的加载渲染地图数据。如果海量的地图数据以矢量的形式传输到客户端,在客户端渲染,首先需要消耗大量的网络流量,其次对客户端的 CPU 也是很大的负荷。考虑到这些情况,WMTS 提出预渲染图块的模式,在服务端将地图渲染好,并根据比例尺分割不同的栅格图块,根据客户端的请求,传输这些图块,提供给客户端显示

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        tilegrid: { WMTS: WMTSTileGrid },
        layer: { Tile: TileLayer },
        source: { WMTS },
        proj: { fromLonLat, get: getProjection },
        extent: { getWidth },
      } = ol;
      const map = new Map({
        target: this.$refs.map,
        view: new View({
          zoom: 5,
          center: fromLonLat([5, 45]),
        }),
      });
      const resolutions = [];
      const matrixIds = [];
      const proj3857 = getProjection("EPSG:3857");
      const maxResolution = getWidth(proj3857.getExtent()) / 256;
      for (let i = 0; i < 20; i++) {
        matrixIds[i] = i.toString();
        resolutions[i] = maxResolution / Math.pow(2, i);
      }
      const tileGrid = new WMTSTileGrid({
        origin: [-20037508, 20037508],
        resolutions: resolutions,
        matrixIds: matrixIds,
      });
      const ign_source = new WMTS({
        url: "https://wxs.ign.fr/choisirgeoportail/geoportail/wmts",
        layer: "GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2",
        matrixSet: "PM",
        format: "image/png",
        projection: "EPSG:3857",
        tileGrid: tileGrid,
        style: "normal",
        attributions:
          '<a href="https://www.ign.fr/" target="_blank">' +
          '<img src="https://wxs.ign.fr/static/logos/IGN/IGN.gif" title="Institut national de l\'' +
          'information géographique et forestière" alt="IGN"></a>',
      });
      const ign = new TileLayer({
        source: ign_source,
      });
      map.addLayer(ign);
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# 6.WMS

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { Tile: TileLayer },
        source: { OSM, TileWMS },
      } = ol;
  
      const layers = [
        new TileLayer({
          source: new OSM(),
        }),
        new TileLayer({
          extent: [-13884991, 2870341, -7455066, 6338219],
          source: new TileWMS({
            url: "https://ahocevar.com/geoserver/wms",
            params: { LAYERS: "topp:states", TILED: true },
            serverType: "geoserver",
            transition: 0,
          }),
        }),
      ];
      const map = new Map({
        layers: layers,
        target: this.$refs.map,
        view: new View({
          center: [-10997148, 4569099],
          zoom: 4,
        }),
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 7.TileJSON

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { Tile: TileLayer },
        source: { TileJSON },
      } = ol;
      const map = new Map({
        layers: [
          new TileLayer({
            source: new TileJSON({
              url: "https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json?secure=1",
              crossOrigin: "anonymous",
            }),
          }),
        ],
        target: this.$refs.map,
        view: new View({
          center: [12579156, 3274244],
          zoom: 2,
        }),
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 8.TileDebug

ol.source.TileDebug,并不从服务器获取数据,而是为切片渲染一个网格,继承自 ol.source.Tile

黑色网格瓦片图是使用 HTML5 画布在客户端上生成的。显示的 TMS 瓦片图坐标使用 TMS 的自定义模板、矢量瓦片图源的 512 像素瓦片图网格和矢量瓦片图的 zDirection 设置生成。注意如何在瓦片图之间分割国家多边形,矢量标签可能会出现在每个瓦片图中。

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        format: { MVT },
        Map,
        View,
        layer: { Tile: TileLayer, VectorTile: VectorTileLayer },
        source: { VectorTile: VectorTileSource, TileDebug },
        style: { Fill, Stroke, Style, Text },
      } = ol;
      const style = new Style({
        fill: new Fill({
          color: "rgba(255, 255, 255, 0.6)",
        }),
        stroke: new Stroke({
          color: "#319FD3",
          width: 1,
        }),
        text: new Text({
          font: "12px Calibri,sans-serif",
          fill: new Fill({
            color: "#000",
          }),
          stroke: new Stroke({
            color: "#fff",
            width: 3,
          }),
        }),
      });
  
      const vtLayer = new VectorTileLayer({
        declutter: true,
        source: new VectorTileSource({
          maxZoom: 15,
          format: new MVT(),
          url:
            "https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/" +
            "ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf",
        }),
        style: function (feature) {
          style.getText().setText(feature.get("name"));
          return style;
        },
      });
  
      const debugLayer = new TileLayer({
        source: new TileDebug({
          template: "z:{z} x:{x} y:{-y}",
          projection: vtLayer.getSource().getProjection(),
          tileGrid: vtLayer.getSource().getTileGrid(),
          zDirection: 1,
        }),
      });
  
      const map = new Map({
        layers: [vtLayer, debugLayer],
        target: this.$refs.map,
        view: new View({
          center: [0, 6000000],
          zoom: 4,
        }),
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

# 9.TileJSON

ol.source.TileJSON,TileJSON 格式的切片数据,继承自 ol.source.TileImage

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { Tile: TileLayer },
        source: { TileJSON, OSM },
        proj: { fromLonLat },
      } = ol;
      const map = new Map({
        layers: [
          new TileLayer({
            className: "bw",
            source: new OSM(),
          }),
          new TileLayer({
            source: new TileJSON({
              url:
                "https://api.tiles.mapbox.com/v4/mapbox.va-quake-aug.json?secure&access_token=" +
                mapkeys.mapbox,
              crossOrigin: "anonymous",
              transition: 0,
            }),
          }),
        ],
        target: this.$refs.map,
        view: new View({
          center: fromLonLat([-77.93255, 37.9555]),
          zoom: 7,
        }),
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 10.Zoomify

ol.source.Zoomify,Zoomify 格式的切片数据,继承自 ol.source.TileImage

查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <div class="controls">
      <select ref="zoomifyProtocol">
        <option value="zoomify">Zoomify</option>
        <option value="zoomifyretina">Zoomify Retina</option>
      </select>
    </div>
  </div>
</template>
  
  <script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { Zoomify },
    } = ol;
    const imgWidth = 4000;
    const imgHeight = 3000;
    const zoomifyUrl = "https://ol-zoomify.surge.sh/zoomify/";
    const source = new Zoomify({
      url: zoomifyUrl,
      size: [imgWidth, imgHeight],
      crossOrigin: "anonymous",
      zDirection: -1,
    });
    const extent = source.getTileGrid().getExtent();
    const retinaPixelRatio = 2;
    const retinaSource = new Zoomify({
      url: zoomifyUrl,
      size: [imgWidth, imgHeight],
      crossOrigin: "anonymous",
      zDirection: -1,
      tilePixelRatio: retinaPixelRatio,
      tileSize: 256 / retinaPixelRatio,
    });
    const layer = new TileLayer({
      source: source,
    });
    const map = new Map({
      layers: [layer],
      target: this.$refs.map,
      view: new View({
        resolutions: layer.getSource().getTileGrid().getResolutions(),
        extent: extent,
        constrainOnlyCenter: true,
      }),
    });
    map.getView().fit(extent);
    this.$refs.zoomifyProtocol.addEventListener("change", function (event) {
      const value = event.currentTarget.value;
      if (value === "zoomify") {
        layer.setSource(source);
      } else if (value === "zoomifyretina") {
        layer.setSource(retinaSource);
      }
    });
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

# 11.CartoDB

查看代码详情
<template>
    <div class="row-fluid">
      <div class="span12">
        <div>
          <div ref="map" class="map"></div>
        </div>
        <form class="form-horizontal">
          <label>
            显示大于
            <select ref="countryarea" class="form-control">
              <option value="0" default>0 ㎢</option>
              <option value="5000">5000 ㎢</option>
              <option value="10000">10000 ㎢</option>
              <option value="50000">50000 ㎢</option>
              <option value="100000">100000 ㎢</option>
            </select>
          </label>
        </form>
      </div>
    </div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { Tile: TileLayer },
        source: { CartoDB, OSM },
      } = ol;
      const mapConfig = {
        layers: [
          {
            type: "cartodb",
            options: {
              cartocss_version: "2.1.1",
              cartocss: "#layer { polygon-fill: #F00; }",
              sql: "select * from european_countries_e where area > 0",
            },
          },
        ],
      };
      const cartoDBSource = new CartoDB({
        account: "documentation",
        config: mapConfig,
      });
      const map = new Map({
        layers: [
          new TileLayer({
            source: new OSM(),
          }),
          new TileLayer({
            source: cartoDBSource,
          }),
        ],
        target: this.$refs.map,
        view: new View({
          center: [12579156, 3274244],
          zoom: 2,
        }),
      });
      function setArea(n) {
        mapConfig.layers[0].options.sql =
          "select * from european_countries_e where area > " + n;
        cartoDBSource.setConfig(mapConfig);
      }
      this.$refs.countryarea.addEventListener("change", function () {
        setArea(this.value);
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

# 12.TileDebug

OpenLayers 提供了一个用于调试瓦片坐标系的 ol.source.TileDebug 类。借助这个类,我们可以清晰的看到每一个瓦片的坐标

查看代码详情
<template>
    <div ref="map" class="map"></div>
  </template>
  
  <script>
  export default {
    mounted() {
      let {
        Map,
        View,
        layer: { Tile: TileLayer },
        source: { OSM, TileDebug },
      } = ol;
      new Map({
        layers: [
          new TileLayer({
            source: new OSM(),
          }),
          new TileLayer({
            source: new TileDebug(),
          }),
        ],
        target: this.$refs.map,
        view: new View({
          center: [12579156, 3274244],
          zoom: 1,
        }),
      });
    },
  };
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

总结

瓦片地图将地理信息以一块块瓦片的形式进行组织并渲染,瓦片的本质是图片,因此不能对瓦片地图进行修改样式、空间分析等操作,而且瓦片不包含属性信息,隐含的空间信息也不能直接获取使用