vue2+Ts中openLayer绘图工具组件封装

vue2+Ts中openLayer绘图工具组件封装

效果:
在这里插入图片描述
封装组件代码:

<!-- openLayer绘图工具 -->
<template>
  <a-button-group v-show="isShow">
    <a-button v-if="shouldShowButton('point')" @click="draw('Point')">
      绘点
      <a-icon type="dot-chart" />
    </a-button>
    <a-button v-if="shouldShowButton('line')" @click="draw('LineString')">
      绘线
      <a-icon type="line-chart" />
    </a-button>
    <a-button v-if="shouldShowButton('polygon')" @click="draw('Polygon')">
      绘面
      <a-icon type="border" />
    </a-button>
    <a-button v-if="shouldShowButton('edit')" @click="edit()">
      编辑
      <a-icon type="edit" />
    </a-button>
    <a-button v-if="shouldShowButton('undo')" @click="undo()">
      撤销
      <a-icon type="undo" />
    </a-button>
    <a-button v-if="shouldShowButton('redo')" @click="redo()">
      重做
      <a-icon type="redo" />
    </a-button>
    <a-button v-if="shouldShowButton('save')" @click="save()">
      保存
      <a-icon type="save" />
    </a-button>
  </a-button-group>
</template>

<script lang="ts">
import abpbase from '@/libs/abpbase';
import VectorSource from 'ol/source/Vector';
import Map from 'ol/Map';
import { Component, Emit, Prop } from 'vue-property-decorator';
import ol from 'ol';
import VectorLayer from 'ol/layer/Vector';
import Draw, { createRegularPolygon } from 'ol/interaction/Draw';
import Modify from 'ol/interaction/Modify';
import {
 singleClick, doubleClick, pointerMove, never,
} from 'ol/events/condition';
import Select from 'ol/interaction/Select';
import Translate from 'ol/interaction/Translate';
import Snap from 'ol/interaction/Snap';
// eslint-disable-next-line import/no-unresolved
import * as jsts_io from 'jsts/org/locationtech/jts/io';
import {
 Style, Fill, Stroke, Circle,
} from 'ol/style';
import {
  LinearRing,
  LineString,
  MultiLineString,
  MultiPoint,
  MultiPolygon,
  Point,
  Polygon,
} from 'ol/geom.js';
import MapBrowserEventType from 'ol/MapBrowserEventType';

@Component({
  name: 'OpenLayerDrawTool',
  components: {
  },
})
export default class OpenLayerDrawTool extends abpbase {
  /**
   * 最大可绘制要素数量
   */
  @Prop({type:Number, default:1})
  maxFeatures

  @Prop({ type: Array, default: () => ["point", "line", "polygon", "undo", "redo", "save", "edit"] })
  buttonsToShow: string[];

  /**
   * 编辑操作
   */
  editOperation: Modify;

  shouldShowButton(buttonName: string): boolean {
    return this.buttonsToShow.includes(buttonName);
  }

  /**
   * 绘制的矢量图层
   */
  drawVectorLayer: VectorLayer<any>;

  /**
   * 绘制的数据源
   */
  drawSource: VectorSource;

  /**
   * 传入的openLayer地图
   */
  map: Map = null;

  /**
   * 绘制操作
   */
  drawOperation: Draw;

  /**
   * 绘制的图形堆栈
   */
  drawStack = []

  /**
   * 重做的图形堆栈
   */
  redoStack = []

  selectOperation: Select

  translateOperation: Translate

  snapOperation: Snap

  get isShow() {
    return this.map != null;
  }

  /**
   * 初始化地图控件,需要在父组件调用;
   * @param map openLayer地图对象
   * @param requestDataId 请求的数据参数
   */
  initCtrl(map: Map) {
    this.map = map;
    this.drawSource = new VectorSource();

    const createCustomStyle = () => (feature) => {
        const geometryType = feature.getGeometry().getType();
        let style;
        switch (geometryType) {
          case 'Point':
            style = new Style({
              image: new Circle({
                radius: 6,
                fill: new Fill({ color: 'rgba(255, 0, 0, 0.5)' }),
                stroke: new Stroke({ color: 'red', width: 2 }),
              }),
            });
            break;
          case 'LineString':
            style = new Style({
              stroke: new Stroke({
                color: 'blue',
                width: 4,
              }),
            });
            break;
          case 'Polygon':
            style = new Style({
              fill: new Fill({ color: 'rgba(0, 255, 0, 0.2)' }),
              stroke: new Stroke({ color: 'green', width: 3 }),
            });
            break;
          default: {
            break;
          }
        }

        return style;
      };

    this.drawVectorLayer = new VectorLayer<any>({
      source: this.drawSource,
      style: createCustomStyle(),
      zIndex: 999,
    });
    this.map.addLayer(this.drawVectorLayer);
    this.$forceUpdate();
  }

  draw(type) {
    this.map.removeInteraction(this.drawOperation);
    this.drawOperation = new Draw({
      source: this.drawSource,
      type,
      condition: (event) => event.type === MapBrowserEventType.POINTERDOWN && event.originalEvent.button === 0,
    });
    this.map.addInteraction(this.drawOperation);

    this.drawOperation.on('drawend', (e) => {
      // 为要素分配一个唯一的 ID
      e.feature.set('id', Date.now());

      this.drawStack.push(e.feature);
      // 如果绘制的图形数量超过最大限制,移除最早添加的图形
      if (this.drawStack.length > this.maxFeatures) {
        const firstFeature = this.drawStack.shift();
        this.drawSource.removeFeature(firstFeature);
      }
      this.map.removeInteraction(this.drawOperation);
    });
  }

  undo() {
    const lastFeature = this.drawStack.pop();
    if (lastFeature) {
      this.drawSource.removeFeature(lastFeature);
      this.redoStack.push(lastFeature);
    }
  }

  redo() {
    const lastFeature = this.redoStack.pop();
    if (lastFeature) {
      // 如果绘制的图形数量达到最大限制,移除最早添加的图形并将其从重做堆栈中移除
      if (this.drawStack.length >= this.maxFeatures) {
        const firstFeature = this.drawStack.shift();
        this.drawSource.removeFeature(firstFeature);
      }
      this.drawSource.addFeature(lastFeature);
      this.drawStack.push(lastFeature);
    }
  }

  save() {
    const parser = new jsts_io.OL3Parser();
    parser.inject(
        Point,
        LineString,
        LinearRing,
        Polygon,
        MultiPoint,
        MultiLineString,
        MultiPolygon,
    );

    const format = new jsts_io.WKTWriter();
    const features = this.drawSource.getFeatures();
    const wkts = features.map((feature) => {
      const olGeom = feature.getGeometry();
      const jstsGeom = parser.read(olGeom);
      return format.write(jstsGeom);
    });
    console.log(JSON.stringify(wkts));
  }

  mounted() {

  }

  edit() {
    // 移除 drawOperation 交互
    this.map.removeInteraction(this.drawOperation);

    // // 创建 selectOperation 交互对象
    this.selectOperation = new Select({
      condition: singleClick,
    });

    this.map.addInteraction(this.selectOperation);

    // 创建 translateOperation 交互对象
    this.translateOperation = new Translate({
      features: this.selectOperation.getFeatures(),
    });

    this.map.addInteraction(this.translateOperation);

    // 创建 modifyOperation 交互对象
    this.editOperation = new Modify({
      features: this.selectOperation.getFeatures(),
    });
    this.editOperation.setActive(false);

    this.map.addInteraction(this.editOperation);

    this.editOperation.on('modifyend', (e) => {
      // 更新 drawStack 中的要素
      const updatedFeature = e.features.getArray()[0];
      const featureIndex = this.drawStack.findIndex(
          (feature) => feature.get('id') === updatedFeature.get('id'),
      );
      if (featureIndex >= 0) {
        this.drawStack.splice(featureIndex, 1, updatedFeature);
      }
    });

    // 为地图添加双击事件侦听器
    this.map.on('dblclick', (event) => {
      const features = this.map.getFeaturesAtPixel(event.pixel);
      if (features && features.length > 0) {
        this.editOperation.setActive(true);
        this.snapOperation.setActive(true);
        this.translateOperation.setActive(false);
      } else {
        this.editOperation.setActive(false);
        this.snapOperation.setActive(false);
        this.translateOperation.setActive(true);
      }
    });

    // 为地图添加 pointermove 事件侦听器
    // this.map.on('pointermove', (event) => {
    //   const features = this.map.getFeaturesAtPixel(event.pixel);
    //   if (features && features.length > 0) {
    //     this.editOperation.setActive(true);
    //   } else {
    //     this.editOperation.setActive(false);
    //   }
    // });
  }

  // 初始化
  // init() {
  // }

  // created() {
  // }
}
</script>

<style lang="less" scoped>
.home-wrap {
  min-width: 1280px;
  overflow: auto;
}
</style>

父组件使用:

<div class="absolute right-4 top-4">
   <open-layer-draw-tool ref="drawTool"></open-layer-draw-tool>
</div>

initDrawTool() {
     this.$nextTick(() => {
       (this.$refs.drawTool as any).initCtrl(this.map);
     });
  }
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你可以尝试以下步骤来封装一个Vue 3和TypeScript下使用Element Plus的表单提交组件: 1. 安装必要的依赖: - Vue 3:`npm install vue@next` - TypeScript:`npm install -D typescript` - Element Plus:`npm install element-plus` 2. 创建一个新的Vue组件,并为其选择一个合适的名称,例如`FormSubmit.vue`。 3. 在`FormSubmit.vue`文件,导入必要的模块和样式: ```vue <template> <!-- 表单内容 --> </template> <script lang="ts"> import { defineComponent } from 'vue'; import { ElButton, ElForm, ElFormItem } from 'element-plus'; export default defineComponent({ components: { ElButton, ElForm, ElFormItem, }, }); </script> <style scoped> /* Element Plus 样式 */ @import 'element-plus/packages/theme-chalk/src/index.scss'; /* 自定义样式 */ /* ... */ </style> ``` 4. 在模板编写表单内容,并使用Element Plus的组件来构建表单: ```vue <template> <el-form ref="form" :model="formData" label-width="120px"> <el-form-item label="姓名" prop="name"> <el-input v-model="formData.name"></el-input> </el-form-item> <!-- 更多表单项 --> <el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form-item> </el-form> </template> <script lang="ts"> // ... export default defineComponent({ // ... data() { return { formData: { name: '', // 更多表单字段 } }; }, methods: { submitForm() { // 表单提交逻辑 if (this.$refs.form.validate()) { // 表单验证通过,执行提交操作 // ... } } } }); </script> ``` 这样,你就可以使用封装好的表单提交组件来方便地处理表单提交了。你可以根据实际需求添加更多的表单项,并在`submitForm`方法实现你的提交逻辑。希望这可以帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星月前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值