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;
+        }
+      })
+    ]
+  };
+})();