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.