-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathMap.vue
More file actions
268 lines (242 loc) · 8.2 KB
/
Map.vue
File metadata and controls
268 lines (242 loc) · 8.2 KB
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
<template></template>
<script>
import Vue from 'vue';
import Map from 'ol/Map'
import View from 'ol/View'
import Attribution from 'ol/control/Attribution';
import Zoom from 'ol/control/Zoom';
import SelectInteraction from 'ol/interaction/Select';
import {defaults as defaultInteractions} from 'ol/interaction';
import RotateControl from 'ol/control/Rotate';
import Projection from 'ol/proj/Projection';
import {register as olproj4} from 'ol/proj/proj4';
import proj4 from 'proj4'
import Overlay from 'ol/Overlay';
// import the app-wide EventBus
import { WguEventBus } from '../../WguEventBus.js';
import { LayerFactory } from '../../factory/Layer.js';
import ColorUtil from '../../util/Color';
export default {
name: 'wgu-map',
props: {
color: {type: String, required: false, default: 'red darken-3'},
collapsibleAttribution: {type: Boolean, default: false},
rotateableMap: {type: Boolean, required: false, default: false}
},
data () {
return {
zoom: this.$appConfig.mapZoom,
center: this.$appConfig.mapCenter,
projection: this.$appConfig.mapProjection,
projectionDefs: this.$appConfig.projectionDefs
}
},
mounted () {
var me = this;
// Make the OL map accessible for Mapable mixin even 'ol-map-mounted' has
// already been fired. Don not use directly in cmps, use Mapable instead.
Vue.prototype.$map = me.map;
// Send the event 'ol-map-mounted' with the OL map as payload
WguEventBus.$emit('ol-map-mounted', me.map);
// resize the map, so it fits to parent
window.setTimeout(() => {
me.map.setTarget(document.getElementById('ol-map-container'));
me.map.updateSize();
// adjust the bg color of the OL buttons (like zoom, rotate north, ...)
me.setOlButtonColor();
// initialize map hover functionality
me.setupMapHover();
}, 200);
},
created () {
var me = this;
// make map rotateable according to property
const interactions = defaultInteractions({
altShiftDragRotate: me.rotateableMap,
pinchRotate: me.rotateableMap
});
let controls = [
new Zoom(),
new Attribution({
collapsible: me.collapsibleAttribution
})
];
// add a button control to reset rotation to 0, if map is rotateable
if (me.rotateableMap) {
controls.push(new RotateControl());
}
// Optional projection (EPSG) definitions for Proj4
if (me.projectionDefs) {
// Add all (array of array)
proj4.defs(me.projectionDefs);
// Register with OpenLayers
olproj4(proj4);
}
// Projection for Map, default is Web Mercator
if (!me.projection) {
me.projection = {code: 'EPSG:3857', units: 'm'}
}
const projection = new Projection(me.projection);
me.map = new Map({
layers: [],
controls: controls,
interactions: interactions,
view: new View({
center: me.center || [0, 0],
zoom: me.zoom,
projection: projection
})
});
// create layers from config and add them to map
const layers = me.createLayers();
me.map.getLayers().extend(layers);
},
methods: {
/**
* Creates the OL layers due to the "mapLayers" array in app config.
* @return {ol.layer.Base[]} Array of OL layer instances
*/
createLayers () {
const me = this;
let layers = [];
const appConfig = this.$appConfig;
const mapLayersConfig = appConfig.mapLayers || [];
mapLayersConfig.reverse().forEach(function (lConf) {
let layer = LayerFactory.getInstance(lConf);
layers.push(layer);
// if layer is selectable register a select interaction
if (lConf.selectable) {
const selectClick = new SelectInteraction({
layers: [layer],
style: layer.get('styleSelected') || undefined
});
// forward an event if feature selection changes
selectClick.on('select', function (evt) {
// TODO use identifier for layer (once its implemented)
WguEventBus.$emit(
'map-selectionchange',
layer.get('lid'),
evt.selected,
evt.deselected
);
});
// register/activate interaction on map
me.map.addInteraction(selectClick);
}
});
return layers;
},
/**
* Sets the background color of the OL buttons to the color property.
*/
setOlButtonColor () {
var me = this;
if (ColorUtil.isCssColor(me.color)) {
// directly apply the given CSS color
if (document.querySelector('.ol-zoom')) {
document.querySelector('.ol-zoom .ol-zoom-in').style.backgroundColor = me.color;
document.querySelector('.ol-zoom .ol-zoom-out').style.backgroundColor = me.color;
}
if (document.querySelector('.ol-rotate')) {
document.querySelector('.ol-rotate .ol-rotate-reset').style.backgroundColor = me.color;
}
} else {
// apply vuetify color by transforming the color to the corresponding
// CSS class (see https://vuetifyjs.com/en/framework/colors)
const [colorName, colorModifier] = me.color.toString().trim().split(' ', 2);
if (document.querySelector('.ol-zoom')) {
document.querySelector('.ol-zoom .ol-zoom-in').classList.add(colorName);
document.querySelector('.ol-zoom .ol-zoom-in').classList.add(colorModifier);
document.querySelector('.ol-zoom .ol-zoom-out').classList.add(colorName);
document.querySelector('.ol-zoom .ol-zoom-out').classList.add(colorModifier);
}
if (document.querySelector('.ol-rotate')) {
document.querySelector('.ol-rotate .ol-rotate-reset').classList.add(colorName);
document.querySelector('.ol-rotate .ol-rotate-reset').classList.add(colorModifier);
}
}
},
/**
* Initializes the map hover functionality:
* Adds a little tooltip like DOM element, wrapped as OL Overlay to the
* map.
* Registers a 'pointermove' event on the map and shows the layer's
* 'hoverAttribute' if the layer is configured as 'hoverable'
*/
setupMapHover () {
const me = this;
const map = me.map;
let overlayEl;
// create a span to show map tooltip
overlayEl = document.createElement('span');
overlayEl.classList.add('wgu-hover-tooltiptext');
map.getTarget().append(overlayEl);
me.overlayEl = overlayEl;
// wrap the tooltip span in a OL overlay and add it to map
me.overlay = new Overlay({
element: overlayEl,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
map.addOverlay(me.overlay);
// show tooltip if a hoverable feature gets hit with the mouse
map.on('pointermove', me.onPointerMove, me);
},
/**
* Shows the hover tooltip on the map if an appropriate feature of a
* 'hoverable' layer was hit with the mouse.
*
* @param {Object} event The OL event for pointermove
*/
onPointerMove (event) {
const me = this;
const map = me.map;
const overlayEl = me.overlayEl;
let hoverAttr;
const features = map.getFeaturesAtPixel(event.pixel, {layerFilter: (layer) => {
if (layer.get('hoverable')) {
hoverAttr = layer.get('hoverAttribute');
}
return layer.get('hoverable');
}});
if (!features || features.length === 0 || !hoverAttr) {
hoverAttr = null;
overlayEl.innerHTML = null;
me.overlay.setPosition(undefined);
return;
}
const feature = features[0];
var attr = feature.get(hoverAttr);
overlayEl.innerHTML = attr;
me.overlay.setPosition(event.coordinate);
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
div.ol-zoom {
top: auto;
left: auto;
bottom: 3em;
right: 0.5em;
}
div.ol-attribution.ol-uncollapsible {
bottom: 12px;
font-size: 10px;
}
/* Hover tooltip */
.wgu-hover-tooltiptext {
width: 120px;
background-color: rgba(211, 211, 211, .9);
color: #222;
text-align: center;
padding: 5px;
border-radius: 6px;
/* Position the hover tooltip */
position: absolute;
z-index: 1;
}
</style>