GeoJSONVectorTileLayer
GeoJSONVectorTileLayer是VectorTileLayer的子类,区别在于其是对geojson文件在前端自动切片的图层.
该图层基于的 geojson-vt 开源库,在worker中对GeoJSON数据实时切片后返回给主线程渲染绘制。
注意其在maptalks-gl包里,你需要:
npm i maptalks-gl设置数据的主键
图层支持配置 featureIdProperty,即让properties里的 某个值作为id主键
const layer = new maptalks.GeoJSONVectorTileLayer("geo", {
featureIdProperty: "id",
features: true,
pickingGeometry: true,
debugTileData: true,
data: url / geojsondata,
});怎样获取某个数据?
GeoJSONVectorTileLayer 也提供了 getGeometryById方法,设置完数据的主键后featureIdProperty后, 图层会收集所有的要素并组成一个全局的要素集合
主要数据的加载是异步的,所以要在图层的数据加载完成或者瓦片加载完成后去 getGeometryById
layer.on("dataload", (e) => {
// console.log(e);
const feature = layer.getGeometryById("id0");
console.log(feature);
});
layer.on("tileload", (e) => {
// console.log(e);
const feature = layer.getGeometryById("id0");
console.log(feature);
});GeoJSONVectorTileLayer custom feature id demo
GeoJSONVectorTileLayer 使用注意事项
- GeoJSONVectorTileLayer是在前端对GeoJSON文件进行自动切片,所以不适合数据体积比较大的GeoJSON
- GeoJSON比较大时解决方法:
- 应该将GeoJSON切成静态的MVT数据放到服务端
- 或者把GeoJSON文件导入数据库有数据库提供MVT服务
- 或者利用GeoServer等GIS容器发布成MVT服务
然后用VectorTileLayer去加载服务
- GeoJSONVectorTileLayer图层不宜过多,即使每个GeoJSON文件不大,当GeoJSONVectorTileLayer过多时:
- 因为图层太多,导致浏览器有大面积的切片服务,即使放到worker里也会导致大面积的worker数据通信,因此性能极差
可以把多个GeoJSON文件合并成一个文件,然后再GeoJSONVectorTileLayer的样式系统里用filter进行数据分类和进行分类配置样式
- 关于合并GeoJSON
- 可以在前端请求这些GeoJSON文件,然后将他们合并成一个
- 或者用工具或者自己写个脚本将其合并成一个文件放到前端的项目里的静态目录
- 具体的可以参考这个geojson 合并的例子
加载非EPSG:4326的geojson文件
geojson-vt的数据源只能是EPSG4326的数据源(除非你魔改), 但是有时我们项目里的数据投影可能其他投影的数据文件,比如我所在的江苏地区喜欢用EPSG4528,这时如果要是用GeoJSONVectorTileLayer加载需要我们对GeoJSON文件里坐标 数据进行投影转换下
- 可以使用一些工具,比如Arcgis,QGIS等
- 也可以利用 proj4js库在前端直接对geojson文件转换下, 相对于使用桌面工具更加灵活和动态
- 其他的坐标转换方法等,比如你的数据在数据库里也可以使用数据库里的内置函数来解决投影转换等
TIP
一句话,非4326投影的就把数据转成4326,不限制使用方法,你怎么方便怎么来
这里演示下加载EPSG4528的数据源,为了方便演示代码所以使用了proj4js在前端直接 转换geojson文件
编写geojson坐标转换函数
如果你是个GISer的话,你对proj4js应该是不陌生的,第一次接触的同学请参阅其官方 仓库 proj4js
proj4.defs(
"EPSG:4528",
"+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs",
);
proj4.defs("EPSG:4326", "+proj=longlat +datum=WGS84 +no_defs +type=crs");
//I'm not going to redefine those two in latter examples.
// const result = proj4('EPSG:4528', 'EPSG:4326', [40639772.446103811264038, 3466944.809701459016651]);
// console.log(result);
function geojsonTransform(geojson) {
const coordinatesTransform = (coordinate) => {
if (Array.isArray(coordinate[0])) {
return coordinate.map((c) => {
return coordinatesTransform(c);
});
} else {
return proj4("EPSG:4528", "EPSG:4326", coordinate);
}
};
geojson.features.forEach((feature) => {
const coordinates = feature.geometry.coordinates;
feature.geometry.coordinates = coordinatesTransform(coordinates);
});
}GeoJSONVectorTileLayer的数据源设置为转换后的geojson
const style = {
style: [
{
name: "area-fill",
filter: true,
renderPlugin: {
dataConfig: {
type: "fill",
},
sceneConfig: {},
type: "fill",
},
symbol: {
polygonFill: "green",
polygonOpacity: 0.7,
},
},
{
name: "area-border",
filter: true,
renderPlugin: {
dataConfig: {
type: "line",
},
sceneConfig: {},
type: "line",
},
symbol: {
lineColor: "#000",
lineOpacity: 1,
lineWidth: 2,
},
},
],
};
const layer = new maptalks.GeoJSONVectorTileLayer("geo", {
style,
//默认设置空的数据源
data: {
type: "FeatureCollection",
features: [],
},
});
layer.on("dataload", (e) => {
map.fitExtent(e.extent);
});
const groupGLLayer = new maptalks.GroupGLLayer("gl", [layer], {}).addTo(map);
function loadData() {
fetch("./../assets/data/shanghai-epsg4528.geojson")
.then((res) => res.json())
.then((geojson) => {
//transform EPSG4528 to EPSG4326
geojsonTransform(geojson);
layer.setData(geojson);
});
}
loadData();WARNING
GeoJSONVectorTileLayer适合加载小数据量的geojson,如果数据量比较大请参阅上面的注意事项里的解决方案