PageSourceSearch

https://www.drought.gov/modules/custom/general_page_js_css/js/map-helpers/ol-styles.js?tlrx84

js drought.gov collected 2026-09-24 08:36:07 UTC 30,120 bytes, 871 lines download raw bytes

1/**
2 * @module map-helpers/ol-styles
3 *
4 * More detailed API documentation for each function is below, but the intended
5 * pattern for using this module is to import the window.olStyles global object
6 * into your code. Then the main public functions are as follows. Other utility
7 * functions exported can be found in the exportConfig function, but these should
8 * cover 99% of use cases.
9 *
10 * - makeCachedStyle(type, options): This will be the most commonly called
11 *   function. It will always return an ol.style object -- either an existing
12 *   cached style if one which matches your passed parameters is found, or it
13 *   will create, cache, and then return one if it is not. The type parameter is
14 *   a String, accepted values are documented below. This value delegates what
15 *   type of style should be made. The options is an Object, it contains the
16 *   styles parameters.
17 * - getStyle(key): Returns an individual style from the cache. The key
18 *   parameter is a String which is used to query the cache. For debugging
19 *   purposes it can return the entire cache if called with a falsy value.
20 * - setStyle(key, style): Sets an ol.style to the cache, this function allows
21 *   for more custom styles that the system cannot dynamically generate to be
22 *   stored. The key parameter is a string, which is what your style is keyed by
23 *   in the cache. The style should be an ol.style, and it is what is stored.
24 *
25 * ACCEPTED STYLES: These are the types of styles the makeCachedStyle function
26 * can create.
27 *
28 * - 'basic': Style which is used for most polygons and line layers. Options are:
29 *    - key: String, optional. If you want to explicitly set a key for the cache
30 *      set it here. Otherwise a key will be dynamically generated from the
31 *      other options as a way to reduce duplicates.
32 *    - fillColor: String or null. HEX / RGB / HSV code for the fill of a layer.
33 *      Use a falsy value (but ideally null) to have the layer not be filled.
34 *    - strokeColor String or null. HEX / RGB / HSV code for the stroke of a
35 *      layer. Use a falsy value (but ideally null) to have no lines be drawn.
36 *    - strokeWidth Number or null. Width of the lines for a layer, if they are
37 *      drawn.
38 *
39 * - 'point': Style which is used for point layers. Options are:
40 *    - key: String, optional. If you want to explicitly set a key for the cache
41 *      set it here. Otherwise a key will be dynamically generated from the
42 *      other options as a way to reduce duplicates.
43 *    - radius: Number. Radius of the point.
44 *    - fillColor: String or null. HEX / RGB / HSV code for the fill of a layer.
45 *      Use a falsy value (but ideally null) to have the layer not be filled.
46 *    - strokeColor String or null. HEX / RGB / HSV code for the stroke of a
47 *      layer. Use a falsy value (but ideally null) to have no lines be drawn.
48 *    - strokeWidth Number or null. Width of the lines for a layer, if they are
49 *      drawn.
50 *
51 */
52(function (ol, olColors) {
53  const olStyleCache = {};
54
55  (function main() {
56    createUniversalStyles();
57    exportConfig();
58  })();
59
60  /**
61   * Creates the style function which colors in primary vector layers.
62   *
63   * Function needs to be dynamically generated to close over the parameters.
64   * @param {string} url - Primary url of layer. TODO: pull from metadata.
65   * @param {Element} mapElem - Wrapper element for the map.
66   * @param {Metadata} metadata - Metadata for the map.
67   * @return {function} - ol style function.
68   */
69  function createDataLayerStyleFunction(url, mapElem, metadata) {
70    return function (feature) {
71      let color = "#000";
72      const properties = feature.getProperties();
73      if (
74        feature.getGeometry() &&
75        (feature.getGeometry().getType().toLowerCase() === "point" ||
76          feature.getGeometry().getType().toLowerCase() === "multipoint")
77      ) {
78        if (url.indexOf("nws-dgt-pnts") !== -1) {
79          return makeNWSFeatureStyle(properties);
80        }
81        const pair = olColors.getOLColorKeyValuePair(metadata, feature);
82        if (pair.key !== undefined && pair.value !== undefined) {
83          color = olColors.getColor(pair.key, pair.value);
84          if (feature.get("isHighlighted")) {
85            color = toDarkenedHSL(color);
86          }
87        }
88        if (properties.hasOwnProperty("DM")) {
89          color = olColors.getColor("DM-nodata", parseInt(properties.DM, 10));
90        }
91        if (metadata.classes.indexOf("point-size-fib") !== -1) {
92          return makeCachedStyle("point", makeFibCircleStyleOptions(color, properties.DM));
93        }
94        if (
95          (url.indexOf("sector/agriculture") !== -1 ||
96            url.indexOf("sector/manufacturing") !== -1 ||
97            url.indexOf("acf/agriculture") !== -1 ||
98            url.indexOf("hucs2/agriculture") !== -1) &&
99          url.indexOf("-pnt") !== -1
100        ) {
101          if (window.drupalSettings.fipsCode || window.drupalSettings.watershed_name) {
102            let strokeColor = "#000";
103
104            if (window.drupalSettings.abv_state) {
105              if (properties.STATE !== window.drupalSettings.abv_state) {
106                color = "rgba(0,0,0,0)";
107                strokeColor = "rgba(0,0,0,0)";
108              }
109            }
110
111            return makeCachedStyle("point", {
112              radius: _getAgricultureRadius(parseInt(properties.INVENSCALE, 10)),
113              fillColor: color,
114              strokeColor,
115              strokeWidth: 0.5,
116            });
117          }
118          return makeCachedStyle("point", {
119            radius: 1 + parseInt(properties.INVENSCALE, 10),
120            fillColor: color,
121            strokeColor: "#000",
122            strokeWidth: 0.5,
123          });
124        }
125        if (url.indexOf("nrcs_swe") !== -1) {
126          const radius = color !== "transparent" ? 4 : 0;
127          const strokeColor = color !== "transparent" ? "#000" : "transparent";
128          return makeCachedStyle("point", { radius, fillColor: color, strokeColor, strokeWidth: 0.5 });
129        }
130        if (url.indexOf("strmflow") !== -1) {
131          let radius = color !== "transparent" ? 7 : 0;
132          const map = window.jQuery(mapElem).data("map");
133          if (map && radius !== 0 && map.getView().getZoom() < 6.5) {
134            radius = 3;
135          }
136          const strokeColor = color !== "transparent" ? "#000" : "transparent";
137          return makeCachedStyle("point", { radius, fillColor: color, strokeColor, strokeWidth: 0.5 });
138        }
139        if (url.indexOf("usace-dams") !== -1) {
140          const radius = color !== "transparent" ? 7 : 0;
141          const strokeColor = color !== "transparent" ? "#000" : "transparent";
142          return makeCachedStyle("point", { radius, fillColor: color, strokeColor, strokeWidth: 0.5 });
143        }
144        if (url.indexOf("svicounty") !== -1) {
145          feature.setGeometry(new ol.geom.Point(window.mapsUtil.getCenterOfExtent(feature.getGeometry().getExtent())));
146          return makeSVICountyPointStyle(properties, color);
147        }
148        if (url.indexOf("ahpsfcst") !== -1 || url.includes("nwpsobs")) {
149          const radius = color !== "transparent" ? 4 : 0;
150          const strokeColor = color !== "transparent" ? "#000" : "transparent";
151          return makeCachedStyle("point", { radius, fillColor: color, strokeColor, strokeWidth: 0.5 });
152        }
153
154        if (url.toLowerCase().includes("umrb") && url.toLowerCase().includes("svwc") && window.umrbStyle) {
155          return window.umrbStyle(color, properties, metadata);
156        }
157
158        if (metadata.classes.includes("faw-") && window.umrbFAWStyle) {
159          return window.umrbFAWStyle(color);
160        }
161
162        if (metadata.classes.includes("u--hide-transparent") && color === "transparent") {
163          return makeCachedStyle("point", {
164            radius: 0,
165            fillColor: "transparent",
166            strokeColor: "transparent",
167            strokeWidth: 0,
168          });
169        }
170
171        return makeCachedStyle("point", {
172          radius: 7,
173          fillColor: color,
174          strokeColor: "#000",
175          strokeWidth: 0.5,
176        });
177      }
178      if (feature.getGeometry() && feature.getGeometry().getType().toLowerCase().indexOf("linestring") !== -1) {
179        const keyValuePair = olColors.getOLColorKeyValuePair(metadata, feature);
180        const strokeColor = olColors.getColor(keyValuePair.key, keyValuePair.value);
181        return makeCachedStyle("basic", { fillColor: null, strokeColor, strokeWidth: 1 });
182      }
183      if (url.indexOf("svicounty") !== -1) {
184        feature.setGeometry(new ol.geom.Point(window.mapsUtil.getCenterOfExtent(feature.getGeometry().getExtent())));
185        return makeSVICountyPointStyle(properties, color);
186      }
187      if (typeof feature !== "undefined") {
188        const keyValuePair = olColors.getOLColorKeyValuePair(metadata, feature);
189        const fillColor = olColors.getColor(keyValuePair.key, keyValuePair.value);
190        const strokeColor = metadata.classes.indexOf("no-stroke") !== -1 ? null : "rgba(0, 0, 0, .35)";
191        const strokeWidth = metadata.classes.indexOf("no-stroke") !== -1 ? null : 0.4;
192        return makeCachedStyle("basic", { fillColor, strokeColor, strokeWidth });
193      }
194    };
195  }
196
197  /**
198   * Generates an openlayers flat style for use with the WebGL renderer of the streamflow map.
199   *
200   * Unable to use the filter/rules pattern since that doesn't seem to work with webgl.
201   * https://stackoverflow.com/questions/77170889/openlayers-8-1-apply-flatstyle-conditionally
202   * @return {{}} - OpenLayers flat style https://openlayers.org/en/latest/apidoc/module-ol_style_flat.html
203   */
204  function makeStreamflowFlatStyle() {
205    const ramp = olColors.getRamp("streamflow");
206
207    return {
208      // eslint-disable-next-line no-restricted-properties
209      "circle-radius": ["interpolate", ["exponential", 2], ["zoom"], 5, 3, 15, 1.5 * Math.pow(2, 10)],
210      "circle-fill-color": [
211        "match",
212        ["get", "isHighlighted"],
213        1,
214        [
215          "match",
216          ["get", "CLASS"],
217          1,
218          toDarkenedHSL(ramp[1]),
219          2,
220          toDarkenedHSL(ramp[2]),
221          3,
222          toDarkenedHSL(ramp[3]),
223          4,
224          toDarkenedHSL(ramp[4]),
225          5,
226          toDarkenedHSL(ramp[5]),
227          6,
228          toDarkenedHSL(ramp[6]),
229          7,
230          toDarkenedHSL(ramp[7]),
231          8,
232          toDarkenedHSL(ramp[8]),
233          "1",
234          toDarkenedHSL(ramp[1]),
235          "2",
236          toDarkenedHSL(ramp[2]),
237          "3",
238          toDarkenedHSL(ramp[3]),
239          "4",
240          toDarkenedHSL(ramp[4]),
241          "5",
242          toDarkenedHSL(ramp[5]),
243          "6",
244          toDarkenedHSL(ramp[6]),
245          "7",
246          toDarkenedHSL(ramp[7]),
247          "8",
248          toDarkenedHSL(ramp[8]),
249          "transparent",
250        ],
251        [
252          "match",
253          ["get", "CLASS"],
254          1,
255          ramp[1],
256          2,
257          ramp[2],
258          3,
259          ramp[3],
260          4,
261          ramp[4],
262          5,
263          ramp[5],
264          6,
265          ramp[6],
266          7,
267          ramp[7],
268          8,
269          ramp[8],
270          "1",
271          ramp[1],
272          "2",
273          ramp[2],
274          "3",
275          ramp[3],
276          "4",
277          ramp[4],
278          "5",
279          ramp[5],
280          "6",
281          ramp[6],
282          "7",
283          ramp[7],
284          "8",
285          ramp[8],
286          "transparent",
287        ],
288      ],
289      "circle-displacement": [0, 0],
290      "circle-stroke-width": ["match", ["get", "CLASS"], 0, 0, 0.5],
291      "circle-stroke-color": ["match", ["get", "CLASS"], 0, "transparent", "0", "transparent", "#000"],
292    };
293  }
294
295  /**
296   * Converts hex to hsl and darkens the color by 40%.
297   * @param {string} hex - Base color for a point. Only accepts 4 or 7 digit hex codes.
298   * @return {string} - hsl formatted hex or original color if not parse~able.
299   */
300  function toDarkenedHSL(hex) {
301    let result;
302    if (hex.charAt(0) !== "#") {
303      return hex;
304    }
305    if (hex.length === 4) {
306      hex =
307        hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2) + hex.charAt(3) + hex.charAt(3);
308    }
309    if (hex.length === 7) {
310      result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
311    } else {
312      return hex;
313    }
314    const r = parseInt(result[1], 16) / 255;
315    const g = parseInt(result[2], 16) / 255;
316    const b = parseInt(result[3], 16) / 255;
317    const max = Math.max(r, g, b);
318    const min = Math.min(r, g, b);
319
320    let h,
321      s,
322      l = (max + min) / 2;
323
324    if (max === min) {
325      h = 0;
326      s = 0; // achromatic
327    } else {
328      const d = max - min;
329      s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
330      if (max === r) {
331        h = (g - b) / d + (g < b ? 6 : 0);
332      } else if (max === g) {
333        h = (b - r) / d + 2;
334      } else {
335        h = (r - g) / d + 4;
336      }
337      h /= 6;
338    }
339    h = Math.round(360 * h);
340    s = Math.round(s * 100);
341    l = Math.round(l * 100 * 0.6);
342
343    return `hsl(${h}, ${s}%, ${l}%)`;
344  }
345
346  /**
347   * Calculates the agriculture dots radius based on the scale parameter.
348   * @param {integer|undefined} scale - INVENSCALE value. Relative size of crop.
349   * @return {number} - radius of ag point.
350   */
351  function _getAgricultureRadius(scale) {
352    let radius = 5;
353    if (scale) {
354      if (scale === 7) {
355        radius = 9;
356      } else if ([5, 6].includes(scale)) {
357        radius = 7;
358      } else if ([3, 4].includes(scale)) {
359        radius = 5;
360      } else if ([0, 1, 2].includes(scale)) {
361        radius = 3;
362      }
363    }
364    return radius;
365  }
366
367  /**
368   * Sets up initial styles used across most maps
369   */
370  function createUniversalStyles() {
371    setStyle("strokeOutline", makeBasicStyle("rgba(255, 255, 255, 0)", "#000", 1));
372    setStyle("strokeGrayInner", makeBasicStyle("#dad9d9", "#000", 0.2));
373    setStyle("strokeInner", makeBasicStyle("rgba(255, 255, 255, 0)", "#000", 0.5));
374    setStyle("styleHighlight", makeBasicStyle("rgba(76, 76, 76, 0.5)", "#000", 0.5));
375    setStyle("styleMask", makeBasicStyle("#f00", null, null));
376    setStyle("styleDrought", makeBasicStyle("rgba(255, 255, 255, 0.8)", null, null));
377    setStyle("styleTransparent", makeBasicStyle("transparent", "transparent", 0));
378    setStyle("styleStates", makeBasicStyle("rgba(255, 255, 255, 0)", "rgba(48, 48, 48, .9)", 0.5));
379    setStyle("usdm", function (feature) {
380      return makeCachedStyle("basic", {
381        fillColor: olColors.getColor("DM-nodata", feature.getProperties().DM),
382        strokeColor: null,
383        strokeWidth: null,
384      });
385    });
386    setStyle("usdmchange", function (feature) {
387      return makeCachedStyle("basic", {
388        fillColor: olColors.getColor("drought-change", feature.getProperties().DN),
389        strokeColor: null,
390        strokeWidth: null,
391      });
392    });
393    setStyle("usdmlines", function (feature) {
394      return makeCachedStyle("basic", {
395        strokeColor: olColors.getColor("DM-nodata", feature.getProperties().DM),
396        strokeWidth: 2,
397      });
398    });
399    setStyle("usdmlinesfill", function (feature) {
400      return makeCachedStyle("basic", {
401        fillColor: olColors.getColor("DM-light", feature.getProperties().DM),
402        strokeColor: olColors.getColor("DM-nodata", feature.getProperties().DM),
403        strokeWidth: 2,
404      });
405    });
406  }
407
408  /**
409   * Returns an individual style. For debugging purposes it can return the
410   * entire cache if called with a falsy value as the key.
411   * @param key {string|null}
412   * @return {{}|ol.style.Style|function}
413   */
414  function getStyle(key) {
415    if (!key) {
416      return olStyleCache;
417    }
418    return olStyleCache[key];
419  }
420
421  /**
422   * Assigns a style to the cache.
423   * @param key {string}
424   * @param style {ol.style.Style|function}
425   */
426  function setStyle(key, style) {
427    olStyleCache[key] = style;
428  }
429
430  /**
431   * For performance reasons we do not want to remake a layer/feature style if
432   * another layer/feature uses the exact same options. This function returns a
433   * cached version of the style if it exists, and creates/caches/returns it if
434   * it does not.
435   * @param {string} type - "basic", "point", "shape", or "vectortile".
436   * @param {{}} options - Options for the style.
437   * @param {number|undefined} options.radius - For point or shape. Radius of point.
438   * @param {string|null} options.fillColor - For all. Hex color for fill.
439   * @param {string|null} options.strokeColor - For basic or point. Color of polygon border.
440   * @param {number|null} options.strokeWidth - For basic or point. Width of polygon border.
441   * @param {number|null} options.points - For shape. Number of points on shape.
442   * @param {string} options.key- optional key for the style. one will be procedurally made if this is not set.
443   * @return {ol.style.Style} - The style.
444   */
445  function makeCachedStyle(type, options) {
446    const key = options.key || makeCacheKey(type, options);
447    if (getStyle(key)) {
448      return getStyle(key);
449    }
450    if (type === "basic") {
451      return makeCachedBasicStyle(key, options);
452    }
453    if (type === "point") {
454      return makeCachedPointStyle(key, options);
455    }
456    if (type === "shape") {
457      return makeCachedShapeStyle(key, options);
458    }
459    if (type === "vectortile") {
460      return makeCachedVectorTileStyle(key);
461    }
462  }
463
464  /**
465   * @param key {string}
466   * @param options {{}}
467   * @param options.fillColor {string|null}
468   * @param options.strokeColor {string|null}
469   * @param options.strokeWidth {number|null}
470   * @return {ol.style.Style}
471   */
472  function makeCachedBasicStyle(key, options) {
473    const style = makeBasicStyle(options.fillColor, options.strokeColor, options.strokeWidth);
474    setStyle(key, style);
475    return style;
476  }
477
478  /**
479   * @param key {string}
480   * @param options {{}}
481   * @param options.radius {number}
482   * @param options.fillColor {string|null}
483   * @param options.strokeColor {string|null}
484   * @param options.strokeWidth {number|null}
485   * @return {ol.style.Style}
486   */
487  function makeCachedPointStyle(key, options) {
488    const style = makePointStyle(options.radius, options.fillColor, options.strokeColor, options.strokeWidth);
489    setStyle(key, style);
490    return style;
491  }
492
493  /**
494   * Generates and caches RegularShape style.
495   * @param {string} key - Key to cache generated style.
496   * @param {{}} options - Options for shape.
497   * @param {number} options.points - Number of points for the shape. IE 3 for triangle.
498   * @param {number} options.radius - Radius of shape. Will be scaled up by 25%.
499   * @param {string|null} options.fillColor - Hex color that fills shape.
500   * @return {ol.style.Style} - Shape style.
501   */
502  function makeCachedShapeStyle(key, options) {
503    const style = makeShapeStyle(options.points, options.radius, options.fillColor);
504    setStyle(key, style);
505    return style;
506  }
507
508  /**
509   * Creates a key for accessing the cache that uses the type of style and all relevant options
510   * @param type {string}
511   * @param options {{}}
512   * @return {string}
513   */
514  function makeCacheKey(type, options) {
515    let key = type + "-";
516    for (const prop in options) {
517      if (options.hasOwnProperty(prop) && options[prop]) {
518        key = key + "-" + prop.toString() + "-" + options[prop].toString();
519      }
520    }
521    return key;
522  }
523
524  /**
525   * @param fillColor {string|null}
526   * @param strokeColor {string|null}
527   * @param strokeWidth {number|null}
528   * @return {ol.style.Style}
529   */
530  function makeBasicStyle(fillColor, strokeColor, strokeWidth) {
531    const styleOptions = {};
532    if (fillColor) {
533      styleOptions.fill = new ol.style.Fill({
534        color: fillColor,
535      });
536    }
537    if (strokeColor) {
538      styleOptions.stroke = new ol.style.Stroke({
539        color: strokeColor,
540        width: strokeWidth,
541      });
542    }
543
544    return new ol.style.Style(styleOptions);
545  }
546
547  /**
548   * @param radius{number}
549   * @param fillColor {string|null}
550   * @param strokeColor {string|null}
551   * @param strokeWidth {number|null}
552   * @return {ol.style.Style}
553   */
554  function makePointStyle(radius, fillColor, strokeColor, strokeWidth) {
555    const styleOptions = {
556      radius,
557    };
558    if (fillColor) {
559      styleOptions.fill = new ol.style.Fill({
560        color: fillColor,
561      });
562    }
563    if (strokeColor) {
564      styleOptions.stroke = new ol.style.Stroke({
565        color: strokeColor,
566        width: strokeWidth,
567      });
568    }
569
570    return new ol.style.Style({
571      image: new ol.style.Circle(styleOptions),
572    });
573  }
574
575  /**
576   * Creates a RegularShape style. Currently just used for triangles for the UMRB.
577   * https://openlayers.org/en/latest/apidoc/module-ol_style_RegularShape-RegularShape.html
578   * @param {number} points - Number of points for the shape. IE 3 for a triangle.
579   * @param {number} radius - Radius of the shape. Value is scaled up as triangles are the only type generated.
580   * @param {string|null} fillColor - Color filled in the shape.
581   * @return {ol.style.Style} - The style for a feature.
582   */
583  function makeShapeStyle(points, radius, fillColor) {
584    const styleOptions = {
585      points,
586      radius: radius * 1.25,
587      angle: 0,
588      stroke: new ol.style.Stroke({
589        color: "#000",
590        width: 0.5,
591      }),
592    };
593    if (fillColor) {
594      styleOptions.fill = new ol.style.Fill({
595        color: fillColor,
596      });
597    }
598
599    return new ol.style.Style({
600      image: new ol.style.RegularShape(styleOptions),
601    });
602  }
603
604  /**
605   * @param properties {ol.Object}
606   * @param properties.STATEMENT {string}
607   * @param properties.DATE {string}
608   * @return {ol.style.Style}
609   */
610  function makeNWSFeatureStyle(properties) {
611    if (properties.STATEMENT !== "No drought statement available for this WFO.") {
612      const date = properties.DATE?.replace("p.m.", "PM").replace("a.m.", "AM").slice(0, -4).trim();
613      const dateParsed = d3.timeParse("%b %-d, %Y, %-I:%M %p")(date);
614      if (dateParsed && d3.timeDay.count(dateParsed, new Date()) < 35) {
615        if (!olStyles.getStyle("nws-dgt-pnts")) {
616          olStyles.setStyle("nws-dgt-pnts", olStyles.makeNWSIconStyle());
617        }
618        return olStyles.getStyle("nws-dgt-pnts");
619      }
620    }
621    return new ol.style.Style({});
622  }
623
624  /**
625   * Makes custom points for the county SVI dots. Creates radius based on the
626   * vulnerability value.
627   * @param properties {{}} OL Feature properties
628   * @param color {string}
629   * @return {ol.style.Style}
630   */
631  function makeSVICountyPointStyle(properties, color) {
632    const vulnerability = parseFloat(properties.RPL_THEMES);
633    let radius = 4;
634    if (vulnerability >= 0.25001) {
635      radius = 10 * vulnerability;
636    } else if (vulnerability >= 0 && vulnerability <= 0.25) {
637      radius = 10 * vulnerability + 2;
638    }
639    if (radius === 0) {
640      radius = 4;
641    }
642    // Round to nearest .5
643    radius = Math.round(radius * 2) / 2;
644    return makeCachedStyle("point", {
645      radius,
646      fillColor: color,
647      strokeColor: "#000",
648      strokeWidth: 1,
649    });
650  }
651
652  /**
653   * @return {ol.style.Style}
654   */
655  function makeNWSIconStyle() {
656    return new ol.style.Style({
657      image: new ol.style.RegularShape({
658        radius: 16,
659        points: 4,
660        angle: Math.PI / 4,
661        fill: new ol.style.Fill({
662          color: "#0071bc",
663        }),
664        stroke: new ol.style.Stroke({
665          color: "#fdb81e",
666          width: 2,
667        }),
668      }),
669      text: new ol.style.Text({
670        textAlign: "center",
671        text: "i",
672        font: "bold 12px Roboto Slab, serif",
673        scale: 1.5,
674        fill: new ol.style.Fill({
675          color: "#FFFFFF",
676        }),
677        stroke: new ol.style.Stroke({
678          color: "#000000",
679          width: 1,
680        }),
681      }),
682    });
683  }
684
685  /**
686   * Implements points which are scaled using the fibonacci numbers as the
687   * difference between point sizes for each drought monitor category.
688   * @param color {string}
689   * @param DM {string|undefined}
690   * @return {{fillColor: string, strokeWidth: number, radius: number, strokeColor: string}}
691   */
692  function makeFibCircleStyleOptions(color, DM) {
693    const fibScaler = [0, 1, 2, 4, 7];
694    let pointSize = 3;
695    if (DM) {
696      pointSize += fibScaler[parseInt(DM, 10)];
697    }
698
699    return {
700      radius: pointSize,
701      fillColor: DM ? color : "#7fb135",
702      strokeColor: "#000",
703      strokeWidth: 1,
704    };
705  }
706
707  /**
708   * Creates, stores, and returns a vector tile style object.
709   * @param {string} url - URL for a vector style file. Should be in /modules/custom/nidis_maps/vector_styles
710   * @return {Promise|{}}
710 - A Promise of the remote style json or the json itself.
711   */
712  function makeCachedVectorTileStyle(url) {
713    setStyle(url, getRemoteVectorTileStyle(url));
714    return getStyle(url);
715  }
716
717  /**
718   * Gets and parses a vector tile style file.
719   * Lightly modified from
720   * https://github.com/openlayers/ol-mapbox-style/blob/d49cba2bb083d25c6b1619539a2e9f1902fb6df7/src/util.js#L165
721   * @param {string} url - URL for a vector style file. Should be in /modules/custom/nidis_maps/vector_styles
722   * @return {Promise|{}} - A Promise of the remote style json or the json itself.
723   */
724  function getRemoteVectorTileStyle(url) {
725    if (typeof url === "string") {
726      if (url.trim().startsWith("{")) {
727        try {
728          const glStyle = JSON.parse(url);
729          return Promise.resolve(glStyle);
730        } catch (error) {
731          return Promise.reject(error);
732        }
733      } else {
734        return fetchResource(url);
735      }
736    } else {
737      return Promise.resolve(url);
738    }
739  }
740
741  const pendingRequests = {};
742  /**
743   * Fetches a vector tile style file.
744   * Modified from
745   * https://github.com/openlayers/ol-mapbox-style/blob/d49cba2bb083d25c6b1619539a2e9f1902fb6df7/src/util.js#L121
746   * @param {string} url - URL for a vector style file. Should be in /modules/custom/nidis_maps/vector_styles
747   * @return {Promise|string} - A Promise of the remote style json or the a string of the json itself.
748   */
749  function fetchResource(url) {
750    if (url in pendingRequests) {
751      return pendingRequests[url][1];
752    }
753    const handleError = function (error) {
754      delete pendingRequests[url];
755      return Promise.reject(new Error("Error fetching source " + url));
756    };
757    const handleResponse = function (response) {
758      delete pendingRequests[url];
759      return response.ok ? response.json() : Promise.reject(new Error("Error fetching source " + url));
760    };
761    const pendingRequest = fetch(url)
762      .then((transformedRequest) => {
763        if (transformedRequest instanceof Response) {
764          return handleResponse(transformedRequest);
765        }
766        if (!(transformedRequest instanceof Request)) {
767          transformedRequest = new Request(transformedRequest);
768        }
769        if (!transformedRequest.headers.get("Accept")) {
770          transformedRequest.headers.set("Accept", "application/json");
771        }
772        return fetch(transformedRequest).then(handleResponse).catch(handleError);
773      })
774      .catch(handleError);
775    pendingRequests[url] = [url, pendingRequest];
776    return pendingRequest;
777  }
778
779  /**
780   * Fixed style function used for the creation of the ol-fixed-layers SNOTEL layer.
781   * @param {ol.Feature} feature - Feature to be styled.
782   * @return {ol.style.Style} - Dynamic style based on feature values.
783   */
784  function snotelStyle(feature) {
785    const metadata = {
786      layer:
787        "https://storage.googleapis.com/noaa-nidis-drought-gov-data/current-conditions/json/v1/us/swe/nrcs_huc_swe.geojson",
788      classes: "swe",
789    };
790    const keyValuePair = olColors.getOLColorKeyValuePair(metadata, feature);
791    const fillColor = olColors.getColor(keyValuePair.key, keyValuePair.value);
792    const strokeColor = "rgba(0, 0, 0, .35)";
793    const strokeWidth = 0.4;
794    return makeCachedStyle("basic", { fillColor, strokeColor, strokeWidth });
795  }
796
797  /**
798   * Fixed style function to draw thicker state lines. Currently only used by the NWS widget.
799   * @return {ol.style.Style} - The style for the state lines layer.
800   */
801  function statesThickLines() {
802    return makeCachedStyle("basic", {
803      fillColor: "rgba(255, 255, 255, 0)",
804      strokeColor: "rgba(48, 48, 48, .9)",
805      strokeWidth: 3,
806    });
807  }
808
809  /**
810   * Creates crosshatched tribal style. Since the image needs to load this is run at page load.
811   */
812  function tribalScreenshot() {
813    const tribalStyle = new window.ol.style.Style({
814      stroke: new window.ol.style.Stroke({
815        color: "#454545",
816        width: 1,
817      }),
818      fill: new window.ol.style.Fill({
819        color: "transparent",
820      }),
821    });
822    const canvas = document.createElement("canvas");
823    const context = canvas.getContext("2d");
824    const img = new Image();
825
826    img.onload = function () {
827      const pattern = context.createPattern(img, "repeat");
828      tribalStyle.getFill().setColor(pattern);
829    };
830    img.src = "/modules/custom/general_page_js_css/js/screenshot/icons/hatch.png?q=4";
831    return tribalStyle;
832  }
833
834  /**
835   * Creates a custom style function to highlight a selected DEWS.
836   * @param {string} dews - hyphenated name of DEWS.
837   * @return {function} - Style function which hides a DEWS if it isn't set in the URL or highlights it if so.
838   */
839  function dewsOverrideStyle(dews) {
840    return function dewsStyle(feature) {
841      if (feature.get("dews") !== dews.toLowerCase()) {
842        return getStyle("styleTransparent");
843      }
844      return makeCachedStyle("basic", {
845        fillColor: "transparent",
846        strokeColor: "#000",
847        strokeWidth: 2,
848      });
849    };
850  }
851
852  function exportConfig() {
853    window.olStyles = {
854      createDataLayerStyleFunction,
855      makeStreamflowFlatStyle,
856      getStyle,
857      setStyle,
858      makeCachedStyle,
859      makeBasicStyle,
860      makeNWSFeatureStyle,
861      makeNWSIconStyle,
862      makePointStyle,
863      makeFibCircleStyleOptions,
864      makeSVICountyPointStyle,
865      snotelStyle,
866      statesThickLines,
867      tribalScreenshot,
868      dewsOverrideStyle,
869    };
870  }
871})(window.ol, window.olColors);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.