UNPKG

4.15 kBJavaScriptView Raw
1import {Map} from '../Map';
2import {Handler} from '../../core/Handler';
3import {on, off, stop} from '../../dom/DomEvent';
4import {toPoint} from '../../geometry/Point';
5
6
7/*
8 * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
9 */
10
11// @namespace Map
12// @section Keyboard Navigation Options
13Map.mergeOptions({
14 // @option keyboard: Boolean = true
15 // Makes the map focusable and allows users to navigate the map with keyboard
16 // arrows and `+`/`-` keys.
17 keyboard: true,
18
19 // @option keyboardPanDelta: Number = 80
20 // Amount of pixels to pan when pressing an arrow key.
21 keyboardPanDelta: 80
22});
23
24export var Keyboard = Handler.extend({
25
26 keyCodes: {
27 left: [37],
28 right: [39],
29 down: [40],
30 up: [38],
31 zoomIn: [187, 107, 61, 171],
32 zoomOut: [189, 109, 54, 173]
33 },
34
35 initialize: function (map) {
36 this._map = map;
37
38 this._setPanDelta(map.options.keyboardPanDelta);
39 this._setZoomDelta(map.options.zoomDelta);
40 },
41
42 addHooks: function () {
43 var container = this._map._container;
44
45 // make the container focusable by tabbing
46 if (container.tabIndex <= 0) {
47 container.tabIndex = '0';
48 }
49
50 on(container, {
51 focus: this._onFocus,
52 blur: this._onBlur,
53 mousedown: this._onMouseDown
54 }, this);
55
56 this._map.on({
57 focus: this._addHooks,
58 blur: this._removeHooks
59 }, this);
60 },
61
62 removeHooks: function () {
63 this._removeHooks();
64
65 off(this._map._container, {
66 focus: this._onFocus,
67 blur: this._onBlur,
68 mousedown: this._onMouseDown
69 }, this);
70
71 this._map.off({
72 focus: this._addHooks,
73 blur: this._removeHooks
74 }, this);
75 },
76
77 _onMouseDown: function () {
78 if (this._focused) { return; }
79
80 var body = document.body,
81 docEl = document.documentElement,
82 top = body.scrollTop || docEl.scrollTop,
83 left = body.scrollLeft || docEl.scrollLeft;
84
85 this._map._container.focus();
86
87 window.scrollTo(left, top);
88 },
89
90 _onFocus: function () {
91 this._focused = true;
92 this._map.fire('focus');
93 },
94
95 _onBlur: function () {
96 this._focused = false;
97 this._map.fire('blur');
98 },
99
100 _setPanDelta: function (panDelta) {
101 var keys = this._panKeys = {},
102 codes = this.keyCodes,
103 i, len;
104
105 for (i = 0, len = codes.left.length; i < len; i++) {
106 keys[codes.left[i]] = [-1 * panDelta, 0];
107 }
108 for (i = 0, len = codes.right.length; i < len; i++) {
109 keys[codes.right[i]] = [panDelta, 0];
110 }
111 for (i = 0, len = codes.down.length; i < len; i++) {
112 keys[codes.down[i]] = [0, panDelta];
113 }
114 for (i = 0, len = codes.up.length; i < len; i++) {
115 keys[codes.up[i]] = [0, -1 * panDelta];
116 }
117 },
118
119 _setZoomDelta: function (zoomDelta) {
120 var keys = this._zoomKeys = {},
121 codes = this.keyCodes,
122 i, len;
123
124 for (i = 0, len = codes.zoomIn.length; i < len; i++) {
125 keys[codes.zoomIn[i]] = zoomDelta;
126 }
127 for (i = 0, len = codes.zoomOut.length; i < len; i++) {
128 keys[codes.zoomOut[i]] = -zoomDelta;
129 }
130 },
131
132 _addHooks: function () {
133 on(document, 'keydown', this._onKeyDown, this);
134 },
135
136 _removeHooks: function () {
137 off(document, 'keydown', this._onKeyDown, this);
138 },
139
140 _onKeyDown: function (e) {
141 if (e.altKey || e.ctrlKey || e.metaKey) { return; }
142
143 var key = e.keyCode,
144 map = this._map,
145 offset;
146
147 if (key in this._panKeys) {
148 if (!map._panAnim || !map._panAnim._inProgress) {
149 offset = this._panKeys[key];
150 if (e.shiftKey) {
151 offset = toPoint(offset).multiplyBy(3);
152 }
153
154 if (map.options.maxBounds) {
155 offset = map._limitOffset(toPoint(offset), map.options.maxBounds);
156 }
157
158 if (map.options.worldCopyJump) {
159 var newLatLng = map.wrapLatLng(map.unproject(map.project(map.getCenter()).add(offset)));
160 map.panTo(newLatLng);
161 } else {
162 map.panBy(offset);
163 }
164 }
165 } else if (key in this._zoomKeys) {
166 map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
167
168 } else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {
169 map.closePopup();
170
171 } else {
172 return;
173 }
174
175 stop(e);
176 }
177});
178
179// @section Handlers
180// @section Handlers
181// @property keyboard: Handler
182// Keyboard navigation handler.
183Map.addInitHook('addHandler', 'keyboard', Keyboard);