GeoJSON

作者: xueyueshuai | 来源:发表于2024-01-02 16:13 被阅读0次
    <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>
    
    

    相关文章

      网友评论

          本文标题:GeoJSON

          本文链接:https://www.haomeiwen.com/subject/sxnpndtx.html