# 十一.Interactions(一)

前言

默认的交互功能,包含多个交互。规定了默认包含在地图中的功能,他们都是继承自 ol.interaction 类。 主要是最为常用的功能,如缩放、平移和旋转地图等。

功能点 说明
doubleclickzoom 双击地图进行缩放
draganddrop 以“拖文件到地图中”的交互添加图层
dragbox 拉框,用于划定一个矩形范围,常用于放大地图
dragpan 拖拽平移地图
dragrotateandzoom 拖拽方式进行缩放和旋转地图
dragrotate 拖拽方式旋转地图
draw 绘制地理要素功能
keyboardpan 键盘方式平移地图
keyboardzoom 键盘方式缩放地图
select 选择要素功能
modify 更改要素
mousewheelzoom 鼠标滚轮缩放功能
pinchrotate 手指旋转地图,针对触摸屏
pinchzoom 手指进行缩放,针对触摸屏
pointer 鼠标的用户自定义事件基类
snap 鼠标捕捉,当鼠标距离某个要素一定距离之内,自动吸附到要素

# 1.默认属性

默认的交互功能,包含多个交互。规定了默认包含在地图中的功能,他们都是继承自 ol.interaction 类

功能点 说明
鼠标拖拽旋转 DragRotate 鼠标拖拽旋转,一般配合一个键盘按键辅助
鼠标拖拽缩放 DragZoom 鼠标拖拽缩放,一般配合一个键盘按键辅助
鼠标/手指双击缩放 DoubleClickZoom 鼠标或手指双击缩放地图
手指旋转 PinchRotate 两个手指旋转地图,针对触摸屏
手指缩放 PinchZoom 两个手指缩放地图,针对触摸屏
鼠标/手指拖拽平移 DragPan 鼠标或手指拖拽平移地图
键盘 + / - 缩放 KeyboardZoom 使用键盘 + 和 - 按键进行缩放
方向键平移 KeyboardPan 使用键盘方向键平移地图
鼠标滚轮缩放 MouseWheelZoom 鼠标滚轮缩放地图
查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { OSM },
    } = ol
    new Map({
      view: new View({
        center: [12579156, 3274244],
        zoom: 12,
      }),
      layers: [
        new TileLayer({
          source: new OSM(),
        }),
      ],
      target: this.$refs.map,
    })
  },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 2.常见属性

# 2.1 综合案例

禁用功能点 说明
鼠标/手指双击缩放 DoubleClickZoom 鼠标或手指双击缩放地图
鼠标/手指拖拽平移 DragPan 鼠标或手指拖拽平移地图
键盘 + / - 缩放 KeyboardZoom 使用键盘 + 和 - 按键进行缩放
方向键平移 KeyboardPan 使用键盘方向键平移地图
鼠标滚轮缩放 MouseWheelZoom 鼠标滚轮缩放地图
查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      interaction: { defaults },
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { OSM },
      events: { condition: platformModifierKeyOnly },
    } = ol

    const map = new Map({
      interactions: defaults({
        mouseWheelZoom: false,
        doubleClickZoom: false,
        dragPan: false,
      }),
      layers: [
        new TileLayer({
          source: new OSM(),
        }),
      ],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 2,
      }),
    })
  },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 2.draganddrop

以“拖文件到地图中”的交互添加图层

# 3.dragbox

拉框,用于划定一个矩形范围,常用于放大地图

# 5.dragrotateandzoom

拖拽方式进行缩放和旋转地图

  • 全屏拖动、旋转和缩放

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { XYZ },
      control: { FullScreen, defaults: defaultControls },
      interaction: { DragRotateAndZoom, defaults: defaultInteractions },
    } = ol
    const attributions =
      '<a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> ' +
      '<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'

    const map = new Map({
      controls: defaultControls().extend([new FullScreen()]),
      interactions: defaultInteractions().extend([new DragRotateAndZoom()]),
      layers: [
        new TileLayer({
          source: new XYZ({
            attributions: attributions,
            url:
              "https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=" +
              mapkeys.maptiler,
            maxZoom: 20,
          }),
        }),
      ],
      target: this.$refs.map,
      view: new View({
        center: [-33519607, 5616436],
        rotation: -Math.PI / 8,
        zoom: 8,
      }),
    })
  },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 6.dragrotate

拖拽方式旋转地图

# 7.dragzoom

拖拽方式缩放地图

# 8.draw

绘制地理要素功能

查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <div class="row">
      <div class="col-auto">
        <span class="input-group">
          <label class="input-group-text" for="type">几何类型:</label>
          <select class="form-select" ref="type">
            <option value="Point"></option>
            <option value="LineString">直线</option>
            <option value="Polygon">多边形</option>
            <option value="Circle"></option>
            <option value="None"></option>
          </select>
          <input class="form-control" type="button" value="撤销" ref="undo" />
        </span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer, Vector: VectorLayer },
      source: { OSM, Vector: VectorSource },
      interaction: { Draw },
    } = ol;
    const raster = new TileLayer({
      source: new OSM(),
    });
    const source = new VectorSource({ wrapX: false });
    const vector = new VectorLayer({
      source: source,
    });
    const map = new Map({
      layers: [raster, vector],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 8,
      }),
    });
    const typeSelect = this.$refs.type;
    let draw;
    function addInteraction() {
      const value = typeSelect.value;
      if (value !== "None") {
        draw = new Draw({
          source: source,
          type: typeSelect.value,
        });
        map.addInteraction(draw);
      }
    }
    typeSelect.onchange = function () {
      map.removeInteraction(draw);
      addInteraction();
    };
    this.$refs.undo.addEventListener("click", function () {
      draw.removeLastPoint();
    });
    addInteraction();
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

# 9.keyboardpan

键盘方式平移地图

# 10.keyboardzoom

键盘方式缩放地图

# 11.select

选择要素功能

# 12.更改要素

功能点 说明
select 选择要素功能
modify 更改要素
查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      format: { GeoJSON },
      Map,
      View,
      layer: { Vector: VectorLayer },
      source: { Vector: VectorSource },
      interaction: { Modify, Select, defaults: defaultInteractions },
      style: Style,
      proj: { fromLonLat },
    } = ol
    const vector = new VectorLayer({
      background: "white",
      source: new VectorSource({
        url: "https://openlayers.org/data/vector/us-states.json",
        format: new GeoJSON(),
        wrapX: false,
      }),
    })
    const select = new Select({
      wrapX: false,
    })
    const modify = new Modify({
      features: select.getFeatures(),
    })
    const map = new Map({
      interactions: defaultInteractions().extend([select, modify]),
      layers: [vector],
      target: this.$refs.map,
      view: new View({
        center: fromLonLat([-100, 38.5]),
        zoom: 4,
      }),
    })
  },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 14.pinchrotate

手指旋转地图,针对触摸屏

# 15.手指缩放

功能点 说明
pinchzoom 手指进行缩放,针对触摸屏
查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      Map,
      View,
      layer: { Tile: TileLayer },
      source: { OSM },
      interaction: { PinchZoom, defaults: defaultInteractions },
    } = ol
    const map = new Map({
      interactions: defaultInteractions().extend([new PinchZoom()]),
      layers: [
        new TileLayer({
          source: new OSM(),
        }),
      ],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 2,
        constrainResolution: true,
      }),
    })
  },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 16.pointer

鼠标的用户自定义事件基类

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      Feature,
      geom: { LineString, Point, Polygon },
      Map,
      View,
      layer: { Tile: TileLayer, Vector: VectorLayer },
      source: { TileJSON, Vector: VectorSource },
      style: { Fill, Icon, Stroke, Style },
      interaction: {
        Pointer: PointerInteraction,
        defaults: defaultInteractions,
      },
    } = ol
    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
      }
    }
    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
    }
    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]
    }
    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
        }
      }
    }
    function handleUpEvent() {
      this.coordinate_ = null
      this.feature_ = null
      return false
    }
    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 TileJSON({
            url:
              "https://a.tiles.mapbox.com/v4/aj.1x1-degrees.json?secure&access_token=" +
              mapkeys.mapbox,
          }),
        }),
        new VectorLayer({
          source: new VectorSource({
            features: [pointFeature, lineFeature, polygonFeature],
          }),
          style: new Style({
            image: new Icon({
              anchor: [0.5, 46],
              anchorXUnits: "fraction",
              anchorYUnits: "pixels",
              opacity: 0.95,
              src: this.$withBase("/data/icon.png"),
            }),
            stroke: new Stroke({
              width: 3,
              color: [255, 0, 0, 1],
            }),
            fill: new Fill({
              color: [0, 0, 255, 0.6],
            }),
          }),
        }),
      ],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 2,
      }),
    })
  },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

# 17.自动吸附

功能点 说明
draw 绘制地理要素功能
select 选择要素功能
modify 更改要素
snap 鼠标捕捉,当鼠标距离某个要素一定距离之内,自动吸附到要素
查看代码详情
<template>
  <div>
    <div ref="map" class="map"></div>
    <form ref="optionsform" autocomplete="off">
      <div class="radio">
        <label>
          <input
            type="radio"
            name="interaction"
            value="draw"
            ref="draw"
            checked
          />
          编辑 &nbsp;
        </label>
        <select name="drawtype" ref="drawtype">
          <option value="Point"></option>
          <option value="LineString">直线</option>
          <option value="Polygon">多边形</option>
          <option value="Circle"></option>
        </select>
      </div>
      <div class="radio">
        <label>
          <input type="radio" name="interaction" value="modify" />
          查看 &nbsp;
        </label>
      </div>
    </form>
  </div>
</template>

<script>
export default {
  mounted() {
    let {
      interaction: { Draw, Modify, Select, Snap },
      Map,
      View,
      layer: { Tile: TileLayer, Vector: VectorLayer },
      source: { OSM, Vector: VectorSource },
      style: { Circle: CircleStyle, Fill, Stroke, Style },
    } = ol;

    const raster = new TileLayer({
      source: new OSM(),
    });

    const vector = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        fill: new Fill({
          color: "rgba(255, 255, 255, 0.2)",
        }),
        stroke: new Stroke({
          color: "#ffcc33",
          width: 2,
        }),
        image: new CircleStyle({
          radius: 7,
          fill: new Fill({
            color: "#ffcc33",
          }),
        }),
      }),
    });
    const map = new Map({
      layers: [raster, vector],
      target: this.$refs.map,
      view: new View({
        center: [12579156, 3274244],
        zoom: 3,
      }),
    });
    const ExampleModify = {
      init: function () {
        this.select = new Select();
        map.addInteraction(this.select);
        this.modify = new Modify({
          features: this.select.getFeatures(),
        });
        map.addInteraction(this.modify);
        this.setEvents();
      },
      setEvents: function () {
        const selectedFeatures = this.select.getFeatures();
        this.select.on("change:active", function () {
          selectedFeatures.forEach(function (each) {
            selectedFeatures.remove(each);
          });
        });
      },
      setActive: function (active) {
        this.select.setActive(active);
        this.modify.setActive(active);
      },
    };
    ExampleModify.init();
    const optionsForm = this.$refs.optionsform;
    const ExampleDraw = {
      init: function () {
        map.addInteraction(this.Point);
        this.Point.setActive(false);
        map.addInteraction(this.LineString);
        this.LineString.setActive(false);
        map.addInteraction(this.Polygon);
        this.Polygon.setActive(false);
        map.addInteraction(this.Circle);
        this.Circle.setActive(false);
      },
      Point: new Draw({
        source: vector.getSource(),
        type: "Point",
      }),
      LineString: new Draw({
        source: vector.getSource(),
        type: "LineString",
      }),
      Polygon: new Draw({
        source: vector.getSource(),
        type: "Polygon",
      }),
      Circle: new Draw({
        source: vector.getSource(),
        type: "Circle",
      }),
      activeDraw: null,
      setActive: function (active) {
        if (this.activeDraw) {
          this.activeDraw.setActive(false);
          this.activeDraw = null;
        }
        if (active) {
          const type = optionsForm.elements["drawtype"].value;
          this.activeDraw = this[type];
          this.activeDraw.setActive(true);
        }
      },
    };
    ExampleDraw.init();
    optionsForm.onchange = function (e) {
      const type = e.target.getAttribute("name");
      if (type == "draw-type") {
        ExampleModify.setActive(false);
        ExampleDraw.setActive(true);
        optionsForm.elements["interaction"].value = "draw";
      } else if (type == "interaction") {
        const interactionType = e.target.value;
        if (interactionType == "modify") {
          ExampleDraw.setActive(false);
          ExampleModify.setActive(true);
        } else if (interactionType == "draw") {
          ExampleDraw.setActive(true);
          ExampleModify.setActive(false);
        }
      }
    };
    ExampleDraw.setActive(true);
    ExampleModify.setActive(false);
    const snap = new Snap({
      source: vector.getSource(),
    });
    map.addInteraction(snap);
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

# 18.翻译功能

查看代码详情
<template>
  <div ref="map" class="map"></div>
</template>

<script>
export default {
  mounted() {
    let {
      format: { GeoJSON },
      Map,
      View,
      layer: { Vector: VectorLayer },
      source: { Vector: VectorSource },
      interaction: { Select, Translate, defaults: defaultInteractions },
      proj: { fromLonLat },
    } = ol
    const vector = new VectorLayer({
      background: "white",
      source: new VectorSource({
        url: "https://openlayers.org/data/vector/us-states.json",
        format: new GeoJSON(),
      }),
    })
    const select = new Select()
    const translate = new Translate({
      features: select.getFeatures(),
    })
    const map = new Map({
      interactions: defaultInteractions().extend([select, translate]),
      layers: [vector],
      target: this.$refs.map,
      view: new View({
        center: fromLonLat([-100, 38.5]),
        zoom: 4,
      }),
    })
  },
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38