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

发布于:2024-05-23 ⋅ 阅读:(30) ⋅ 点赞:(0)

官网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>