自己的九又四分之三站台

自己的九又四分之三站台

本文用纯前端获取shp文件以及前后端交互的方式获取Shapefile文件中的图形信息

1.案例说明

在日常的WebGIS开发中,我们往往会面对,需要用户选择矢量数据,通过矢量数据中的空间范围信息,显示在界面上,并给用户的下一步操作提供一定意义上的数据基础。

在上述的描述上我们会接收到如下数据

  • WKT、GeoJSON字符串
  • Shape file文件
  • GDB文件

本文我们来看看Shapefile文件,关于Shapefile可以参考此文什么是shapefile文件_shapefile和kml最多能存多少个点-CSDN博客

2.技术实现

本文只对Shapefile文件进行技术实现,Shapefile文件相较比较简单,因为有开源标准所以第三方包比较多。

本文提供两种解决方案

  • 前端选择Shapefile相关文件,将文件上传到后端,后端使用相关技术解析,使用WKT或者GeoJson返回
  • 纯前端解析Shape file文件

本文的两种方案均可以只解析[.shp]文件,而不需要文件组。

2.1. 前后端衔接

此处就不说明前端如何传输文件了。后端使用Java技术栈(后续有时间研究一下C#中是否存在相同的技术方案。)

Java使用Geotools可以直接解析Shapefile文件,并且可以只解析Shp文件,而不需要同级目录下有其他相关的文件。

import org.geotools.data.FileDataStore;  
import org.geotools.data.FileDataStoreFinder;  
import org.geotools.data.shapefile.shp.ShapefileReader;  
import org.geotools.data.simple.SimpleFeatureSource;  
import org.geotools.data.simple.SimpleFeatureIterator;  
import org.opengis.feature.simple.SimpleFeature;  
  
import java.io.File;  
import java.io.IOException;  
  
public class ReadShapefileMain {  
  
    public void readShp(String path) {  
        File file = new File(path);  
        FileDataStore store = null;  
        SimpleFeatureIterator iterator = null;  
        try {  
            store = FileDataStoreFinder.getDataStore(file);  
            SimpleFeatureSource featureSource = store.getFeatureSource();  
            iterator = featureSource.getFeatures().features();  
  
            while (iterator.hasNext()) {  
                SimpleFeature feature = iterator.next();  
                // 这里你可以访问 feature 的几何数据  
                System.out.println(feature.getDefaultGeometry());  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            if (iterator != null) {  
                iterator.close();  
            }  
            if (store != null) {  
                store.dispose();  
            }  
        }  
    }  
  
    public static void main(String[] args) {  
        ReadShapefileMain reader = new ReadShapefileMain();  
        reader.readShp("C:\\Users\\HTHT\\Desktop\\1\\12\\320312.shp");  
    }  
}

应用工程中获取Shapefile文件的图形信息并显示-LMLPHP
应用工程中获取Shapefile文件的图形信息并显示-LMLPHP

如果需要合并所有图形并修改图形的表达方式可以使用Geotools中的JTS进行相关的操作。

2.2.纯前端实现

如果需要在 JavaScript 中直接读取 .shp 文件(而不涉及 .dbf 文件),一个可能的解决方案是使用 shapefile 库,这是一个可以在 Node.js 和浏览器中使用的纯 JavaScript 库。它可以读取 .shp 文件并将其解析为 GeoJSON 格式。

npm install shapefile

要在 JavaScript 中将所有几何图形(如从 .shp 文件读取的)执行 Union 操作,我们可以使用 turf.js 库。turf.js 是一个强大的地理空间处理库,它提供了各种用于处理和分析空间数据的方法,包括 Union 操作。

npm install @turf/turf

在JavaScript中实现GeoJSON和WKT(Well-Known Text)格式之间的相互转换,你可以使用一些现有的库,如Terraformerwellknown

npm install terraformer terraformer-wkt-parser

前端代码

<template>
  <!-- 文件输入 -->
  <input type="file" @change="handleFileChange" />
</template>

<script>
import * as shapefile from 'shapefile';
import * as turf from 'turf';
import * as WKT from 'terraformer-wkt-parser';

export default {
  methods: {
    handleFileChange(event) {
      const file = event.target.files[0];
      this.readShpFile(file);
    },
    readShpFile(file) {
      const reader = new FileReader();
      reader.onload = (e) => {
        const arrayBuffer = e.target.result;
        shapefile.read(arrayBuffer)
          .then(geojson => {
            this.unionGeometries(geojson);
          })
      };
      reader.readAsArrayBuffer(file);
    },
    unionGeometries(geojson) {
      let combinedGeometry = null;
      geojson.features.forEach((feature, index) => {
        if (index === 0) {
          combinedGeometry = feature.geometry;
        } else {
          combinedGeometry = turf.union(turf.feature(combinedGeometry), feature).geometry;
        }
      });
      console.log('GeoJson---Geometry:', combinedGeometry);
      const wkt1 = WKT.convert(JSON.parse(JSON.stringify(combinedGeometry)));
      console.log(wkt1);
      console.log(JSON.stringify(WKT.parse(wkt1), null, 2));
    }
  }
};
</script>

2.3. 附:terraformer-wkt-parser 格式转换

<template>
  <div>
    <h2>GeoJSON and WKT Converter</h2>
    <textarea v-model="input" placeholder="Enter GeoJSON or WKT..."></textarea>
    <button @click="convert">Convert</button>
    <div v-if="output">
      <h3>Result</h3>
      <pre>{{ output }}</pre>
    </div>
  </div>
</template>

<script>
import * as WKT from 'terraformer-wkt-parser';

export default {
  name: 'GeoConverter',
  data() {
    return {
      input: '',
      output: ''
    };
  },
  methods: {
    convert() {
      try {
        if (this.input.trim().startsWith('{')) {
          // Assume it's GeoJSON
          const geoJson = JSON.parse(this.input);
          this.output = WKT.convert(geoJson);
        } else {
          // Assume it's WKT
          this.output = JSON.stringify(WKT.parse(this.input), null, 2);
        }
      } catch (error) {
        this.output = 'Error: ' + error.message;
      }
    }
  }
};
</script>

<style scoped>
	textarea {
	  width: 100%;
	  height: 100px;
	  margin-bottom: 10px;
	}
	
	pre {
	  background-color: #f0f0f0;
	  padding: 10px;
	}
</style>
03-12 11:17