贴个群号
WebGIS学习交流群461555818,欢迎大家。
效果图
原理与源码
本文采用的是shapefile.js工具
这里是他的npm地址
https://www.npmjs.com/package/shapefile
这是他的unpkg地址,可以点开查看源码
https://unpkg.com/shapefile@0.6.6/dist/shapefile.js
这个最关键的核心问题是如何用这个工具,网上的大多数用法包括官网的例子,我用来皆不可行。
首先网上的例子大概都是这样用的,都是线上的地址,而我们是要加载本地的shp文件,而我尝试将本地的shp的file文件流加载并不可行。而官网又无其它例子与介绍,我们只能去翻阅他的源码。
查看源码发现,这个open方法解析shp的话,他只接受1是后缀名为.shp的文件,那也就是上面官方例子的在线地址,2是接受ArrayBuffer和Uint8Array的二进制文件流,那我们是不是采取第二种方法就好了?
function open(shp$$1, dbf$$1, options) {
if (typeof dbf$$1 === "string") {
if (!/\.dbf$/.test(dbf$$1)) dbf$$1 += ".dbf";
dbf$$1 = path(dbf$$1, options);
} else if (dbf$$1 instanceof ArrayBuffer || dbf$$1 instanceof Uint8Array) {
dbf$$1 = array(dbf$$1);
} else if (dbf$$1 != null) {
dbf$$1 = stream(dbf$$1);
}
if (typeof shp$$1 === "string") {
if (!/\.shp$/.test(shp$$1)) shp$$1 += ".shp";
if (dbf$$1 === undefined) dbf$$1 = path(shp$$1.substring(0, shp$$1.length - 4) + ".dbf", options).catch(function() {});
shp$$1 = path(shp$$1, options);
} else if (shp$$1 instanceof ArrayBuffer || shp$$1 instanceof Uint8Array) {
shp$$1 = array(shp$$1);
} else {
shp$$1 = stream(shp$$1);
}
return Promise.all([shp$$1, dbf$$1]).then(function(sources) {
var shp$$1 = sources[0], dbf$$1 = sources[1], encoding = "windows-1252";
if (options && options.encoding != null) encoding = options.encoding;
return shapefile(shp$$1, dbf$$1, dbf$$1 && new TextDecoder(encoding));
});
}
于是我们就尝试要将文件转换为ArrayBuffer和Uint8Array格式的文件流,代码如下
//转换文件为二进制流
transferToArrayBuffer(file){
let fileType = file.name.split('.')[1]
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.readAsArrayBuffer(file) //读取文件为 ArrayBuffer
reader.onload = function(evt){
try {
let fileData = evt.target.result //fileData就是读取到的文件ArrayBuffer
resolve(fileData)
} catch (error) {
console.error("File cannot be read or JSON is invalid.");
reject(error); // 使用reject返回错误信息
}
}
})
},
其结果就是解析为ArrayBuffer的二进制文件流,如果是想要Uint8Array格式的话,可以直接将fileData改为 new Uint8Array(fileData),
然后
shapefile.open(fileData).then(source => source.read().then(function log(result) {
console.log(result)
let geojson = result.value
resolve(geojson); // 使用resolve返回结果
}))
我们会发现确实可以得到一个转换为json的结果,但是呢,只有geometry信息,并没有properties信息,然后会发现shapefile.open其实是可以接受三个参数的,在源码中也有体现
function open(shp$$1, dbf$$1, options)
也要讲dbf文件引入进来,关于shp文件的各个部分的内容如下。
这里我们只需要shp和dbf,dbf同样也要解析成为ArrayBuffer和Uint8Array格式。
shapefile.open(shp,dbf).then(source => source.read().then(function log(result) {
console.log(result)
let geojson = result.value
}))
这样就大功告成了吗?非也,反正我的是没成,得到的结果大概是整个shp文件的第一个要素的信息,是一个单独的feature,并不是全部features。但是仔细查看上述操作并不问题。
再次查看源码,发现了shapefile.js的另外一个方法,那就是.read方法。其源码如下
function read(shp$$1, dbf$$1, options) {
return open(shp$$1, dbf$$1, options).then(function(source) {
var features = [], collection = {type: "FeatureCollection", features: features, bbox: source.bbox};
return source.read().then(function read(result) {
if (result.done) return collection;
features.push(result.value);
return source.read().then(read);
});
});
}
可以看到其返回的是全部的features!!!,但是好奇的是全网竟无人说过read方法,实际使用的时候,read方法确实是可行的,而且更加简洁。