概述
shapefile
是常见的矢量数据格式,但是由于其文件组成结构很难在webgis上直接展示。本文通过express
和compressing
实现打包后shapefile
文件的上传,并结合shapefile.js
实现shapefile
数据的转换展示。
实现效果
实现代码
1. 后端实现
router.post('/upload/shp', function (req, res) {
const filePath = path.resolve(__dirname, '../')
const basePath = `${filePath}/${config.root}/shape/`
fileUtils.dirExists(basePath).then(() => {
fs.readFile(req.files[0].path, function (err, data) {
const timestamp = Date.now()
const des_file = basePath + timestamp + '.zip' ;
const des_path = basePath + timestamp
fs.writeFile(des_file, data, function (err) {
compressing.zip.uncompress(des_file, des_path).then(() => {
const file = fs.readdirSync(des_path)[0]
const {ext, name} = path.parse(file);
let fileName = ''
if(ext) { // 文件
fileName = `${name}.shp`
} else { // 文件夹
const _path = des_path + '/' + name
const _file = fs.readdirSync(_path)[0]
fileName = `${name}/${path.parse(_file).name}.shp`;
}
const response = {
code: 200,
url: `//${config.url}/shape/${timestamp}/${fileName}`
};
res.end(JSON.stringify(response));
}).catch(() => {
console.log('解压失败')
})
});
});
})
})
2.前端实现
页面代码如下:
<div id="app" class="container">
<div class="map-tools">
<el-upload
ref="upload"
:action="uploadAction"
:multiple="false"
:limit="1"
:auto-upload="false"
:before-upload="beforeUpload"
:on-change="changeMethod"
accept=".zip"
:on-success="successMethod"
:file-list="fileList"
drag
class="upload-demo">
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或<em>点击上传</em><br>
<b>只允许上传zip文件</b>
</div>
</el-upload>
<el-button class="my-button" size="small" type="primary" @click="clearShow()">清除展示</el-button>
</div>
<div id="map" class="map"></div>
</div>
js实现代码如下:
let jsonformat = new ol.format.GeoJSON();
let vectorSource = new ol.source.Vector({
features: []
})
let styleFunction = (feat) => {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({color: 'rgba(0, 0, 255, 0.5)'}),
stroke: new ol.style.Stroke({color: 'rgba(0, 0, 255, 1)', width: 6})
}),
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 255, 1)',
width: 3
}),
fill: new ol.style.Fill({color: 'rgba(0, 0, 255, 0.1)'}),
})
}
let vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: styleFunction,
zIndex: 9
});
const app = new Vue({
el: '#app',
mounted() {
this.initMap()
},
computed: {
uploadAction() {
return `//${window.location.hostname}/file/upload/shp`
}
},
data() {
return {
fileList: []
}
},
methods: {
initMap() {
window.map = new ol.Map({
controls: ol.control.defaults({
attribution: false
}),
target: 'map',
layers: [getBaseLayer(), vectorLayer],
view: new ol.View({
center: [11598420.046414003, 4059611.6231072573],
zoom: 4
})
});
},
beforeUpload(file) {
const that = this
if(!file.type === 'application/zip') {
that.$message("只能上传*.zip格式压缩包", "error");
return false;
}
},
changeMethod() {
const that = this
that.$refs.upload.submit();
},
successMethod({code, url}) {
if(code === 200) {
this.$message('文件上传成功!')
this.fileList = []
shapefile.open(url)
.then(source => source.read()
.then(function log(result) {
if (result.done) return;
let features = jsonformat.readFeatures(result.value, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857',
})
vectorSource.clear()
vectorSource.addFeatures(features);
map.getView().fit(vectorSource.getExtent(), {
padding: [100,100,100,100]
})
}))
.catch(error => console.error(error.stack));
}
},
clearShow() {
vectorSource.clear()
}
}
})
function getBaseLayer(){
return new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://gac-geo.googlecnapps.cn/maps/vt?lyrs=m&x={x}&y={y}&z={z}'
})
})
}