二十四、openlayers官网示例Custom Interactions——自定义交互实现在地图上移动、拖拽feature

官网demo地址:

Custom Interactions

这个示例介绍了如何在地图上自定义一个交互实现在地图上拖拽、移动要素。

首先是加载了三个要素到地图上,一个点、一个多边形、一条线。

const pointFeature = new Feature(new Point([0, 0]));

      const lineFeature = new Feature(
        new LineString([
          [-1e7, 1e6],
          [-1e6, 3e6],
        ])
      );

      const polygonFeature = new Feature(
        new Polygon([
          [
            [-3e6, -1e6],
            [-3e6, 1e6],
            [-1e6, 1e6],
            [-1e6, -1e6],
            [-3e6, -1e6],
          ],
        ])
      );

  new VectorLayer({
       source: new VectorSource({
          features: [pointFeature, lineFeature, polygonFeature],
        }),
        style: {
          "icon-src": "data/icon.png",
          "icon-opacity": 0.95,
          "icon-anchor": [0.5, 46], //设置图标锚点的位置  
          "icon-anchor-x-units": "fraction", //指定锚点的水平单位是比例值
          "icon-anchor-y-units": "pixels", //指定锚点的垂直单位是像素值
          "stroke-width": 3,
          "stroke-color": [255, 0, 0, 1],
          "fill-color": [0, 0, 255, 0.6],
        },
    }),

然后创建了一个类继承原本的PointerInteraction,将四个事件作为参数传递给PointerInteraction。来处理事件逻辑。

class Drag extends PointerInteraction {
    constructor() {
        super({
            handleDownEvent: handleDownEvent, //按下事件
            handleDragEvent: handleDragEvent, //拖动事件
            handleMoveEvent: handleMoveEvent, //移动事件
            handleUpEvent: handleUpEvent, //释放事件
        });
        //存储鼠标点击时的坐标
        this.coordinate_ = null;

        //用于存储鼠标悬停在要素上时的光标样式
        this.cursor_ = "pointer";

        //存储被拖拽的要素  
        this.feature_ = null;

        //存储之前的光标样式,以便恢复
        this.previousCursor_ = undefined;
    }


}

可以看下源码中PointerInteraction的定义。

这里移动要素用了一个geometry.translate()方法,如果我们自己写方法来完成移动的话会比较麻烦。

/**
* @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event.
*/
function handleDragEvent(evt) {
    //计算鼠标拖动的位移
    const deltaX = evt.coordinate[0] - this.coordinate_[0];
    const deltaY = evt.coordinate[1] - this.coordinate_[1];
    //平移被拖拽要素的几何图形
    const geometry = this.feature_.getGeometry();
    geometry.translate(deltaX, deltaY);
    //更新存储的坐标为当前鼠标的位置
    this.coordinate_[0] = evt.coordinate[0];
    this.coordinate_[1] = evt.coordinate[1];
}

重新定义了一个Drag类,我放在了utils下的Drag.js中便于多次使用。

import Drag from '@/utils/Drag'
const map = new Map({
     interactions: defaultInteractions().extend([new Drag()]),
})

完整代码:

utils/Drag.js:

import {
    Pointer as PointerInteraction,
} from "ol/interaction.js";
class Drag extends PointerInteraction {
    constructor() {
        super({
            handleDownEvent: handleDownEvent, //按下事件
            handleDragEvent: handleDragEvent, //拖动事件
            handleMoveEvent: handleMoveEvent, //移动事件
            handleUpEvent: handleUpEvent, //释放事件
        });
        //存储鼠标点击时的坐标
        this.coordinate_ = null;

        //用于存储鼠标悬停在要素上时的光标样式
        this.cursor_ = "pointer";

        //存储被拖拽的要素  
        this.feature_ = null;

        //存储之前的光标样式,以便恢复
        this.previousCursor_ = undefined;
    }


}

/**
         * @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event.
         * @return {boolean} `true` to start the drag sequence.
         */

function handleDownEvent(evt) {
    const map = evt.map;
    // 在地图上检测鼠标点击的位置是否有要素,如果有,则存储要素和点击位置的坐标
    const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
        return feature;
    });

    if (feature) {
        this.coordinate_ = evt.coordinate;
        this.feature_ = feature;
    }

    return !!feature;
}
/**
* @param {import("../src/ol/MapBrowserEvent.js").default} evt Map browser event.
*/
function handleDragEvent(evt) {
    //计算鼠标拖动的位移
    const deltaX = evt.coordinate[0] - this.coordinate_[0];
    const deltaY = evt.coordinate[1] - this.coordinate_[1];
    //平移被拖拽要素的几何图形
    const geometry = this.feature_.getGeometry();
    geometry.translate(deltaX, deltaY);
    //更新存储的坐标为当前鼠标的位置
    this.coordinate_[0] = evt.coordinate[0];
    this.coordinate_[1] = evt.coordinate[1];
}
/**
 * @param {import("../src/ol/MapBrowserEvent.js").default} evt Event.
 */
function handleMoveEvent(evt) {
    if (this.cursor_) {
        const map = evt.map;
        const feature = map.forEachFeatureAtPixel(
            evt.pixel,
            function (feature) {
                return feature;
            }
        );
        //检测鼠标移动到的要素,如果有要素则改变光标样式。
        const element = evt.map.getTargetElement();
        if (feature) {
            if (element.style.cursor != this.cursor_) {
                this.previousCursor_ = element.style.cursor;
                element.style.cursor = this.cursor_;
            }
            //如果鼠标移出要素,则恢复之前的光标样式
        } else if (this.previousCursor_ !== undefined) {
            element.style.cursor = this.previousCursor_;
            this.previousCursor_ = undefined;
        }
    }
}
/**
 * @return {boolean} `false` to stop the drag sequence.
 */
//重置存储的坐标和要素,表示拖拽序列结束
function handleUpEvent() {
    this.coordinate_ = null;
    this.feature_ = null;
    return false;
}
export default Drag

.vue文件:

<template>
  <div class="box">
    <h1>自定义工具</h1>
    <div id="map"></div>
  </div>
</template>

<script>
import Feature from "ol/Feature.js";
import Map from "ol/Map.js";
import View from "ol/View.js";
import { LineString, Point, Polygon } from "ol/geom.js";
import { OGCMapTile, Vector as VectorSource } from "ol/source.js";
import {
    defaults as defaultInteractions,
} from "ol/interaction.js";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
import Drag from '@/utils/Drag'
export default {
  name: "",
  components: {},
  data() {
    return {
      map: null,
    };
  },
  computed: {},
  created() {},
  mounted() {
    this.addfeatureToMap();
  },
  methods: {
    addfeatureToMap() {
      const pointFeature = new Feature(new Point([0, 0]));

      const lineFeature = new Feature(
        new LineString([
          [-1e7, 1e6],
          [-1e6, 3e6],
        ])
      );

      const polygonFeature = new Feature(
        new Polygon([
          [
            [-3e6, -1e6],
            [-3e6, 1e6],
            [-1e6, 1e6],
            [-1e6, -1e6],
            [-3e6, -1e6],
          ],
        ])
      );
      const map = new Map({
        interactions: defaultInteractions().extend([new Drag()]),
        layers: [
          new TileLayer({
            source: new OGCMapTile({
              url: "https://maps.gnosis.earth/ogcapi/collections/NaturalEarth:raster:HYP_HR_SR_OB_DR/map/tiles/WebMercatorQuad",
              crossOrigin: "",
            }),
          }),
          new VectorLayer({
            source: new VectorSource({
              features: [pointFeature, lineFeature, polygonFeature],
            }),
            style: {
              "icon-src": "data/icon.png",
              "icon-opacity": 0.95,
              "icon-anchor": [0.5, 46], //设置图标锚点的位置  
              "icon-anchor-x-units": "fraction", //指定锚点的水平单位是比例值
              "icon-anchor-y-units": "pixels", //指定锚点的垂直单位是像素值
              "stroke-width": 3,
              "stroke-color": [255, 0, 0, 1],
              "fill-color": [0, 0, 255, 0.6],
            },
          }),
        ],
        target: "map",
        view: new View({
          center: [0, 0],
          zoom: 2,
        }),
      });
    },
  },
};
</script>

<style lang="scss" scoped>
#map {
  width: 100%;
  height: 500px;
}
.box {
  height: 100%;
}

#info {
  width: 100%;
  height: 24rem;
  overflow: scroll;
  display: flex;
  align-items: baseline;
  border: 1px solid black;
  justify-content: flex-start;
}
</style>
相关推荐
f89790707025 分钟前
layui动态表格出现 横竖间隔线
前端·javascript·layui
鱼跃鹰飞31 分钟前
Leecode热题100-295.数据流中的中位数
java·服务器·开发语言·前端·算法·leetcode·面试
二十雨辰1 小时前
[uni-app]小兔鲜-04推荐+分类+详情
前端·javascript·uni-app
霸王蟹2 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习
小白求学12 小时前
CSS计数器
前端·css
Anita_Sun2 小时前
🌈 Git 全攻略 - Git 的初始设置 ✨
前端
lucifer3112 小时前
深入解析 React 组件封装 —— 从业务需求到性能优化
前端·react.js
等什么君!2 小时前
复习HTML(进阶)
前端·html
儒雅的烤地瓜2 小时前
JS | 如何解决ajax无法后退的问题?
前端·javascript·ajax·pushstate·popstate事件·replacestate
觉醒法师2 小时前
Vue3+TS项目 - ref和useTemplateRef获取组件实例
开发语言·前端·javascript