官网demo地址:
这个示例介绍了如何在地图上自定义一个交互实现在地图上拖拽、移动要素。
首先是加载了三个要素到地图上,一个点、一个多边形、一条线。
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>