OpenLayers中的GeoJSON
GeoJSON是WebGIS中非常常见的矢量数据格式,而OpenLayers提供了专门的GeoJSON格式类,用于在GeoJSON与OpenLayers Feature之间进行转换。
简单来说:
GeoJSON
↓
OpenLayers GeoJSON
↓
Feature
↓
VectorSource
↓
VectorLayer
↓
Map
OpenLayers中的GeoJSON主要用于:
- 加载GeoJSON
- 将GeoJSON转换为Feature
- 将Feature转换为GeoJSON
- 坐标系转换
- GeoJSON数据导出
- WebGIS接口数据展示
OpenLayers的GeoJSON类
OpenLayers使用:
import GeoJSON from 'ol/format/GeoJSON.js'
创建GeoJSON格式对象:
const format = new GeoJSON()
之后可以使用:
format.readFeature()
format.readFeatures()
format.writeFeature()
format.writeFeatures()
完成GeoJSON与Feature之间的转换。
GeoJSON与Feature的关系
OpenLayers中的GeoJSON主要负责数据格式转换。
可以理解为:
GeoJSON
↓
ol/format/GeoJSON
↓
Feature
而Feature是OpenLayers地图运行时使用的对象。
因此:
GeoJSON
↓
数据交换格式
Feature
↓
OpenLayers运行时对象
读取单个Feature
如果GeoJSON表示一个Feature,可以使用:
const feature = format.readFeature(geojson)
例如:
const geojson = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [116.397, 39.908]
},
properties: {
name: '北京'
}
}
const feature = format.readFeature(geojson)
读取之后:
GeoJSON Feature
↓
readFeature()
↓
OpenLayers Feature
读取FeatureCollection
实际WebGIS接口中更常见的是:
FeatureCollection
例如:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [116.397, 39.908]
},
"properties": {
"name": "北京"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [121.473, 31.230]
},
"properties": {
"name": "上海"
}
}
]
}
可以使用:
const features = format.readFeatures(geojson)
返回:
Feature[]
即:
GeoJSON FeatureCollection
↓
readFeatures()
↓
Feature[]
创建VectorSource
读取Feature之后,通常会放入VectorSource。
import VectorSource from 'ol/source/Vector.js'
const source = new VectorSource({
features
})
完整流程:
GeoJSON
↓
readFeatures()
↓
Feature[]
↓
VectorSource
创建VectorLayer
然后使用VectorLayer显示数据。
import VectorLayer from 'ol/layer/Vector.js'
const layer = new VectorLayer({
source
})
最后加入地图:
map.addLayer(layer)
完整代码:
import GeoJSON from 'ol/format/GeoJSON.js'
import VectorSource from 'ol/source/Vector.js'
import VectorLayer from 'ol/layer/Vector.js'
const format = new GeoJSON()
const features = format.readFeatures(geojson)
const source = new VectorSource({
features
})
const layer = new VectorLayer({
source
})
map.addLayer(layer)
完整数据流:
GeoJSON
↓
GeoJSON.readFeatures()
↓
Feature[]
↓
VectorSource
↓
VectorLayer
↓
Map
读取GeoJSON字符串
GeoJSON也可以是JSON字符串。
例如:
const json = `{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [116.397, 39.908]
},
"properties": {
"name": "北京"
}
}`
可以直接:
const feature = format.readFeature(json)
OpenLayers会解析JSON字符串。
读取JSON对象
如果已经通过:
JSON.parse()
获得JavaScript对象:
const data = JSON.parse(json)
也可以:
const features = format.readFeatures(data)
因此:
JSON字符串
↓
readFeature / readFeatures
JSON对象
↓
readFeature / readFeatures
读取GeoJSON Geometry
除了Feature,也可以直接读取Geometry。
例如:
{
"type": "Point",
"coordinates": [116.397, 39.908]
}
可以使用:
const geometry = format.readGeometry(geojson)
得到OpenLayers Geometry对象。
关系:
GeoJSON Geometry
↓
readGeometry()
↓
ol/geom/Geometry
例如:
const geometry = format.readGeometry({
type: 'Point',
coordinates: [116.397, 39.908]
})
Geometry与Feature的区别
如果GeoJSON是:
Geometry
使用:
readGeometry()
如果GeoJSON是:
Feature
使用:
readFeature()
如果GeoJSON是:
FeatureCollection
使用:
readFeatures()
可以记住:
Geometry
↓
readGeometry()
Feature
↓
readFeature()
FeatureCollection
↓
readFeatures()
坐标系转换
这是OpenLayers读取GeoJSON时非常重要的功能。
GeoJSON数据可能使用:
EPSG:4326
而OpenLayers地图通常使用:
EPSG:3857
例如:
GeoJSON
EPSG:4326
↓
坐标转换
↓
Feature
EPSG:3857
可以通过:
const features = format.readFeatures(geojson, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
其中:
dataProjection
↓
GeoJSON数据本身的坐标系
featureProjection
↓
OpenLayers Feature使用的坐标系
为什么需要坐标转换
例如GeoJSON:
[116.397, 39.908]
通常表示:
经度 = 116.397
纬度 = 39.908
属于:
EPSG:4326
而Web地图经常使用:
EPSG:3857
如果直接把两种坐标混合使用:
EPSG:4326
↓
直接当成EPSG:3857
地图上的位置就会出现错误。
因此应该明确:
数据坐标系
↓
dataProjection
地图坐标系
↓
featureProjection
readFeature中的坐标转换
例如:
const feature = format.readFeature(geojson, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
OpenLayers会在读取过程中完成坐标转换。
因此:
GeoJSON
EPSG:4326
↓
GeoJSON.readFeature()
↓
坐标转换
↓
Feature
EPSG:3857
readFeatures中的坐标转换
FeatureCollection通常使用:
const features = format.readFeatures(geojson, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
这是WebGIS项目中非常常见的写法。
例如:
const format = new GeoJSON()
const features = format.readFeatures(data, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
然后:
const source = new VectorSource({
features
})
从Feature生成GeoJSON
OpenLayers也可以将Feature转换为GeoJSON。
例如:
const geojson = format.writeFeature(feature)
结果:
Feature
↓
writeFeature()
↓
GeoJSON
例如:
const feature = new Feature({
geometry: new Point([12958000, 4850000])
})
const geojson = format.writeFeature(feature)
返回的是GeoJSON字符串。
writeFeatureObject
如果希望获得JavaScript对象,可以使用:
const object = format.writeFeatureObject(feature)
例如:
const data = format.writeFeatureObject(feature)
console.log(data)
得到类似:
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [116.397, 39.908]
},
"properties": {}
}
因此:
writeFeature()
↓
GeoJSON字符串
writeFeatureObject()
↓
GeoJSON对象
导出多个Feature
多个Feature可以使用:
const geojson = format.writeFeatures(features)
例如:
const features = source.getFeatures()
const geojson = format.writeFeatures(features)
流程:
VectorSource
↓
getFeatures()
↓
Feature[]
↓
writeFeatures()
↓
GeoJSON
writeFeaturesObject
如果需要GeoJSON对象:
const object = format.writeFeaturesObject(features)
结果通常是:
{
"type": "FeatureCollection",
"features": []
}
因此:
writeFeatures()
↓
GeoJSON字符串
writeFeaturesObject()
↓
GeoJSON对象
导出时进行坐标转换
读取时可以:
dataProjection
featureProjection
写出时也需要注意坐标系。
例如:
const geojson = format.writeFeatures(features, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
可以理解为:
OpenLayers Feature
EPSG:3857
↓
writeFeatures()
↓
转换
↓
GeoJSON
EPSG:4326
这对于GeoJSON下载功能非常重要。
GeoJSON加载HTTP接口
实际项目中GeoJSON通常来自后端API。
例如:
const response = await fetch('/api/places')
const data = await response.json()
然后:
const features = format.readFeatures(data, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
再:
source.addFeatures(features)
完整流程:
HTTP API
↓
JSON
↓
GeoJSON
↓
readFeatures()
↓
Feature[]
↓
VectorSource
↓
Map
动态加载GeoJSON
也可以创建空的VectorSource:
const source = new VectorSource()
之后动态加载:
const response = await fetch('/data/city.geojson')
const data = await response.json()
const features = format.readFeatures(data, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
source.addFeatures(features)
这样可以在地图初始化之后继续加载数据。
GeoJSON与VectorSource
GeoJSON本身不是图层。
这是OpenLayers初学者容易混淆的地方。
GeoJSON
↓
数据格式
而:
VectorSource
↓
Feature数据容器
以及:
VectorLayer
↓
地图图层
因此:
GeoJSON
↓
Feature
↓
VectorSource
↓
VectorLayer
不能直接把GeoJSON理解成Layer。
GeoJSON与VectorLayer
正确结构:
GeoJSON
↓
GeoJSON Format
↓
Feature
↓
VectorSource
↓
VectorLayer
例如:
const features = new GeoJSON().readFeatures(data)
const source = new VectorSource({
features
})
const layer = new VectorLayer({
source
})
给GeoJSON设置样式
GeoJSON转换成Feature之后,就可以按照普通Feature进行样式设置。
例如:
const layer = new VectorLayer({
source,
style: new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: '#1677ff'
})
})
})
})
因此:
GeoJSON
↓
Feature
↓
Style
↓
VectorLayer
GeoJSON本身不负责地图显示样式。
根据属性设置样式
GeoJSON的:
properties
可以用于动态设置样式。
例如:
style: (feature) => {
const status = feature.get('status')
if (status === 'warning') {
return warningStyle
}
return normalStyle
}
GeoJSON:
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [116.397, 39.908]
},
"properties": {
"status": "warning"
}
}
读取后:
feature.get('status')
就可以获得:
warning
因此:
GeoJSON properties
↓
Feature属性
↓
样式判断
↓
地图显示
GeoJSON中的属性读取
例如:
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [116.397, 39.908]
},
"properties": {
"name": "北京",
"type": "city"
}
}
读取之后:
feature.get('name')
得到:
北京
读取:
feature.get('type')
得到:
city
也可以:
feature.getProperties()
获得全部属性。
获取Geometry
OpenLayers Feature中可以通过:
const geometry = feature.getGeometry()
获取Geometry。
关系:
Feature
↓
getGeometry()
↓
Geometry
例如:
const geometry = feature.getGeometry()
console.log(geometry.getType())
可能得到:
Point
获取GeoJSON Geometry
如果想获得Feature中的Geometry对应GeoJSON,可以使用:
const geometry = format.writeGeometryObject(
feature.getGeometry()
)
结果类似:
{
"type": "Point",
"coordinates": [116.397, 39.908]
}
流程:
Feature
↓
getGeometry()
↓
Geometry
↓
writeGeometryObject()
↓
GeoJSON Geometry
GeoJSON Geometry转换
OpenLayers还可以直接:
format.writeGeometry(geometry)
或者:
format.writeGeometryObject(geometry)
因此:
readGeometry()
↓
GeoJSON → Geometry
writeGeometry()
↓
Geometry → GeoJSON
GeoJSON Feature转换总结
读取:
format.readFeature(data)
多个:
format.readFeatures(data)
Geometry:
format.readGeometry(data)
写出:
format.writeFeature(feature)
多个:
format.writeFeatures(features)
Geometry:
format.writeGeometry(geometry)
对象形式:
format.writeFeatureObject(feature)
format.writeFeaturesObject(features)
format.writeGeometryObject(geometry)
常见方法总结
| 方法 | 作用 |
|---|---|
| readFeature | GeoJSON Feature → Feature |
| readFeatures | FeatureCollection → Feature |
| readGeometry | GeoJSON Geometry → Geometry |
| writeFeature | Feature → GeoJSON字符串 |
| writeFeatures | Feature → GeoJSON字符串 |
| writeGeometry | Geometry → GeoJSON字符串 |
| writeFeatureObject | Feature → GeoJSON对象 |
| writeFeaturesObject | Feature → FeatureCollection对象 |
| writeGeometryObject | Geometry → GeoJSON Geometry对象 |
GeoJSON完整加载示例
import GeoJSON from 'ol/format/GeoJSON.js'
import VectorSource from 'ol/source/Vector.js'
import VectorLayer from 'ol/layer/Vector.js'
const format = new GeoJSON()
const response = await fetch('/data/cities.geojson')
const data = await response.json()
const features = format.readFeatures(data, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
const source = new VectorSource({
features
})
const layer = new VectorLayer({
source
})
map.addLayer(layer)
数据流:
cities.geojson
↓
fetch()
↓
JSON
↓
readFeatures()
↓
Feature[]
↓
VectorSource
↓
VectorLayer
↓
Map
GeoJSON完整导出示例
const format = new GeoJSON()
const features = source.getFeatures()
const geojson = format.writeFeatures(features, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
console.log(geojson)
流程:
VectorSource
↓
getFeatures()
↓
Feature[]
↓
writeFeatures()
↓
GeoJSON
下载GeoJSON
可以结合浏览器Blob实现下载。
const geojson = format.writeFeatures(features, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
const blob = new Blob(
[geojson],
{
type: 'application/geo+json'
}
)
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = 'data.geojson'
link.click()
URL.revokeObjectURL(url)
完整流程:
Feature[]
↓
GeoJSON
↓
Blob
↓
浏览器下载
↓
data.geojson
GeoJSON与WKT
OpenLayers也经常同时处理GeoJSON和WKT。
例如:
WKT
↓
WKT Format
↓
Feature
以及:
GeoJSON
↓
GeoJSON Format
↓
Feature
最终都可以进入:
Feature
↓
VectorSource
↓
VectorLayer
因此:
WKT ───────┐
↓
Feature
↑
GeoJSON ───┘
GeoJSON与API
典型后端接口:
GET /api/features
返回:
{
"type": "FeatureCollection",
"features": []
}
前端:
const data = await fetch('/api/features')
.then(res => res.json())
const features = new GeoJSON().readFeatures(data, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
然后:
source.addFeatures(features)
这是非常典型的OpenLayers业务开发模式。
GeoJSON与PostGIS
常见后端架构:
PostGIS
↓
Spatial Query
↓
ST_AsGeoJSON
↓
GeoJSON
↓
HTTP API
↓
OpenLayers
例如:
数据库Geometry
↓
GeoJSON
↓
HTTP
↓
OpenLayers
↓
Feature
OpenLayers负责的是:
GeoJSON
↓
Feature
而空间数据库负责:
Geometry
↓
查询
↓
GeoJSON
常见问题
GeoJSON加载后位置错误
首先检查:
dataProjection
featureProjection
例如:
format.readFeatures(data, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
})
GeoJSON点跑到错误位置
首先检查坐标顺序:
[经度, 纬度]
而不是:
[纬度, 经度]
Polygon显示异常
检查:
coordinates嵌套层级
Ring是否闭合
Geometry是否有效
Feature属性获取不到
检查GeoJSON中的:
properties
例如:
"properties": {
"name": "北京"
}
OpenLayers:
feature.get('name')
GeoJSON无法显示
检查:
GeoJSON格式
type
coordinates
geometry
properties
FeatureCollection
坐标系
OpenLayers GeoJSON核心关系
GeoJSON
│
├── Geometry
│
├── Feature
│ ├── geometry
│ └── properties
│
└── FeatureCollection
│
└── features[]
↓
GeoJSON.readFeatures()
↓
Feature[]
↓
VectorSource
↓
VectorLayer
↓
Map
OpenLayers GeoJSON读写关系
读取:
GeoJSON
↓
readGeometry()
↓
Geometry
GeoJSON Feature
↓
readFeature()
↓
Feature
GeoJSON FeatureCollection
↓
readFeatures()
↓
Feature[]
写出:
Geometry
↓
writeGeometry()
↓
GeoJSON
Feature
↓
writeFeature()
↓
GeoJSON
Feature[]
↓
writeFeatures()
↓
FeatureCollection
总结
OpenLayers中的GeoJSON主要通过:
import GeoJSON from 'ol/format/GeoJSON.js'
完成GeoJSON与OpenLayers对象之间的转换。
最核心的方法是:
readGeometry()
readFeature()
readFeatures()
writeGeometry()
writeFeature()
writeFeatures()
典型加载流程:
GeoJSON
↓
readFeatures()
↓
Feature[]
↓
VectorSource
↓
VectorLayer
↓
Map
典型导出流程:
Feature[]
↓
writeFeatures()
↓
GeoJSON
↓
下载 / API / 数据交换
而在实际WebGIS项目中,还需要特别注意:
GeoJSON坐标顺序
坐标参考系
dataProjection
featureProjection
Feature属性
Geometry结构
可以记住:
OpenLayers中的GeoJSON不是地图图层,而是负责GeoJSON与Feature、Geometry之间数据转换的格式类。GeoJSON经过解析后进入Feature,再由VectorSource和VectorLayer负责管理和显示。
相关工具
使用 IYATools 在线工具快速处理 GIS 数据