GIS加油站

shapefile.js实现shp数据的上传与展示

2023-05-08  本文已影响0人  牛老师讲webgis

概述

shapefile是常见的矢量数据格式,但是由于其文件组成结构很难在webgis上直接展示。本文通过expresscompressing实现打包后shapefile文件的上传,并结合shapefile.js实现shapefile数据的转换展示。

实现效果

image.png

实现代码

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}'
    })
  })
}
上一篇下一篇

猜你喜欢

热点阅读