GeoJSON

2024-01-02  本文已影响0人  xueyueshuai
<template>
  <div class="container">
    <h1>GeoJSON</h1>
    <p>
      <h2>添加元素状态</h2>
      <ul style="padding-left: 20px">
        <li>可添加点线面元素到页面</li>
        <li>可获取GeoJSON</li>
      </ul>
    </p>
    <p>
      <h2>编辑原属状态</h2>
      <ul style="padding-left: 20px">
        <li>可删除元素</li>
        <li>获取元素元素属性</li>
      </ul>
    </p>

    <p>
      <h2>展示状态</h2>
      <ul style="padding-left: 20px">
        <li>根据GeoJSON展示元素</li>
        <li>获取元素元素属性</li>
      </ul>
    </p>


    <div id="vue-openlayers"></div>

    <!-- 状态   -->
    <div>
      状态:
      <select v-model="status">
        <option value="drawing">添加元素状态</option>
        <option value="set-get-properties">编辑元素属性</option>
        <option value="display">展示状态</option>
      </select>

      <select id="type" v-model="type" v-if="status === 'drawing'">
        <option v-for="item in tools" :key="item.value" :value="item.value">画 - {{ item.label }}</option>
      </select>
      <button v-if="status === 'drawing'" @click="type='None'">停止作画</button>
    </div>


    <div v-if="status === 'drawing' || status === 'set-get-properties'">
      <fieldset style="margin: 5px;padding:5px">
        <legend>
          <button @click="get_GeoJSON_fromMap"> 将画布内容保存到 textarea</button>

          <button @click="downJsonStrFile">下载json</button>
        </legend>
        <textarea v-model="jsonStr"></textarea>
      </fieldset>
    </div>


    <div v-if="status === 'display'">
      <fieldset style="margin: 5px;padding:5px">
        <legend>
          <button @click="set_GeoJSON_toMap"> 将textarea内容 渲染到画布</button>
        </legend>
        <textarea v-model="jsonStr"></textarea>
        <button @click="downJsonStrFile">下载json</button>
      </fieldset>
    </div>

    <div style="margin-top:50px" v-if="activeFeature">
      <fieldset style="margin: 5px;padding:5px">
        <legend>
          {{ activeFeature ? '有选中' : '无选中' }}
          <button @click="getActiveFeatureProperties">将选中元素的属性 输入 到textarea</button>
          <button @click="setActiveFeatureProperties">将textarea内容 渲染 到选中的元素</button>
          <button @click="onDel">删除选中的元素</button>
        </legend>
        <textarea v-model="featurePropertiesStr"></textarea>
      </fieldset>
    </div>

  </div>
</template>

<script>
import md5 from 'md5'

import 'ol/ol.css'
import {Map, View} from 'ol'
import Tile from 'ol/layer/Tile'
import OSM from 'ol/source/OSM'

import LayerVector from 'ol/layer/Vector'
import SourceVector from 'ol/source/Vector'

import Style from 'ol/style/Style'
import Fill from 'ol/style/Fill'
import Stroke from 'ol/style/Stroke'
import Circle from 'ol/style/Circle'

import GeoJSON from "ol/format/GeoJSON";
import {Select, Translate, Draw} from "ol/interaction";
import XYZ from "ol/source/XYZ";
import {fromLonLat} from "ol/proj";

export default {
  data() {
    return {
      status: 'drawing', // drawing:编辑状态 display:展示状态

      type: 'Point',

      tools: [
        {value: 'Point', label: '点'},
        {value: 'LineString', label: '线'},
        {value: 'Polygon', label: '多边形'},
        {value: 'Circle', label: '圆'},
        {value: 'None', label: '无'}
      ],
      map: null, // 地图

      vectorLayer: null, //矢量图层 也就是画布
      vectorLayerSource: new SourceVector({
        wrapX: false
      }),

      drawInteraction: null, // 画图交互
      selectInteraction: null, // 选中交互
      translateInteraction: null, // 拖拽交互

      activeFeature: {},

      jsonStr: '', // {"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[112.70586074886323,22.8627981812439]},"properties":null},{"type":"Feature","geometry":{"type":"Point","coordinates":[112.83436538276673,22.97987660474396]},"properties":null},{"type":"Feature","geometry":{"type":"Point","coordinates":[113.02682460842134,23.100152221389774]},"properties":null}]}

      featurePropertiesStr: ''
    }
  },

  watch: {
    status: {
      handler(val) {
        this.selectInteraction?.getFeatures().clear()
        this.activeFeature = null

        this.$nextTick(() => {

          if (this.drawInteraction) this.map.removeInteraction(this.drawInteraction)
          if (this.selectInteraction) this.map.removeInteraction(this.selectInteraction)
          if (this.translateInteraction) this.map.removeInteraction(this.selectInteraction)

          if (val === 'display') {
            this.addSelectInteraction()
          }
          if (val === 'drawing') {
            this.addDrawInteraction()
          }

          if (val === 'set-get-properties') {
            this.addSelectInteraction()
            this.addTranslateInteraction();
          }
        })

      },
      immediate: true
    },
    type() {
      this.addDrawInteraction()
    }
  },
  mounted() {
    this.initMap()
  },
  methods: {
    initMap() {
      let vectorLayer = new LayerVector({
        source: this.vectorLayerSource,
        // Vector层显示的样式
        style: (feature) => {
          return this.getFeatureStyle(feature, false)
        }
      });

      this.vectorLayer = vectorLayer

      this.map = new Map({
        target: 'vue-openlayers',
        layers: [
          // new Tile({
          //   source: new OSM()
          // }),

          new Tile({
            source: new XYZ({
              url: 'http://wprd0{1-4}.is.auto' + 'navi.com/appmap' + 'tile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7'
            })
          }),

          vectorLayer
        ],

        view: new View({
          // projection: "EPSG:4326",
          // center: [116, 40],

          projection: "EPSG:3857",
          center: fromLonLat([116, 40]),

          zoom: 2.5,

          minZoom:2.5,
          maxZoom:20
        }),
      })

      this.map.on('moveend',()=>{
        let view = this.map.getView()
        let zoom = view.getZoom()
        console.log('zoom is '+ zoom)
      })
    },

    downJsonStrFile(){
      let jsonStr = this.jsonStr

      // 创建一个 Blob 对象,该对象表示数据,并设置 MIME 类型为 application/json
      const blob = new Blob([jsonStr], {type: "application/json"});

      // 创建一个下载链接
      const downloadLink = document.createElement("a");
      downloadLink.href = URL.createObjectURL(blob);
      downloadLink.download = "data.json"; // 设置文件名
      downloadLink.click()
    },

    addDrawInteraction() {
      if (this.drawInteraction !== null) {
        this.map.removeInteraction(this.drawInteraction)
      }

      if (this.type !== 'None') {
        this.drawInteraction = new Draw({
          source: this.vectorLayerSource,
          type: this.type,
          style: (feature => {
            return this.getFeatureStyle(feature, false)
          })
        })
        this.drawInteraction.on('drawend', (event) => {
          let drawnFeature = event.feature;
          // 设置要素的属性
          drawnFeature.setProperties({
            'uuid': this.getUuid(),
          });
        });

        this.map.addInteraction(this.drawInteraction)
      }
    },

    get_GeoJSON_fromMap() {
      let format = new GeoJSON();
      this.jsonStr = format.writeFeatures(this.vectorLayerSource.getFeatures())
    },

    set_GeoJSON_toMap() {
      let jsonData = JSON.parse(this.jsonStr)
      this.vectorLayerSource = new SourceVector({
        format: new GeoJSON(),
        features: new GeoJSON().readFeatures(jsonData),
      })
      this.vectorLayer.setSource(this.vectorLayerSource)
    },

    addSelectInteraction() {
      let selectInteraction = new Select({
        layers: [this.vectorLayer],
        style: (feature => {
          return this.getFeatureStyle(feature, true)
        })
      });

      // 监听select交互的select事件
      selectInteraction.on('select', (event) => {
        let selectedFeatures = event.selected;
        // 输出选中的要素
        selectedFeatures.forEach((feature) => {
          console.log("Selected Features: ", feature);
          this.activeFeature = feature;
        });

        if (selectedFeatures.length === 0) {
          this.activeFeature = null
        }
      });


      this.selectInteraction = selectInteraction
      this.map.addInteraction(selectInteraction)
    },
    addTranslateInteraction() {
      let translateInteraction = new Translate({
        features: this.selectInteraction.getFeatures()
      })
      this.translateInteraction = translateInteraction
      this.map.addInteraction(translateInteraction);
    },

    getUuid() {
      return md5(Math.random() + (new Date()).toString());
    },

    onDel() {
      let selectedFeatures = this.selectInteraction.getFeatures();
      if (selectedFeatures.getLength() > 0) {
        this.vectorLayer.getSource().removeFeature(selectedFeatures.item(0));
        selectedFeatures.clear();
        this.activeFeature = null
      }
    },

    getFeatureStyle(feature, active) {
      // 通过 feature 的几何类型设置不同的样式
      let geometryType = feature.getGeometry().getType();

      let color = feature.getProperties()?.color || '#00f'

      let activeColor = '#f00'

      let style;
      if (geometryType === 'Point') {
        style = new Style({
          image: new Circle({
            radius: 5,
            fill: new Fill({
              color: color
            }),
            stroke: new Stroke({
              color: active ? activeColor : color,
              width: 2
            })
          })
        });
      } else if (geometryType === 'LineString') {
        style = [new Style({
          stroke: new Stroke({
            color: active ? activeColor : color,
            width: 8
          })
        }), new Style({
          stroke: new Stroke({
            color: color,
            width: 4
          })
        })];
      } else if (geometryType === 'Polygon') {
        style = new Style({
          fill: new Fill({
            color: color
          }),
          stroke: new Stroke({
            color: color,
            width: 2
          })
        });
      }

      return style;
    },


    getActiveFeatureProperties() {

      if (this.activeFeature && this.activeFeature.getProperties) {
        let {geometry: _, ...rest} = this.activeFeature.getProperties()
        this.featurePropertiesStr = JSON.stringify(rest)
      }
    },
    setActiveFeatureProperties() {
      let data = null

      try {
        data = JSON.parse(this.featurePropertiesStr)
      } catch (e) {
        data = null
      }

      if (data) {
        this.activeFeature.setProperties(data)
      }
    }
  },

}
</script>
<style scoped>
.container {
  width: 840px;
  margin: 50px auto;
  border: 1px solid #42B983;
}

#vue-openlayers {
  width: 100%;
  height: 400px;
  border: 1px solid #42B983;
  position: relative;
}

textarea {
  width: 100%;
  height: 80px;
}
</style>

上一篇下一篇

猜你喜欢

热点阅读