view client/src/components/map/styles.js @ 4279:30f26bf7ff24

Reordering of elements In order to improve user experience the configuration of avail, forceast vs. real and accuracy was changed in such a way, that it now mirrors the optics of the displayed triangle. The order in the identify tool was changed accordingly 1) avail 2) forcast vs. real 3) accuracy "Currency" was cleaned up to "recency"
author Thomas Junk <thomas.junk@intevation.de>
date Thu, 29 Aug 2019 15:04:02 +0200
parents 1d4e588a61df
children be7c23af783c
line wrap: on
line source

import { Icon, Stroke, Style, Fill, Text, Circle } from "ol/style";
import Point from "ol/geom/Point";
import { getCenter } from "ol/extent";
import store from "@/store/index";
import classifications from "../../lib/classifications";

const styles = {
  blue1: new Style({
    stroke: new Stroke({
      color: [0, 0, 255, 0.8],
      lineDash: [2, 4],
      lineCap: "round",
      width: 2
    }),
    fill: new Fill({
      color: [240, 230, 0, 0.2]
    })
  }),
  blue2: new Style({
    stroke: new Stroke({
      color: [0, 0, 255, 0.9],
      lineDash: [3, 6],
      lineCap: "round",
      width: 2
    }),
    fill: new Fill({
      color: [240, 230, 0, 0.1]
    })
  }),
  blue3: new Style({
    stroke: new Stroke({
      color: [0, 0, 255, 1.0],
      width: 2
    }),
    fill: new Fill({
      color: [255, 255, 255, 0.4]
    })
  }),
  yellow1: new Style({
    stroke: new Stroke({
      color: "rgba(230, 230, 10, .8)",
      width: 4
    }),
    fill: new Fill({
      color: "rgba(230, 230, 10, .3)"
    })
  }),
  yellow2: new Style({
    stroke: new Stroke({
      color: "rgba(250, 200, 0, .8)",
      width: 2
    }),
    fill: new Fill({
      color: "rgba(250, 200, 10, .3)"
    })
  }),
  yellow3: new Style({
    stroke: new Stroke({
      color: "rgba(250, 240, 10, .9)",
      width: 5
    }),
    fill: new Fill({
      color: "rgba(250, 240, 0, .7)"
    })
  }),
  orange1: new Style({
    stroke: new Stroke({
      color: "rgba(255, 150, 10, .8)",
      width: 2
    }),
    fill: new Fill({
      color: "rgba(255, 150, 0, .3)"
    })
  }),
  orange2: new Style({
    stroke: new Stroke({
      color: "rgba(255, 166, 10, .9)",
      width: 5
    }),
    fill: new Fill({
      color: "rgba(255, 166, 0, .7)"
    })
  }),
  red1: new Style({
    stroke: new Stroke({
      color: "rgba(255, 0, 0, 1)",
      width: 4
    })
  }),
  circleBlue: new Style({
    image: new Circle({
      radius: 5,
      fill: new Fill({ color: "rgba(255, 0, 0, 0.1)" }),
      stroke: new Stroke({ color: "blue", width: 1 })
    })
  }),
  textFW1: new Style({
    text: new Text({
      font: 'bold 12px "Open Sans", "sans-serif"',
      placement: "line",
      fill: new Fill({
        color: "black"
      }),
      text: "LOS: 1"
      //, zIndex: 10
    })
  }),
  textFW2: new Style({
    text: new Text({
      font: 'bold 12px "Open Sans", "sans-serif"',
      placement: "line",
      fill: new Fill({
        color: "black"
      }),
      text: "LOS: 2"
      //, zIndex: 10
    })
  }),
  textFW3: new Style({
    text: new Text({
      font: 'bold 12px "Open Sans", "sans-serif"',
      placement: "line",
      fill: new Fill({
        color: "black"
      }),
      text: "LOS: 3"
      //, zIndex: 10
    })
  })
};

const styleFactory = function(mapId) {
  const recencyColorCodes = {
    OK: "lime",
    WARNING: "yellow",
    DANGER: "red",
    NEUTRAL: "white"
  };
  const gmAvailabilityColorCodes = {
    OK: "lime",
    WARNING: "yellow",
    DANGER: "red",
    NEUTRAL: "white"
  };
  const forecastAccuracyColorCodes = {
    OK: "lime",
    WARNING: "yellow",
    DANGER: "red",
    NEUTRAL: "white"
  };

  const forecastVsRealityColorCodes = {
    OK: "lime",
    WARNING: "yellow",
    DANGER: "red",
    NEUTRAL: "white"
  };
  return {
    recencyColorCodes: recencyColorCodes,
    gmAvailabilityColorCodes: gmAvailabilityColorCodes,
    forecastAccuracyColorCodes: forecastAccuracyColorCodes,
    forecastVsRealityColorCodes: forecastVsRealityColorCodes,
    stretches(feature) {
      let style = styles.yellow2;
      if (feature.get("highlighted")) {
        style = styles.yellow3;
      }
      return style;
    },
    sections(feature) {
      let style = styles.orange1;
      if (feature.get("highlighted")) {
        style = styles.orange2;
      }
      return style;
    },
    fwd1() {
      return [styles.blue1, styles.textFW1];
    },
    fwd2() {
      return [styles.blue2, styles.textFW2];
    },
    fwd3() {
      return [styles.blue3, styles.textFW3];
    },
    bottleneck() {
      return styles.yellow1;
    },
    bottleneckStatus(feature, resolution, isLegend) {
      let s = [];
      if ((feature.get("fa_critical") && resolution > 15) || isLegend) {
        let bnCenter = getCenter(feature.getGeometry().getExtent());
        s.push(
          new Style({
            geometry: new Point(bnCenter),
            image: new Icon({
              src: require("@/assets/marker-bottleneck-critical.png"),
              anchor: [0.5, 0.5],
              scale: isLegend ? 0.5 : 1
            })
          })
        );
      }
      if (feature.get("fa_critical") && !isLegend) {
        s.push(styles.red1);
      }
      return s;
    },
    bottleneckFairwayAvailability(feature, resolution, isLegend) {
      let s = [];
      if (isLegend) {
        s.push(
          new Style({
            image: new Icon({
              src: require("@/assets/fa-diagram.png"),
              anchor: [0.5, 0.5],
              scale: 1
            })
          })
        );
      }
      if (feature.get("fa_critical") && feature.get("fa_data")) {
        let data = feature.get("fa_data");
        let lnwlHeight = (80 / 100) * data.ldc;
        let belowThresholdHeight = (80 / 100) * data.below;
        let betweenThresholdHeight = (80 / 100) * data.between;
        let aboveThresholdHeight = (80 / 100) * data.above;

        let frame = `<rect x='0' y='0' width='32' height='84' stroke-width='0' fill='white'/>`;
        let lnwl = `<rect x='2' y='${80 -
          lnwlHeight +
          2}' width='10' height='${lnwlHeight}' stroke-width='0' fill='aqua'/>`;
        let range1 = `<rect x='12' y='2' width='18' height='${belowThresholdHeight}' stroke-width='0' fill='hotpink'/>`;
        let range2 = `<rect x='12' y='${belowThresholdHeight +
          2}' width='18' height='${betweenThresholdHeight}' stroke-width='0' fill='darksalmon'/>`;
        let range3 = `<rect x='12' y='${80 -
          aboveThresholdHeight +
          2}' width='18' height='${aboveThresholdHeight}' stroke-width='0' fill='blue'/>`;
        let svg = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='84'><g>${frame}${lnwl}${range1}${range2}${range3}</g></svg>`;
        let bnCenter = getCenter(feature.getGeometry().getExtent());
        s.push(
          new Style({
            geometry: new Point(bnCenter),
            image: new Icon({
              src: svg,
              anchor: [1.2, 1.2]
            })
          })
        );
      }
      return s;
    },
    dataAvailability(feature, resolution, isLegend) {
      let s = [];
      if (isLegend) {
        s.push(
          new Style({
            image: new Icon({
              src: require("@/assets/da-diagram.png"),
              anchor: [0.5, 0.5],
              scale: 1
            })
          })
        );
      } else {
        // TODO: Get information from feature and check the ranges according to #423, #424, #425
        let colorWaterlevel =
          gmAvailabilityColorCodes[classifications.gmAvailability(feature)];
        let colorComparison =
          forecastVsRealityColorCodes[
            classifications.forecastVsReality(feature)
          ];
        let colorAccuracy =
          forecastAccuracyColorCodes[classifications.forecastAccuracy(feature)];
        let map = store.getters["map/openLayersMap"](mapId);
        let geom = feature.getGeometry();
        if (!(geom instanceof Point)) {
          geom = new Point(getCenter(feature.getGeometry().getExtent()));
        }
        if (
          (map.getLayer("BOTTLENECKS").getVisible() &&
            feature.getId().indexOf("bottlenecks") > -1) ||
          (map.getLayer("SECTIONS").getVisible() &&
            feature.getId().indexOf("sections") > -1) ||
          (map.getLayer("STRETCHES").getVisible() &&
            feature.getId().indexOf("stretches") > -1) ||
          (map.getLayer("GAUGES").getVisible() &&
            feature.getId().indexOf("gauges") > -1)
        ) {
          let frame = `<polyline points='16,0 32,28 0,28 16,0' stroke='grey' stroke-width='1' fill='white'/>`;
          let waterlevel = `<polyline points="16,0 24,14 16,28 8,14 16,0" stroke='grey' stroke-width='1' fill='${colorWaterlevel}'/>`;
          let accuracy = `<polyline points="24,14 32,28 16,28 24,14" stroke='grey' stroke-width='1' fill='${colorAccuracy}'/>`;
          let comparison = `<polyline points="8,14 16,28 0,28 8,14" stroke='grey' stroke-width='1' fill='${colorComparison}'/>`;
          let svg = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='28'><g>${frame}${waterlevel}${comparison}${accuracy}</g></svg>`;
          s.push(
            new Style({
              geometry: geom,
              image: new Icon({
                src: svg,
                anchor: [-0.5, 1]
              })
            })
          );
        }

        if (
          map.getLayer("BOTTLENECKS").getVisible() &&
          feature.getId().indexOf("bottlenecks") > -1
        ) {
          let colorUniformTriangle =
            recencyColorCodes[classifications.surveyRecency(feature)];
          let frame = `<polyline points='16,0 32,28 0,28 16,0' stroke='grey' stroke-width='1' fill='${colorUniformTriangle}'/>`;
          let svg = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='28'><g>${frame}</g></svg>`;
          s.push(
            new Style({
              geometry: geom,
              image: new Icon({
                src: svg,
                anchor: [0.5, 1]
              })
            })
          );
        }
      }
      return s;
    },
    dma(feature, resolution) {
      if (resolution < 10) {
        var s = styles.circleBlue;
        if (resolution < 6) {
          s.setText(
            new Text({
              offsetY: 12,
              font: '10px "Open Sans", "sans-serif"',
              fill: new Fill({
                color: "black"
              }),
              text: (feature.get("hectometre") / 10).toString()
            })
          );
        }
        return s;
      }
      return [];
    },
    gauge(feature, resolution, isLegend) {
      let waterlevel = feature.get("gm_waterlevel");
      let text = feature.get("objname");
      let iconColor = "white";
      if (waterlevel) {
        text += "\n(" + waterlevel + " cm)";
        let refWaterlevels = JSON.parse(feature.get("reference_water_levels"));
        if (refWaterlevels) {
          const HDC =
            refWaterlevels[
              Object.keys(refWaterlevels).find(e => /HDC/.test(e))
            ];
          const LDC =
            refWaterlevels[
              Object.keys(refWaterlevels).find(e => /LDC/.test(e))
            ];
          if (waterlevel < LDC) iconColor = "brown";
          if (waterlevel > LDC && waterlevel < HDC) iconColor = "blue";
          if (waterlevel > HDC) iconColor = "red";
        }
      }

      return [
        new Style({
          image: new Icon({
            src: require("@/assets/marker-gauge-" + iconColor + ".png"),
            anchor: [0.5, isLegend ? 0.5 : 1],
            scale: isLegend ? 0.5 : 1
          }),
          text: new Text({
            font: '10px "Open Sans", "sans-serif"',
            offsetY: 15,
            fill: new Fill({
              color: "black"
            }),
            backgroundFill: new Fill({
              color: "rgba(255, 255, 255, 0.7)"
            }),
            padding: [2, 2, 2, 2],
            text
          })
        })
      ];
    }
  };
};

export { styles, styleFactory };