comparison client/src/components/map/layers.js @ 3011:fc8fbea24568

client: moved map component, layer factory and styles to own subdirectory
author Markus Kottlaender <markus@intevation.de>
date Thu, 11 Apr 2019 12:14:01 +0200
parents
children 2e2a271c1026
comparison
equal deleted inserted replaced
3010:293bdd05ffcd 3011:fc8fbea24568
1 import TileWMS from "ol/source/TileWMS";
2 import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
3 import OSM from "ol/source/OSM";
4 import { Icon, Stroke, Style } from "ol/style";
5 import VectorSource from "ol/source/Vector";
6 import Point from "ol/geom/Point";
7 import { bbox as bboxStrategy } from "ol/loadingstrategy";
8 import { WFS, GeoJSON } from "ol/format";
9 import { equalTo } from "ol/format/filter";
10 import { HTTP } from "@/lib/http";
11 import styles from "./styles";
12
13 const buildVectorLoader = (
14 featureRequestOptions,
15 vectorSource,
16 bboxStrategyDisabled,
17 featurePostProcessor
18 ) => {
19 // build a function to be used for VectorSource.setLoader()
20 // make use of WFS().writeGetFeature to build the request
21 // and use our HTTP library to actually do it
22 // NOTE: the geometryName has to be given in featureRequestOptions if
23 // bboxStrategy (default) is used
24 featureRequestOptions.featureNS = "gemma";
25 featureRequestOptions.featurePrefix = "gemma";
26 featureRequestOptions.outputFormat = "application/json";
27 return (extent, resolution, projection) => {
28 if (!bboxStrategyDisabled) {
29 featureRequestOptions.bbox = extent;
30 }
31 featureRequestOptions.srsName = projection.getCode();
32 HTTP.post(
33 "/internal/wfs",
34 new XMLSerializer().serializeToString(
35 new WFS().writeGetFeature(featureRequestOptions)
36 ),
37 {
38 headers: {
39 "X-Gemma-Auth": localStorage.getItem("token"),
40 "Content-type": "text/xml; charset=UTF-8"
41 }
42 }
43 )
44 .then(response => {
45 const features = new GeoJSON().readFeatures(
46 JSON.stringify(response.data)
47 );
48 if (featurePostProcessor) {
49 features.map(f => featurePostProcessor(f));
50 }
51 vectorSource.addFeatures(features);
52 })
53 .catch(() => {
54 vectorSource.removeLoadedExtent(extent);
55 });
56 };
57 };
58
59 export default (function() {
60 return {
61 get(id) {
62 return this.config.find(l => l.get("id") === id);
63 },
64 config: [
65 new TileLayer({
66 id: "OPENSTREETMAP",
67 label: "Open Streetmap",
68 visible: true,
69 source: new OSM()
70 }),
71 new TileLayer({
72 id: "INLANDECDIS",
73 label: "Inland ECDIS chart Danube",
74 visible: true,
75 source: new TileWMS({
76 preload: 1,
77 url: "https://service.d4d-portal.info/wms/",
78 crossOrigin: "anonymous",
79 params: { LAYERS: "d4d", VERSION: "1.1.1", TILED: true }
80 })
81 }),
82 (function() {
83 const source = new VectorSource({ strategy: bboxStrategy });
84 source.setLoader(
85 buildVectorLoader(
86 {
87 featureTypes: ["waterway_area"],
88 geometryName: "area"
89 },
90 source
91 )
92 );
93 return new VectorLayer({
94 id: "WATERWAYAREA",
95 label: "Waterway Area",
96 visible: true,
97 style: new Style({
98 stroke: new Stroke({
99 color: "rgba(0, 102, 0, 1)",
100 width: 2
101 })
102 }),
103 source
104 });
105 })(),
106 (function() {
107 const source = new VectorSource({ strategy: bboxStrategy });
108 source.setLoader(
109 buildVectorLoader(
110 {
111 featureTypes: ["stretches_geoserver"],
112 geometryName: "area"
113 },
114 source,
115 f => {
116 if (f.getId() === this.selectedStretchId) {
117 f.set("highlighted", true);
118 }
119 return f;
120 }
121 )
122 );
123 return new VectorLayer({
124 id: "STRETCHES",
125 label: "Stretches",
126 visible: false,
127 style: styles.stretches,
128 source
129 });
130 })(),
131 (function() {
132 const source = new VectorSource();
133 source.setLoader(
134 buildVectorLoader(
135 {
136 featureTypes: ["fairway_dimensions"],
137 filter: equalTo("level_of_service", 1)
138 },
139 source,
140 true
141 )
142 );
143 return new VectorLayer({
144 id: "FAIRWAYDIMENSIONSLOS1",
145 label: "LOS 1 Fairway Dimensions",
146 visible: false,
147 style: styles.fwd1,
148 source
149 });
150 })(),
151 (function() {
152 const source = new VectorSource();
153 source.setLoader(
154 buildVectorLoader(
155 {
156 featureTypes: ["fairway_dimensions"],
157 filter: equalTo("level_of_service", 2)
158 },
159 source,
160 true
161 )
162 );
163 return new VectorLayer({
164 id: "FAIRWAYDIMENSIONSLOS2",
165 label: "LOS 2 Fairway Dimensions",
166 visible: false,
167 style: styles.fwd2,
168 source
169 });
170 })(),
171 (function() {
172 const source = new VectorSource();
173 source.setLoader(
174 buildVectorLoader(
175 {
176 featureTypes: ["fairway_dimensions"],
177 filter: equalTo("level_of_service", 3)
178 },
179 source,
180 true
181 )
182 );
183 return new VectorLayer({
184 id: "FAIRWAYDIMENSIONSLOS3",
185 label: "LOS 3 Fairway Dimensions",
186 visible: true,
187 style: styles.fwd3,
188 source
189 });
190 })(),
191 (function() {
192 const source = new VectorSource({ strategy: bboxStrategy });
193 source.setLoader(
194 buildVectorLoader(
195 {
196 featureTypes: ["waterway_axis"],
197 geometryName: "wtwaxs"
198 },
199 source
200 )
201 );
202 return new VectorLayer({
203 id: "WATERWAYAXIS",
204 label: "Waterway Axis",
205 visible: true,
206 style: new Style({
207 stroke: new Stroke({
208 color: "rgba(0, 0, 255, .5)",
209 lineDash: [5, 5],
210 width: 2
211 })
212 }),
213 // TODO: Set layer in layertree active/inactive depending on
214 // resolution.
215 maxResolution: 5,
216 minResolution: 0,
217 source
218 });
219 })(),
220 (function() {
221 const source = new VectorSource({ strategy: bboxStrategy });
222 source.setLoader(
223 buildVectorLoader(
224 {
225 featureTypes: ["waterway_profiles"],
226 geometryName: "geom"
227 },
228 source
229 )
230 );
231 return new VectorLayer({
232 id: "WATERWAYPROFILES",
233 label: "Waterway Profiles",
234 visible: true,
235 style: new Style({
236 stroke: new Stroke({
237 color: "rgba(0, 0, 255, .5)",
238 lineDash: [5, 5],
239 width: 2
240 })
241 }),
242 maxResolution: 2.5,
243 minResolution: 0,
244 source
245 });
246 })(),
247 (function() {
248 const source = new VectorSource({ strategy: bboxStrategy });
249 source.setLoader(
250 buildVectorLoader(
251 {
252 featureTypes: ["bottlenecks_geoserver"],
253 geometryName: "area"
254 },
255 source
256 )
257 );
258 return new VectorLayer({
259 id: "BOTTLENECKS",
260 label: "Bottlenecks",
261 visible: true,
262 style: styles.bottleneck,
263 source
264 });
265 })(),
266 new TileLayer({
267 id: "BOTTLENECKISOLINE",
268 label: "Bottleneck isolines",
269 visible: false,
270 source: new TileWMS({
271 preload: 0,
272 projection: "EPSG:3857",
273 url: window.location.origin + "/api/internal/wms",
274 params: {
275 LAYERS: "sounding_results_contour_lines_geoserver",
276 VERSION: "1.1.1",
277 TILED: true
278 },
279 tileLoadFunction: function(tile, src) {
280 // console.log("calling for", tile, src);
281 HTTP.get(src, {
282 headers: {
283 "X-Gemma-Auth": localStorage.getItem("token")
284 },
285 responseType: "blob"
286 }).then(response => {
287 tile.getImage().src = URL.createObjectURL(response.data);
288 });
289 } // TODO tile.setState(TileState.ERROR);
290 })
291 }),
292 new TileLayer({
293 id: "DIFFERENCES",
294 label: "Bottleneck Differences",
295 visible: false,
296 source: new TileWMS({
297 preload: 0,
298 projection: "EPSG:4326",
299 url: window.location.origin + "/api/internal/wms",
300 params: {
301 LAYERS: "sounding_differences",
302 VERSION: "1.1.1",
303 TILED: true
304 },
305 tileLoadFunction: function(tile, src) {
306 // console.log("calling for", tile, src);
307 HTTP.get(src, {
308 headers: {
309 "X-Gemma-Auth": localStorage.getItem("token")
310 },
311 responseType: "blob"
312 }).then(response => {
313 tile.getImage().src = URL.createObjectURL(response.data);
314 });
315 } // TODO tile.setState(TileState.ERROR);
316 })
317 }),
318 (function() {
319 const source = new VectorSource({ strategy: bboxStrategy });
320 source.setLoader(
321 buildVectorLoader(
322 {
323 featureTypes: ["bottlenecks_geoserver"],
324 geometryName: "area"
325 },
326 source
327 )
328 );
329 return new VectorLayer({
330 id: "BOTTLENECKSTATUS",
331 label: "Critical Bottlenecks",
332 forLegendStyle: { point: true, resolution: 16 },
333 visible: true,
334 style: styles.bottleneckStatus,
335 source
336 });
337 })(),
338 (function() {
339 const source = new VectorSource({ strategy: bboxStrategy });
340 source.setLoader(
341 buildVectorLoader(
342 {
343 featureTypes: ["distance_marks_ashore_geoserver"],
344 geometryName: "geom"
345 },
346 source
347 )
348 );
349 return new VectorLayer({
350 id: "DISTANCEMARKS",
351 label: "Distance marks",
352 forLegendStyle: { point: true, resolution: 8 },
353 visible: false,
354 source
355 });
356 })(),
357 (function() {
358 const source = new VectorSource({ strategy: bboxStrategy });
359 source.setLoader(
360 buildVectorLoader(
361 {
362 featureTypes: ["distance_marks_geoserver"],
363 geometryName: "geom"
364 },
365 source
366 )
367 );
368 return new VectorLayer({
369 id: "DISTANCEMARKSAXIS",
370 label: "Distance marks, Axis",
371 forLegendStyle: { point: true, resolution: 8 },
372 visible: true,
373 style: styles.dma,
374 source
375 });
376 })(),
377 (function() {
378 const source = new VectorSource({ strategy: bboxStrategy });
379 source.setLoader(
380 buildVectorLoader(
381 {
382 featureTypes: ["gauges_geoserver"],
383 geometryName: "geom"
384 },
385 source
386 )
387 );
388 return new VectorLayer({
389 id: "GAUGES",
390 label: "Gauges",
391 forLegendStyle: { point: true, resolution: 8 },
392 visible: true,
393 style: styles.gauge,
394 maxResolution: 100,
395 minResolution: 0,
396 source
397 });
398 })(),
399 new VectorLayer({
400 id: "DRAWTOOL",
401 label: "Draw Tool",
402 visible: true,
403 source: new VectorSource({ wrapX: false }),
404 style: function(feature) {
405 // adapted from OpenLayer's LineString Arrow Example
406 var geometry = feature.getGeometry();
407 var styles = [
408 // linestring
409 new Style({
410 stroke: new Stroke({
411 color: "#369aca",
412 width: 2
413 })
414 })
415 ];
416
417 if (geometry.getType() === "LineString") {
418 geometry.forEachSegment(function(start, end) {
419 var dx = end[0] - start[0];
420 var dy = end[1] - start[1];
421 var rotation = Math.atan2(dy, dx);
422 // arrows
423 styles.push(
424 new Style({
425 geometry: new Point(end),
426 image: new Icon({
427 // we need to make sure the image is loaded by Vue Loader
428 src: require("@/assets/linestring_arrow.png"),
429 // fiddling with the anchor's y value does not help to
430 // position the image more centered on the line ending, as the
431 // default line style seems to be slightly uncentered in the
432 // anti-aliasing, but the image is not placed with subpixel
433 // precision
434 anchor: [0.75, 0.5],
435 rotateWithView: true,
436 rotation: -rotation
437 })
438 })
439 );
440 });
441 }
442 return styles;
443 }
444 }),
445 new VectorLayer({
446 id: "CUTTOOL",
447 label: "Cut Tool",
448 visible: true,
449 source: new VectorSource({ wrapX: false }),
450 style: function(feature) {
451 // adapted from OpenLayer's LineString Arrow Example
452 var geometry = feature.getGeometry();
453 var styles = [
454 // linestring
455 new Style({
456 stroke: new Stroke({
457 color: "#333333",
458 width: 2,
459 lineDash: [7, 7]
460 })
461 })
462 ];
463
464 if (geometry.getType() === "LineString") {
465 geometry.forEachSegment(function(start, end) {
466 var dx = end[0] - start[0];
467 var dy = end[1] - start[1];
468 var rotation = Math.atan2(dy, dx);
469 // arrows
470 styles.push(
471 new Style({
472 geometry: new Point(end),
473 image: new Icon({
474 // we need to make sure the image is loaded by Vue Loader
475 src: require("@/assets/linestring_arrow_grey.png"),
476 // fiddling with the anchor's y value does not help to
477 // position the image more centered on the line ending, as the
478 // default line style seems to be slightly uncentered in the
479 // anti-aliasing, but the image is not placed with subpixel
480 // precision
481 anchor: [0.75, 0.5],
482 rotateWithView: true,
483 rotation: -rotation
484 })
485 })
486 );
487 });
488 }
489 return styles;
490 }
491 })
492 ]
493 };
494 })();