# 八.render

# 1.图层滑动(WebGL)

查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <input id="swipe" type="range" style="width: 100%" />
  </div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { XYZ, OSM },
      style: Style,
      render: { getRenderPixel },
    } = ol;

    const osm = new TileLayer({
      source: new OSM({ wrapX: true }),
    });
    const imagery = new TileLayer({
      source: new XYZ({
        url:
          "https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=" +
          mapkeys.maptiler,
        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>',
        maxZoom: 20,
      }),
    });
    const map = new Map({
      layers: [osm, imagery],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 2,
      }),
    });
    const swipe = document.getElementById("swipe");
    imagery.on("prerender", function (event) {
      const gl = event.context;
      gl.enable(gl.SCISSOR_TEST);
      const mapSize = map.getSize();
      const bottomLeft = getRenderPixel(event, [0, mapSize[1]]);
      const topRight = getRenderPixel(event, [mapSize[0], 0]);

      const width = Math.round(
        (topRight[0] - bottomLeft[0]) * (swipe.value / 100)
      );
      const height = topRight[1] - bottomLeft[1];
      gl.scissor(bottomLeft[0], bottomLeft[1], width, height);
    });
    imagery.on("postrender", function (event) {
      const gl = event.context;
      gl.disable(gl.SCISSOR_TEST);
    });
    const listener = function () {
      map.render();
    };
    swipe.addEventListener("input", listener);
    swipe.addEventListener("change", listener);
  },
};
</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

# 2.放大

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { XYZ },
      proj: { fromLonLat },
      render: { getRenderPixel },
    } = ol
    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 imagery = new TileLayer({
      source: new XYZ({
        attributions: attributions,
        url:
          "https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=" +
          mapkeys.maptiler,
        maxZoom: 20,
        crossOrigin: "",
      }),
    })
    const container = this.$refs.map
    const map = new Map({
      layers: [imagery],
      target: container,
      view: new View({
        center: fromLonLat([-109, 46.5]),
        zoom: 6,
      }),
    })
    let radius = 75
    document.addEventListener("keydown", function (evt) {
      if (evt.which === 38) {
        radius = Math.min(radius + 5, 150)
        map.render()
        evt.preventDefault()
      } else if (evt.which === 40) {
        radius = Math.max(radius - 5, 25)
        map.render()
        evt.preventDefault()
      }
    })
    let mousePosition = null
    container.addEventListener("mousemove", function (event) {
      mousePosition = map.getEventPixel(event)
      map.render()
    })
    container.addEventListener("mouseout", function () {
      mousePosition = null
      map.render()
    })
    imagery.on("postrender", function (event) {
      if (mousePosition) {
        const pixel = getRenderPixel(event, mousePosition)
        const offset = getRenderPixel(event, [
          mousePosition[0] + radius,
          mousePosition[1],
        ])
        const half = Math.sqrt(
          Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2)
        )
        const context = event.context
        const centerX = pixel[0]
        const centerY = pixel[1]
        const originX = centerX - half
        const originY = centerY - half
        const size = Math.round(2 * half + 1)
        const sourceData = context.getImageData(
          originX,
          originY,
          size,
          size
        ).data
        const dest = context.createImageData(size, size)
        const destData = dest.data
        for (let j = 0; j < size; ++j) {
          for (let i = 0; i < size; ++i) {
            const dI = i - half
            const dJ = j - half
            const dist = Math.sqrt(dI * dI + dJ * dJ)
            let sourceI = i
            let sourceJ = j
            if (dist < half) {
              sourceI = Math.round(half + dI / 2)
              sourceJ = Math.round(half + dJ / 2)
            }
            const destOffset = (j * size + i) * 4
            const sourceOffset = (sourceJ * size + sourceI) * 4
            destData[destOffset] = sourceData[sourceOffset]
            destData[destOffset + 1] = sourceData[sourceOffset + 1]
            destData[destOffset + 2] = sourceData[sourceOffset + 2]
            destData[destOffset + 3] = sourceData[sourceOffset + 3]
          }
        }
        context.beginPath()
        context.arc(centerX, centerY, half, 0, 2 * Math.PI)
        context.lineWidth = (3 * half) / radius
        context.strokeStyle = "rgba(255,255,255,0.5)"
        context.putImageData(dest, originX, originY)
        context.stroke()
        context.restore()
      }
    })
  },
}
</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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

# 3.层间谍

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { XYZ },
      style: Style,
      proj: { fromLonLat },
      render: { getRenderPixel },
    } = ol
    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 roads = new TileLayer({
      source: new XYZ({
        attributions: attributions,
        url:
          "https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=" +
          mapkeys.maptiler,
        tileSize: 512,
        maxZoom: 22,
      }),
    })
    const imagery = new TileLayer({
      source: new XYZ({
        attributions: attributions,
        url:
          "https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=" +
          mapkeys.maptiler,
        maxZoom: 20,
      }),
    })
    const container = this.$refs.map
    const map = new Map({
      layers: [roads, imagery],
      target: container,
      view: new View({
        center: fromLonLat([-109, 46.5]),
        zoom: 6,
      }),
    })
    let radius = 75
    document.addEventListener("keydown", function (evt) {
      if (evt.which === 38) {
        radius = Math.min(radius + 5, 150)
        map.render()
        evt.preventDefault()
      } else if (evt.which === 40) {
        radius = Math.max(radius - 5, 25)
        map.render()
        evt.preventDefault()
      }
    })
    let mousePosition = null
    container.addEventListener("mousemove", function (event) {
      mousePosition = map.getEventPixel(event)
      map.render()
    })
    container.addEventListener("mouseout", function () {
      mousePosition = null
      map.render()
    })
    imagery.on("prerender", function (event) {
      const ctx = event.context
      ctx.save()
      ctx.beginPath()
      if (mousePosition) {
        const pixel = getRenderPixel(event, mousePosition)
        const offset = getRenderPixel(event, [
          mousePosition[0] + radius,
          mousePosition[1],
        ])
        const canvasRadius = Math.sqrt(
          Math.pow(offset[0] - pixel[0], 2) + Math.pow(offset[1] - pixel[1], 2)
        )
        ctx.arc(pixel[0], pixel[1], canvasRadius, 0, 2 * Math.PI)
        ctx.lineWidth = (5 * canvasRadius) / radius
        ctx.strokeStyle = "rgba(0,0,0,0.5)"
        ctx.stroke()
      }
      ctx.clip()
    })
    imagery.on("postrender", function (event) {
      const ctx = event.context
      ctx.restore()
    })
  },
}
</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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

# 4.getRenderPixel

图层滑动

查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <input id="swipe" type="range" style="width: 100%" />
  </div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { OSM, XYZ },
      render: { getRenderPixel },
    } = ol;

    const osm = new TileLayer({
      source: new OSM(),
    });
    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 aerial = new TileLayer({
      source: new XYZ({
        attributions: attributions,
        url:
          "https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=" +
          mapkeys.maptiler,
        maxZoom: 20,
      }),
    });
    const map = new Map({
      layers: [osm, aerial],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 2,
      }),
    });
    const swipe = document.getElementById("swipe");
    aerial.on("prerender", function (event) {
      const ctx = event.context;
      const mapSize = map.getSize();
      const width = mapSize[0] * (swipe.value / 100);
      const tl = getRenderPixel(event, [width, 0]);
      const tr = getRenderPixel(event, [mapSize[0], 0]);
      const bl = getRenderPixel(event, [width, mapSize[1]]);
      const br = getRenderPixel(event, mapSize);
      ctx.save();
      ctx.beginPath();
      ctx.moveTo(tl[0], tl[1]);
      ctx.lineTo(bl[0], bl[1]);
      ctx.lineTo(br[0], br[1]);
      ctx.lineTo(tr[0], tr[1]);
      ctx.closePath();
      ctx.clip();
    });
    aerial.on("postrender", function (event) {
      const ctx = event.context;
      ctx.restore();
    });
    const listener = function () {
      map.render();
    };
    swipe.addEventListener("input", listener);
    swipe.addEventListener("change", listener);
  },
};
</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

# 5.矢量剪切层

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      format: { GeoJSON },
      Map,
      View,
      layer: { Tile: TileLayer, Vector: VectorLayer },
      source: { OSM, Stamen, Vector: VectorSource },
      style: { Fill, Style },
      proj: { fromLonLat },
      render: { getVectorContext },
    } = ol
    const background = new TileLayer({
      className: "stamen",
      source: new Stamen({
        layer: "toner",
      }),
    })
    const base = new TileLayer({
      source: new OSM(),
    })
    const clipLayer = new VectorLayer({
      style: null,
      source: new VectorSource({
        url: this.$withBase("/data/geojson/switzerland.geojson"),
        format: new GeoJSON(),
      }),
    })
    clipLayer.getSource().on("addfeature", function () {
      base.setExtent(clipLayer.getSource().getExtent())
    })
    const style = new Style({
      fill: new Fill({
        color: "black",
      }),
    })
    base.on("postrender", function (e) {
      const vectorContext = getVectorContext(e)
      e.context.globalCompositeOperation = "destination-in"
      clipLayer.getSource().forEachFeature(function (feature) {
        vectorContext.drawFeature(feature, style)
      })
      e.context.globalCompositeOperation = "source-over"
    })
    const map = new Map({
      layers: [background, base, clipLayer],
      target: this.$refs.map,
      view: new View({
        center: fromLonLat([8.23, 46.86]),
        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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# 6.动态数据

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      geom: { MultiPoint, Point },
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { OSM },
      style: { Circle: CircleStyle, Fill, Stroke, Style },
      render: { getVectorContext },
    } = ol
    const tileLayer = new TileLayer({
      source: new OSM(),
    })
    const map = new Map({
      layers: [tileLayer],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 2,
      }),
    })
    const imageStyle = new Style({
      image: new CircleStyle({
        radius: 5,
        fill: new Fill({ color: "yellow" }),
        stroke: new Stroke({ color: "red", width: 1 }),
      }),
    })
    const headInnerImageStyle = new Style({
      image: new CircleStyle({
        radius: 2,
        fill: new Fill({ color: "blue" }),
      }),
    })
    const headOuterImageStyle = new Style({
      image: new CircleStyle({
        radius: 5,
        fill: new Fill({ color: "black" }),
      }),
    })
    const n = 200
    const omegaTheta = 30000
    const R = 7e6
    const r = 2e6
    const p = 2e6
    tileLayer.on("postrender", function (event) {
      const vectorContext = getVectorContext(event)
      const frameState = event.frameState
      const theta = (2 * Math.PI * frameState.time) / omegaTheta
      const coordinates = []
      let i
      for (i = 0; i < n; ++i) {
        const t = theta + (2 * Math.PI * i) / n
        const x = (R + r) * Math.cos(t) + p * Math.cos(((R + r) * t) / r)
        const y = (R + r) * Math.sin(t) + p * Math.sin(((R + r) * t) / r)
        coordinates.push([x, y])
      }
      vectorContext.setStyle(imageStyle)
      vectorContext.drawGeometry(new MultiPoint(coordinates))
      const headPoint = new Point(coordinates[coordinates.length - 1])
      vectorContext.setStyle(headOuterImageStyle)
      vectorContext.drawGeometry(headPoint)
      vectorContext.setStyle(headInnerImageStyle)
      vectorContext.drawGeometry(headPoint)
      map.render()
    })
    map.render()
  },
}
</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
73
74
75