# 八.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">© MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© 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
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">© MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© 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
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">© MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© 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
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">© MapTiler</a> ' +
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© 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
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
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
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