0%

OpenLayers6实例分析:GeoJSON

之前翻译了 GeoJSON 的规范全文——《GeoJson 规范(RFC 7946)全文翻译》,在本篇中应用 GeoJSON 的各个特征对象和几何对象到 OpenLayers 中,熟悉 GeoJSON 格式在 OpenLayers 中的应用,也能熟悉 OpenGIS 的各个术语在 OpenLayers 的映射。

geojson

定义基本结构

先把地图基本结构展示出来,地图底图使用的是 OSM 地图,关键在于vectorLayer中的source:vectorSource源和style:styleFunction样式函数。

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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.2.1/css/ol.css"
type="text/css"
/>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.2.1/build/ol.js"></script>
<title>GeoJSON</title>
<style>
html,
body,
.map {
height: 100%;
width: 100%;
}
</style>
</head>

<body>
<div id="map" class="map"></div>
<script type="text/javascript">
// 定义一个矢量图层vectorLayer,源source为vectorSource,样式style为样式函数styleFunction
let vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: styleFunction
});
// 给地图加一个OSM底图
let map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
],
target: "map",
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
</script>
</body>
</html>

添加 GeoJSON 对象

正常情况应该使用 ajax 从后端读取 geojson 对象,为了便于观察和理解,将 geojson 直接定义成一个 geojsonObject 对象。

观察 geojsonObject 这个对象,可以发现比普通的 geojson 多了一个 crs 属性,这是一个GeoJson2008规范GJ2008中的成员,放置了投影方式,但是在最新的GeoJSON规范RFC 7946已经被废弃。其次,拥有正常的 FeatureCollection特征集合,在 features 数组中的每一项都是一个 Feature 特征

再观察每一个 feature 特征对象,其中的 geometry 几何对象中,类型分别是 PointLineStringPolygonMultiLineStringMultiPolygon,均为GeoJSON 规范中定义的七种几何类型之一。每一个类型都按照自己规定的格式存放 coordinates 位置坐标。

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
let geojsonObject = {
// FeatureCollection是规范中的九种GeoJSON类型之一
type: "FeatureCollection",
// crs是规范中的自定义的外部成员
crs: {
type: "name",
properties: {
// 投影方式为EPSG:3857
name: "EPSG:3857"
}
},
// features中存放特征对象
features: [
{
// Feature也是规范中的九种GeoJSON类型之一
type: "Feature",
// geometry是几何对象
geometry: {
// Point是规范中的七种几何类型之一
type: "Point",
// coordinates数组中存放位置,第一个是经度方向,第二个是纬度方向,如果有第三个则为高度方向
coordinates: [0, 0]
}
},
{
type: "Feature",
geometry: {
type: "LineString",
// LineString中存放的是位置数组
coordinates: [
[4e6, -2e6],
[8e6, 2e6]
]
}
},
{
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[4e6, 2e6],
[8e6, -2e6]
]
}
},
{
type: "Feature",
geometry: {
type: "Polygon",
// Polygon中存放的“linear ring数组”组成的数组,第一个数组是外环,如果有其他的则为内环
coordinates: [
[
[-5e6, -1e6],
[-4e6, 1e6],
[-3e6, -1e6]
]
]
}
},
{
type: "Feature",
geometry: {
type: "MultiLineString",
// MutiLineString中存放的是也是“linear ring数组”组成的数组,每个linear ring数组都是一条线
coordinates: [
[
[-1e6, -7.5e5],
[-1e6, 7.5e5]
],
[
[1e6, -7.5e5],
[1e6, 7.5e5]
],
[
[-7.5e5, -1e6],
[7.5e5, -1e6]
],
[
[-7.5e5, 1e6],
[7.5e5, 1e6]
]
]
}
},
{
type: "Feature",
geometry: {
type: "MultiPolygon",
// MultiPolygon中存放的是“Polygon坐标数组”组成的数组
coordinates: [
[
[
[-5e6, 6e6],
[-5e6, 8e6],
[-3e6, 8e6],
[-3e6, 6e6]
]
],
[
[
[-2e6, 6e6],
[-2e6, 8e6],
[0, 8e6],
[0, 6e6]
]
],
[
[
[1e6, 6e6],
[1e6, 8e6],
[3e6, 8e6],
[3e6, 6e6]
]
]
]
}
},
{
type: "Feature",
geometry: {
type: "GeometryCollection",
// GeometryCollection中有geometries几何集合对象,里面每一项都是一个几何对象
geometries: [
{
type: "LineString",
coordinates: [
[-5e6, -5e6],
[0, -5e6]
]
},
{
type: "Point",
coordinates: [4e6, -5e6]
},
{
type: "Polygon",
coordinates: [
[
[1e6, -6e6],
[2e6, -4e6],
[3e6, -6e6]
]
]
}
]
}
}
]
};

// 定义一个矢量源vectorSource,features读取自geojson对象
let vectorSource = new ol.source.Vector({
features: new ol.format.GeoJSON().readFeatures(geojsonObject)
});
// 给vectorSource添加圆这个特征对象
vectorSource.addFeature(new ol.Feature(new ol.geom.Circle([5e6, 7e6], 1e6)));

定义完 geojson 对象后,使用new ol.format.GeoJSON().readFeatures(geojsonObject)方法返回一个特征对象集合,API 如下所示,作为 vectorSource 源中 features 的值。

readFeatures

OpenLayers 与 GeoJSON 格式规范不同的是,OpenLayers 可以绘制“圆”这种 feature 特征对象,如上述代码所示,使用new ol.geom.Circle([5e6, 7e6], 1e6)新建一个 circle 几何对象,再用new ol.Feature几何对象变为特征对象,再用addFeature将“圆”添加给 vectorSource 源。

样式函数

定义样式的时候,主要是遵循下面这个原则:

  • LineStringMultiLineString 这两种一维线类型,只能 stroke 画线;
  • PolygonMultiPolygon 这两种二维多边形类型,既可以 stroke 画线描边,也可以 fill 填充;
  • PointMultiPoint 这种零维点类型,既不能 stroke 画线,又不能 fill 填充,所以定义一个 image对象,专门给点类型画一个小圆点;
  • GeometryCollection 属于几何集合类型,要把 stroke 画线、fill 填充和 image 小圆点都加上;
  • Circle 这种 OpenLayers 自定义的二维几何类型,同样也是既可以 stroke 画线,又可以 fill 填充;
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
// 当type为Point和MultiPoint时既不能stroke也不能fill,所以创建一个小圆点
let image = new ol.style.Circle({
radius: 5,
fill: null,
stroke: new ol.style.Stroke({ color: "red", width: 1 })
});

let styles = {
// 当几何对象为Point时,使用image样式
Point: new ol.style.Style({
image: image
}),
// 当几何对象为LineString时,使用stroke样式
LineString: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "green",
width: 1
})
}),
// 当几何对象为MultiLineString时,使用stroke样式
MultiLineString: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "green",
width: 1
})
}),
// 当几何对象为MultiPoint时,使用image样式
MultiPoint: new ol.style.Style({
image: image
}),
// 当几何对象为MultiPolygon时,有stroke和fill样式
MultiPolygon: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "yellow",
width: 1
}),
fill: new ol.style.Fill({
color: "rgba(255, 255, 0, 0.1)"
})
}),
// 当几何对象为Polygon时,有stroke和fill样式
Polygon: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "blue",
lineDash: [4],
width: 3
}),
fill: new ol.style.Fill({
color: "rgba(0, 0, 255, 0.1)"
})
}),
// 当几何对象为GeometryCollection,stroke、fill、image三个样式都加上
GeometryCollection: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "magenta",
width: 2
}),
fill: new ol.style.Fill({
color: "magenta"
}),
image: new ol.style.Circle({
radius: 10,
fill: null,
stroke: new ol.style.Stroke({
color: "magenta"
})
})
}),
// 当几何对象为Circle时,有stroke和fill样式
Circle: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "red",
width: 2
}),
fill: new ol.style.Fill({
color: "rgba(255,0,0,0.2)"
})
})
};
// 样式函数styleFunction,根据特征对象中几何对象的type来返回样式
const styleFunction = feature => {
return styles[feature.getGeometry().getType()];
};

最后定义一个 styleFunction样式返回函数,使用feature.getGeometry().getType()根据每一个特征对象几何对象类型来返回对应的样式。

全部代码

全部代码如下所示:

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.2.1/css/ol.css"
type="text/css"
/>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.2.1/build/ol.js"></script>
<title>GeoJSON</title>
<style>
html,
body,
.map {
height: 100%;
width: 100%;
}
</style>
</head>

<body>
<div id="map" class="map"></div>
<script type="text/javascript">
// 当type为Point和MultiPoint时既不能stroke也不能fill,所以创建一个小圆点
let image = new ol.style.Circle({
radius: 5,
fill: null,
stroke: new ol.style.Stroke({ color: "red", width: 1 })
});

let styles = {
// 当几何对象为Point时,使用image样式
Point: new ol.style.Style({
image: image
}),
// 当几何对象为LineString时,使用stroke样式
LineString: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "green",
width: 1
})
}),
// 当几何对象为MultiLineString时,使用stroke样式
MultiLineString: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "green",
width: 1
})
}),
// 当几何对象为MultiPoint时,使用image样式
MultiPoint: new ol.style.Style({
image: image
}),
// 当几何对象为MultiPolygon时,有stroke和fill样式
MultiPolygon: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "yellow",
width: 1
}),
fill: new ol.style.Fill({
color: "rgba(255, 255, 0, 0.1)"
})
}),
// 当几何对象为Polygon时,有stroke和fill样式
Polygon: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "blue",
lineDash: [4],
width: 3
}),
fill: new ol.style.Fill({
color: "rgba(0, 0, 255, 0.1)"
})
}),
// 当几何对象为GeometryCollection,stroke、fill、image三个样式都加上
GeometryCollection: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "magenta",
width: 2
}),
fill: new ol.style.Fill({
color: "magenta"
}),
image: new ol.style.Circle({
radius: 10,
fill: null,
stroke: new ol.style.Stroke({
color: "magenta"
})
})
}),
// 当几何对象为Circle时,有stroke和fill样式
Circle: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "red",
width: 2
}),
fill: new ol.style.Fill({
color: "rgba(255,0,0,0.2)"
})
})
};
// 样式函数styleFunction,根据特征对象中几何对象的type来返回样式
const styleFunction = feature => {
return styles[feature.getGeometry().getType()];
};
// geojson对象
let geojsonObject = {
// FeatureCollection是规范中的九种GeoJSON类型之一
type: "FeatureCollection",
// crs是规范中的自定义的外部成员
crs: {
type: "name",
properties: {
// 投影方式为EPSG:3857
name: "EPSG:3857"
}
},
// features中存放特征对象
features: [
{
// Feature也是规范中的九种GeoJSON类型之一
type: "Feature",
// geometry是几何对象
geometry: {
// Point是规范中的七种几何类型之一
type: "Point",
// coordinates数组中存放位置,第一个是经度方向,第二个是纬度方向,如果有第三个则为高度方向
coordinates: [0, 0]
}
},
{
type: "Feature",
geometry: {
type: "LineString",
// LineString中存放的是位置数组
coordinates: [
[4e6, -2e6],
[8e6, 2e6]
]
}
},
{
type: "Feature",
geometry: {
type: "LineString",
coordinates: [
[4e6, 2e6],
[8e6, -2e6]
]
}
},
{
type: "Feature",
geometry: {
type: "Polygon",
// Polygon中存放的“linear ring数组”组成的数组,第一个数组是外环,如果有其他的则为内环
coordinates: [
[
[-5e6, -1e6],
[-4e6, 1e6],
[-3e6, -1e6]
]
]
}
},
{
type: "Feature",
geometry: {
type: "MultiLineString",
// MutiLineString中存放的是也是“linear ring数组”组成的数组,每个linear ring数组都是一条线
coordinates: [
[
[-1e6, -7.5e5],
[-1e6, 7.5e5]
],
[
[1e6, -7.5e5],
[1e6, 7.5e5]
],
[
[-7.5e5, -1e6],
[7.5e5, -1e6]
],
[
[-7.5e5, 1e6],
[7.5e5, 1e6]
]
]
}
},
{
type: "Feature",
geometry: {
type: "MultiPolygon",
// MultiPolygon中存放的是“Polygon坐标数组”组成的数组
coordinates: [
[
[
[-5e6, 6e6],
[-5e6, 8e6],
[-3e6, 8e6],
[-3e6, 6e6]
]
],
[
[
[-2e6, 6e6],
[-2e6, 8e6],
[0, 8e6],
[0, 6e6]
]
],
[
[
[1e6, 6e6],
[1e6, 8e6],
[3e6, 8e6],
[3e6, 6e6]
]
]
]
}
},
{
type: "Feature",
geometry: {
type: "GeometryCollection",
// GeometryCollection中有geometries几何集合对象,里面每一项都是一个几何对象
geometries: [
{
type: "LineString",
coordinates: [
[-5e6, -5e6],
[0, -5e6]
]
},
{
type: "Point",
coordinates: [4e6, -5e6]
},
{
type: "Polygon",
coordinates: [
[
[1e6, -6e6],
[2e6, -4e6],
[3e6, -6e6]
]
]
}
]
}
}
]
};

// 定义一个矢量源vectorSource,features读取自geojson对象
let vectorSource = new ol.source.Vector({
features: new ol.format.GeoJSON().readFeatures(geojsonObject)
});
// 给vectorSource添加圆这个特征对象
vectorSource.addFeature(
new ol.Feature(new ol.geom.Circle([5e6, 7e6], 1e6))
);
// 定义一个矢量图层vectorLayer,源source为vectorSource,样式style为样式函数styleFunction
let vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: styleFunction
});
// 给地图加一个OSM底图
let map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
],
target: "map",
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
</script>
</body>
</html>
👆 全文结束,棒槌时间到 👇