Mercurial > gemma
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/map/layers.js Thu Apr 11 12:14:01 2019 +0200 @@ -0,0 +1,494 @@ +import TileWMS from "ol/source/TileWMS"; +import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer"; +import OSM from "ol/source/OSM"; +import { Icon, Stroke, Style } from "ol/style"; +import VectorSource from "ol/source/Vector"; +import Point from "ol/geom/Point"; +import { bbox as bboxStrategy } from "ol/loadingstrategy"; +import { WFS, GeoJSON } from "ol/format"; +import { equalTo } from "ol/format/filter"; +import { HTTP } from "@/lib/http"; +import styles from "./styles"; + +const buildVectorLoader = ( + featureRequestOptions, + vectorSource, + bboxStrategyDisabled, + featurePostProcessor +) => { + // build a function to be used for VectorSource.setLoader() + // make use of WFS().writeGetFeature to build the request + // and use our HTTP library to actually do it + // NOTE: the geometryName has to be given in featureRequestOptions if + // bboxStrategy (default) is used + featureRequestOptions.featureNS = "gemma"; + featureRequestOptions.featurePrefix = "gemma"; + featureRequestOptions.outputFormat = "application/json"; + return (extent, resolution, projection) => { + if (!bboxStrategyDisabled) { + featureRequestOptions.bbox = extent; + } + featureRequestOptions.srsName = projection.getCode(); + HTTP.post( + "/internal/wfs", + new XMLSerializer().serializeToString( + new WFS().writeGetFeature(featureRequestOptions) + ), + { + headers: { + "X-Gemma-Auth": localStorage.getItem("token"), + "Content-type": "text/xml; charset=UTF-8" + } + } + ) + .then(response => { + const features = new GeoJSON().readFeatures( + JSON.stringify(response.data) + ); + if (featurePostProcessor) { + features.map(f => featurePostProcessor(f)); + } + vectorSource.addFeatures(features); + }) + .catch(() => { + vectorSource.removeLoadedExtent(extent); + }); + }; +}; + +export default (function() { + return { + get(id) { + return this.config.find(l => l.get("id") === id); + }, + config: [ + new TileLayer({ + id: "OPENSTREETMAP", + label: "Open Streetmap", + visible: true, + source: new OSM() + }), + new TileLayer({ + id: "INLANDECDIS", + label: "Inland ECDIS chart Danube", + visible: true, + source: new TileWMS({ + preload: 1, + url: "https://service.d4d-portal.info/wms/", + crossOrigin: "anonymous", + params: { LAYERS: "d4d", VERSION: "1.1.1", TILED: true } + }) + }), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["waterway_area"], + geometryName: "area" + }, + source + ) + ); + return new VectorLayer({ + id: "WATERWAYAREA", + label: "Waterway Area", + visible: true, + style: new Style({ + stroke: new Stroke({ + color: "rgba(0, 102, 0, 1)", + width: 2 + }) + }), + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["stretches_geoserver"], + geometryName: "area" + }, + source, + f => { + if (f.getId() === this.selectedStretchId) { + f.set("highlighted", true); + } + return f; + } + ) + ); + return new VectorLayer({ + id: "STRETCHES", + label: "Stretches", + visible: false, + style: styles.stretches, + source + }); + })(), + (function() { + const source = new VectorSource(); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["fairway_dimensions"], + filter: equalTo("level_of_service", 1) + }, + source, + true + ) + ); + return new VectorLayer({ + id: "FAIRWAYDIMENSIONSLOS1", + label: "LOS 1 Fairway Dimensions", + visible: false, + style: styles.fwd1, + source + }); + })(), + (function() { + const source = new VectorSource(); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["fairway_dimensions"], + filter: equalTo("level_of_service", 2) + }, + source, + true + ) + ); + return new VectorLayer({ + id: "FAIRWAYDIMENSIONSLOS2", + label: "LOS 2 Fairway Dimensions", + visible: false, + style: styles.fwd2, + source + }); + })(), + (function() { + const source = new VectorSource(); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["fairway_dimensions"], + filter: equalTo("level_of_service", 3) + }, + source, + true + ) + ); + return new VectorLayer({ + id: "FAIRWAYDIMENSIONSLOS3", + label: "LOS 3 Fairway Dimensions", + visible: true, + style: styles.fwd3, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["waterway_axis"], + geometryName: "wtwaxs" + }, + source + ) + ); + return new VectorLayer({ + id: "WATERWAYAXIS", + label: "Waterway Axis", + visible: true, + style: new Style({ + stroke: new Stroke({ + color: "rgba(0, 0, 255, .5)", + lineDash: [5, 5], + width: 2 + }) + }), + // TODO: Set layer in layertree active/inactive depending on + // resolution. + maxResolution: 5, + minResolution: 0, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["waterway_profiles"], + geometryName: "geom" + }, + source + ) + ); + return new VectorLayer({ + id: "WATERWAYPROFILES", + label: "Waterway Profiles", + visible: true, + style: new Style({ + stroke: new Stroke({ + color: "rgba(0, 0, 255, .5)", + lineDash: [5, 5], + width: 2 + }) + }), + maxResolution: 2.5, + minResolution: 0, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["bottlenecks_geoserver"], + geometryName: "area" + }, + source + ) + ); + return new VectorLayer({ + id: "BOTTLENECKS", + label: "Bottlenecks", + visible: true, + style: styles.bottleneck, + source + }); + })(), + new TileLayer({ + id: "BOTTLENECKISOLINE", + label: "Bottleneck isolines", + visible: false, + source: new TileWMS({ + preload: 0, + projection: "EPSG:3857", + url: window.location.origin + "/api/internal/wms", + params: { + LAYERS: "sounding_results_contour_lines_geoserver", + VERSION: "1.1.1", + TILED: true + }, + tileLoadFunction: function(tile, src) { + // console.log("calling for", tile, src); + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + new TileLayer({ + id: "DIFFERENCES", + label: "Bottleneck Differences", + visible: false, + source: new TileWMS({ + preload: 0, + projection: "EPSG:4326", + url: window.location.origin + "/api/internal/wms", + params: { + LAYERS: "sounding_differences", + VERSION: "1.1.1", + TILED: true + }, + tileLoadFunction: function(tile, src) { + // console.log("calling for", tile, src); + HTTP.get(src, { + headers: { + "X-Gemma-Auth": localStorage.getItem("token") + }, + responseType: "blob" + }).then(response => { + tile.getImage().src = URL.createObjectURL(response.data); + }); + } // TODO tile.setState(TileState.ERROR); + }) + }), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["bottlenecks_geoserver"], + geometryName: "area" + }, + source + ) + ); + return new VectorLayer({ + id: "BOTTLENECKSTATUS", + label: "Critical Bottlenecks", + forLegendStyle: { point: true, resolution: 16 }, + visible: true, + style: styles.bottleneckStatus, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["distance_marks_ashore_geoserver"], + geometryName: "geom" + }, + source + ) + ); + return new VectorLayer({ + id: "DISTANCEMARKS", + label: "Distance marks", + forLegendStyle: { point: true, resolution: 8 }, + visible: false, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["distance_marks_geoserver"], + geometryName: "geom" + }, + source + ) + ); + return new VectorLayer({ + id: "DISTANCEMARKSAXIS", + label: "Distance marks, Axis", + forLegendStyle: { point: true, resolution: 8 }, + visible: true, + style: styles.dma, + source + }); + })(), + (function() { + const source = new VectorSource({ strategy: bboxStrategy }); + source.setLoader( + buildVectorLoader( + { + featureTypes: ["gauges_geoserver"], + geometryName: "geom" + }, + source + ) + ); + return new VectorLayer({ + id: "GAUGES", + label: "Gauges", + forLegendStyle: { point: true, resolution: 8 }, + visible: true, + style: styles.gauge, + maxResolution: 100, + minResolution: 0, + source + }); + })(), + new VectorLayer({ + id: "DRAWTOOL", + label: "Draw Tool", + visible: true, + source: new VectorSource({ wrapX: false }), + style: function(feature) { + // adapted from OpenLayer's LineString Arrow Example + var geometry = feature.getGeometry(); + var styles = [ + // linestring + new Style({ + stroke: new Stroke({ + color: "#369aca", + width: 2 + }) + }) + ]; + + if (geometry.getType() === "LineString") { + geometry.forEachSegment(function(start, end) { + var dx = end[0] - start[0]; + var dy = end[1] - start[1]; + var rotation = Math.atan2(dy, dx); + // arrows + styles.push( + new Style({ + geometry: new Point(end), + image: new Icon({ + // we need to make sure the image is loaded by Vue Loader + src: require("@/assets/linestring_arrow.png"), + // fiddling with the anchor's y value does not help to + // position the image more centered on the line ending, as the + // default line style seems to be slightly uncentered in the + // anti-aliasing, but the image is not placed with subpixel + // precision + anchor: [0.75, 0.5], + rotateWithView: true, + rotation: -rotation + }) + }) + ); + }); + } + return styles; + } + }), + new VectorLayer({ + id: "CUTTOOL", + label: "Cut Tool", + visible: true, + source: new VectorSource({ wrapX: false }), + style: function(feature) { + // adapted from OpenLayer's LineString Arrow Example + var geometry = feature.getGeometry(); + var styles = [ + // linestring + new Style({ + stroke: new Stroke({ + color: "#333333", + width: 2, + lineDash: [7, 7] + }) + }) + ]; + + if (geometry.getType() === "LineString") { + geometry.forEachSegment(function(start, end) { + var dx = end[0] - start[0]; + var dy = end[1] - start[1]; + var rotation = Math.atan2(dy, dx); + // arrows + styles.push( + new Style({ + geometry: new Point(end), + image: new Icon({ + // we need to make sure the image is loaded by Vue Loader + src: require("@/assets/linestring_arrow_grey.png"), + // fiddling with the anchor's y value does not help to + // position the image more centered on the line ending, as the + // default line style seems to be slightly uncentered in the + // anti-aliasing, but the image is not placed with subpixel + // precision + anchor: [0.75, 0.5], + rotateWithView: true, + rotation: -rotation + }) + }) + ); + }); + } + return styles; + } + }) + ] + }; +})();