1/******/ (() => { // webpackBootstrap 2/******/ var __webpack_modules__ = ({ 3 4/***/ 755:
vendor: 6,901 bytes, lines 4-268
4 5/***/ (function(module, exports) { 6 7var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! 8 * jQuery JavaScript Library v3.6.1 9 * https://jquery.com/ 10 * 11 * Includes Sizzle.js 12 * https://sizzlejs.com/ 13 * 14 * Copyright OpenJS Foundation and other contributors 15 * Released under the MIT license 16 * https://jquery.org/license 17 * 18 * Date: 2022-08-26T17:52Z 19 */ 20( function( global, factory ) { 21 22 "use strict"; 23 24 if ( true && typeof module.exports === "object" ) { 25 26 // For CommonJS and CommonJS-like environments where a proper `window` 27 // is present, execute the factory and get jQuery. 28 // For environments that do not have a `window` with a `document` 29 // (such as Node.js), expose a factory as module.exports. 30 // This accentuates the need for the creation of a real `window`. 31 // e.g. var jQuery = require("jquery")(window); 32 // See ticket trac-14549 for more info. 33 module.exports = global.document ? 34 factory( global, true ) : 35 function( w ) { 36 if ( !w.document ) { 37 throw new Error( "jQuery requires a window with a document" ); 38 } 39 return factory( w ); 40 }; 41 } else { 42 factory( global ); 43 } 44 45// Pass this if window is not defined yet 46} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { 47 48// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 49// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode 50// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common 51// enough that all such attempts are guarded in a try block. 52"use strict"; 53 54var arr = []; 55 56var getProto = Object.getPrototypeOf; 57 58var slice = arr.slice; 59 60var flat = arr.flat ? function( array ) { 61 return arr.flat.call( array ); 62} : function( array ) { 63 return arr.concat.apply( [], array ); 64}; 65 66 67var push = arr.push; 68 69var indexOf = arr.indexOf; 70 71var class2type = {}; 72 73var toString = class2type.toString; 74 75var hasOwn = class2type.hasOwnProperty; 76 77var fnToString = hasOwn.toString; 78 79var ObjectFunctionString = fnToString.call( Object ); 80 81var support = {}; 82 83var isFunction = function isFunction( obj ) { 84 85 // Support: Chrome <=57, Firefox <=52 86 // In some browsers, typeof returns "function" for HTML <object> elements 87 // (i.e., `typeof document.createElement( "object" ) === "function"`). 88 // We don't want to classify *any* DOM node as a function. 89 // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 90 // Plus for old WebKit, typeof returns "function" for HTML collections 91 // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) 92 return typeof obj === "function" && typeof obj.nodeType !== "number" && 93 typeof obj.item !== "function"; 94 }; 95 96 97var isWindow = function isWindow( obj ) { 98 return obj != null && obj === obj.window; 99 }; 100 101 102var document = window.document; 103 104 105 106 var preservedScriptAttributes = { 107 type: true, 108 src: true, 109 nonce: true, 110 noModule: true 111 }; 112 113 function DOMEval( code, node, doc ) { 114 doc = doc || document; 115 116 var i, val, 117 script = doc.createElement( "script" ); 118 119 script.text = code; 120 if ( node ) { 121 for ( i in preservedScriptAttributes ) { 122 123 // Support: Firefox 64+, Edge 18+ 124 // Some browsers don't support the "nonce" property on scripts. 125 // On the other hand, just using `getAttribute` is not enough as 126 // the `nonce` attribute is reset to an empty string whenever it 127 // becomes browsing-context connected. 128 // See https://github.com/whatwg/html/issues/2369 129 // See https://html.spec.whatwg.org/#nonce-attributes 130 // The `node.getAttribute` check was added for the sake of 131 // `jQuery.globalEval` so that it can fake a nonce-containing node 132 // via an object. 133 val = node[ i ] || node.getAttribute && node.getAttribute( i ); 134 if ( val ) { 135 script.setAttribute( i, val ); 136 } 137 } 138 } 139 doc.head.appendChild( script ).parentNode.removeChild( script ); 140 } 141 142 143function toType( obj ) { 144 if ( obj == null ) { 145 return obj + ""; 146 } 147 148 // Support: Android <=2.3 only (functionish RegExp) 149 return typeof obj === "object" || typeof obj === "function" ? 150 class2type[ toString.call( obj ) ] || "object" : 151 typeof obj; 152} 153/* global Symbol */ 154// Defining this global in .eslintrc.json would create a danger of using the global 155// unguarded in another place, it seems safer to define global only for this module 156 157 158 159var 160 version = "3.6.1", 161 162 // Define a local copy of jQuery 163 jQuery = function( selector, context ) { 164 165 // The jQuery object is actually just the init constructor 'enhanced' 166 // Need init if jQuery is called (just allow error to be thrown if not included) 167 return new jQuery.fn.init( selector, context ); 168 }; 169 170jQuery.fn = jQuery.prototype = { 171 172 // The current version of jQuery being used 173 jquery: version, 174 175 constructor: jQuery, 176 177 // The default length of a jQuery object is 0 178 length: 0, 179 180 toArray: function() { 181 return slice.call( this ); 182 }, 183 184 // Get the Nth element in the matched element set OR 185 // Get the whole matched element set as a clean array 186 get: function( num ) { 187 188 // Return all the elements in a clean array 189 if ( num == null ) { 190 return slice.call( this ); 191 } 192 193 // Return just the one element from the set 194 return num < 0 ? this[ num + this.length ] : this[ num ]; 195 }, 196 197 // Take an array of elements and push it onto the stack 198 // (returning the new matched element set) 199 pushStack: function( elems ) { 200 201 // Build a new jQuery matched element set 202 var ret = jQuery.merge( this.constructor(), elems ); 203 204 // Add the old object onto the stack (as a reference) 205 ret.prevObject = this; 206 207 // Return the newly-formed element set 208 return ret; 209 }, 210 211 // Execute a callback for every element in the matched set. 212 each: function( callback ) { 213 return jQuery.each( this, callback ); 214 }, 215 216 map: function( callback ) { 217 return this.pushStack( jQuery.map( this, function( elem, i ) { 218 return callback.call( elem, i, elem ); 219 } ) ); 220 }, 221 222 slice: function() { 223 return this.pushStack( slice.apply( this, arguments ) ); 224 }, 225 226 first: function() { 227 return this.eq( 0 ); 228 }, 229 230 last: function() { 231 return this.eq( -1 ); 232 }, 233 234 even: function() { 235 return this.pushStack( jQuery.grep( this, function( _elem, i ) { 236 return ( i + 1 ) % 2; 237 } ) ); 238 }, 239 240 odd: function() { 241 return this.pushStack( jQuery.grep( this, function( _elem, i ) { 242 return i % 2; 243 } ) ); 244 }, 245 246 eq: function( i ) { 247 var len = this.length, 248 j = +i + ( i < 0 ? len : 0 ); 249 return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); 250 }, 251 252 end: function() { 253 return this.prevObject || this.constructor(); 254 }, 255 256 // For internal use only. 257 // Behaves like an Array's method, not like a jQuery method. 258 push: push, 259 sort: arr.sort, 260 splice: arr.splice 261}; 262 263jQuery.extend = jQuery.fn.extend = function() { 264 var options, name, src, copy, copyIsArray, clone, 265 target = arguments[ 0 ] || {}, 266 i = 1, 267 length = arguments.length, 268 deep = false;
vendor: 78,348 bytes, lines 269-3092
269 270 // Handle a deep copy situation 271 if ( typeof target === "boolean" ) { 272 deep = target; 273 274 // Skip the boolean and the target 275 target = arguments[ i ] || {}; 276 i++; 277 } 278 279 // Handle case when target is a string or something (possible in deep copy) 280 if ( typeof target !== "object" && !isFunction( target ) ) { 281 target = {}; 282 } 283 284 // Extend jQuery itself if only one argument is passed 285 if ( i === length ) { 286 target = this; 287 i--; 288 } 289 290 for ( ; i < length; i++ ) { 291 292 // Only deal with non-null/undefined values 293 if ( ( options = arguments[ i ] ) != null ) { 294 295 // Extend the base object 296 for ( name in options ) { 297 copy = options[ name ]; 298 299 // Prevent Object.prototype pollution 300 // Prevent never-ending loop 301 if ( name === "__proto__" || target === copy ) { 302 continue; 303 } 304 305 // Recurse if we're merging plain objects or arrays 306 if ( deep && copy && ( jQuery.isPlainObject( copy ) || 307 ( copyIsArray = Array.isArray( copy ) ) ) ) { 308 src = target[ name ]; 309 310 // Ensure proper type for the source value 311 if ( copyIsArray && !Array.isArray( src ) ) { 312 clone = []; 313 } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { 314 clone = {}; 315 } else { 316 clone = src; 317 } 318 copyIsArray = false; 319 320 // Never move original objects, clone them 321 target[ name ] = jQuery.extend( deep, clone, copy ); 322 323 // Don't bring in undefined values 324 } else if ( copy !== undefined ) { 325 target[ name ] = copy; 326 } 327 } 328 } 329 } 330 331 // Return the modified object 332 return target; 333}; 334 335jQuery.extend( { 336 337 // Unique for each copy of jQuery on the page 338 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 339 340 // Assume jQuery is ready without the ready module 341 isReady: true, 342 343 error: function( msg ) { 344 throw new Error( msg ); 345 }, 346 347 noop: function() {}, 348 349 isPlainObject: function( obj ) { 350 var proto, Ctor; 351 352 // Detect obvious negatives 353 // Use toString instead of jQuery.type to catch host objects 354 if ( !obj || toString.call( obj ) !== "[object Object]" ) { 355 return false; 356 } 357 358 proto = getProto( obj ); 359 360 // Objects with no prototype (e.g., `Object.create( null )`) are plain 361 if ( !proto ) { 362 return true; 363 } 364 365 // Objects with prototype are plain iff they were constructed by a global Object function 366 Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; 367 return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; 368 }, 369 370 isEmptyObject: function( obj ) { 371 var name; 372 373 for ( name in obj ) { 374 return false; 375 } 376 return true; 377 }, 378 379 // Evaluates a script in a provided context; falls back to the global one 380 // if not specified. 381 globalEval: function( code, options, doc ) { 382 DOMEval( code, { nonce: options && options.nonce }, doc ); 383 }, 384 385 each: function( obj, callback ) { 386 var length, i = 0; 387 388 if ( isArrayLike( obj ) ) { 389 length = obj.length; 390 for ( ; i < length; i++ ) { 391 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 392 break; 393 } 394 } 395 } else { 396 for ( i in obj ) { 397 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 398 break; 399 } 400 } 401 } 402 403 return obj; 404 }, 405 406 // results is for internal usage only 407 makeArray: function( arr, results ) { 408 var ret = results || []; 409 410 if ( arr != null ) { 411 if ( isArrayLike( Object( arr ) ) ) { 412 jQuery.merge( ret, 413 typeof arr === "string" ? 414 [ arr ] : arr 415 ); 416 } else { 417 push.call( ret, arr ); 418 } 419 } 420 421 return ret; 422 }, 423 424 inArray: function( elem, arr, i ) { 425 return arr == null ? -1 : indexOf.call( arr, elem, i ); 426 }, 427 428 // Support: Android <=4.0 only, PhantomJS 1 only 429 // push.apply(_, arraylike) throws on ancient WebKit 430 merge: function( first, second ) { 431 var len = +second.length, 432 j = 0, 433 i = first.length; 434 435 for ( ; j < len; j++ ) { 436 first[ i++ ] = second[ j ]; 437 } 438 439 first.length = i; 440 441 return first; 442 }, 443 444 grep: function( elems, callback, invert ) { 445 var callbackInverse, 446 matches = [], 447 i = 0, 448 length = elems.length, 449 callbackExpect = !invert; 450 451 // Go through the array, only saving the items 452 // that pass the validator function 453 for ( ; i < length; i++ ) { 454 callbackInverse = !callback( elems[ i ], i ); 455 if ( callbackInverse !== callbackExpect ) { 456 matches.push( elems[ i ] ); 457 } 458 } 459 460 return matches; 461 }, 462 463 // arg is for internal usage only 464 map: function( elems, callback, arg ) { 465 var length, value, 466 i = 0, 467 ret = []; 468 469 // Go through the array, translating each of the items to their new values 470 if ( isArrayLike( elems ) ) { 471 length = elems.length; 472 for ( ; i < length; i++ ) { 473 value = callback( elems[ i ], i, arg ); 474 475 if ( value != null ) { 476 ret.push( value ); 477 } 478 } 479 480 // Go through every key on the object, 481 } else { 482 for ( i in elems ) { 483 value = callback( elems[ i ], i, arg ); 484 485 if ( value != null ) { 486 ret.push( value ); 487 } 488 } 489 } 490 491 // Flatten any nested arrays 492 return flat( ret ); 493 }, 494 495 // A global GUID counter for objects 496 guid: 1, 497 498 // jQuery.support is not used in Core but other projects attach their 499 // properties to it so it needs to exist. 500 support: support 501} ); 502 503if ( typeof Symbol === "function" ) { 504 jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; 505} 506 507// Populate the class2type map 508jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), 509 function( _i, name ) { 510 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 511 } ); 512 513function isArrayLike( obj ) { 514 515 // Support: real iOS 8.2 only (not reproducible in simulator) 516 // `in` check used to prevent JIT error (gh-2145) 517 // hasOwn isn't used here due to false negatives 518 // regarding Nodelist length in IE 519 var length = !!obj && "length" in obj && obj.length, 520 type = toType( obj ); 521 522 if ( isFunction( obj ) || isWindow( obj ) ) { 523 return false; 524 } 525 526 return type === "array" || length === 0 || 527 typeof length === "number" && length > 0 && ( length - 1 ) in obj; 528} 529var Sizzle = 530/*! 531 * Sizzle CSS Selector Engine v2.3.6 532 * https://sizzlejs.com/ 533 * 534 * Copyright JS Foundation and other contributors 535 * Released under the MIT license 536 * https://js.foundation/ 537 * 538 * Date: 2021-02-16 539 */ 540( function( window ) { 541var i, 542 support, 543 Expr, 544 getText, 545 isXML, 546 tokenize, 547 compile, 548 select, 549 outermostContext, 550 sortInput, 551 hasDuplicate, 552 553 // Local document vars 554 setDocument, 555 document, 556 docElem, 557 documentIsHTML, 558 rbuggyQSA, 559 rbuggyMatches, 560 matches, 561 contains, 562 563 // Instance-specific data 564 expando = "sizzle" + 1 * new Date(), 565 preferredDoc = window.document, 566 dirruns = 0, 567 done = 0, 568 classCache = createCache(), 569 tokenCache = createCache(), 570 compilerCache = createCache(), 571 nonnativeSelectorCache = createCache(), 572 sortOrder = function( a, b ) { 573 if ( a === b ) { 574 hasDuplicate = true; 575 } 576 return 0; 577 }, 578 579 // Instance methods 580 hasOwn = ( {} ).hasOwnProperty, 581 arr = [], 582 pop = arr.pop, 583 pushNative = arr.push, 584 push = arr.push, 585 slice = arr.slice, 586 587 // Use a stripped-down indexOf as it's faster than native 588 // https://jsperf.com/thor-indexof-vs-for/5 589 indexOf = function( list, elem ) { 590 var i = 0, 591 len = list.length; 592 for ( ; i < len; i++ ) { 593 if ( list[ i ] === elem ) { 594 return i; 595 } 596 } 597 return -1; 598 }, 599 600 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + 601 "ismap|loop|multiple|open|readonly|required|scoped", 602 603 // Regular expressions 604 605 // http://www.w3.org/TR/css3-selectors/#whitespace 606 whitespace = "[\\x20\\t\\r\\n\\f]", 607 608 // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram 609 identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + 610 "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", 611 612 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors 613 attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + 614 615 // Operator (capture 2) 616 "*([*^$|!~]?=)" + whitespace + 617 618 // "Attribute values must be CSS identifiers [capture 5] 619 // or strings [capture 3 or capture 4]" 620 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + 621 whitespace + "*\\]", 622 623 pseudos = ":(" + identifier + ")(?:\\((" + 624 625 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: 626 // 1. quoted (capture 3; capture 4 or capture 5) 627 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + 628 629 // 2. simple (capture 6) 630 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + 631 632 // 3. anything else (capture 2) 633 ".*" + 634 ")\\)|)", 635 636 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter 637 rwhitespace = new RegExp( whitespace + "+", "g" ), 638 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + 639 whitespace + "+$", "g" ), 640 641 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), 642 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + 643 "*" ), 644 rdescend = new RegExp( whitespace + "|>" ), 645 646 rpseudo = new RegExp( pseudos ), 647 ridentifier = new RegExp( "^" + identifier + "$" ), 648 649 matchExpr = { 650 "ID": new RegExp( "^#(" + identifier + ")" ), 651 "CLASS": new RegExp( "^\\.(" + identifier + ")" ), 652 "TAG": new RegExp( "^(" + identifier + "|[*])" ), 653 "ATTR": new RegExp( "^" + attributes ), 654 "PSEUDO": new RegExp( "^" + pseudos ), 655 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + 656 whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + 657 whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), 658 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), 659 660 // For use in libraries implementing .is() 661 // We use this for POS matching in `select` 662 "needsContext": new RegExp( "^" + whitespace + 663 "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + 664 "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) 665 }, 666 667 rhtml = /HTML$/i, 668 rinputs = /^(?:input|select|textarea|button)$/i, 669 rheader = /^h\d$/i, 670 671 rnative = /^[^{]+\{\s*\[native \w/, 672 673 // Easily-parseable/retrievable ID or TAG or CLASS selectors 674 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, 675 676 rsibling = /[+~]/, 677 678 // CSS escapes 679 // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters 680 runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), 681 funescape = function( escape, nonHex ) { 682 var high = "0x" + escape.slice( 1 ) - 0x10000; 683 684 return nonHex ? 685 686 // Strip the backslash prefix from a non-hex escape sequence 687 nonHex : 688 689 // Replace a hexadecimal escape sequence with the encoded Unicode code point 690 // Support: IE <=11+ 691 // For values outside the Basic Multilingual Plane (BMP), manually construct a 692 // surrogate pair 693 high < 0 ? 694 String.fromCharCode( high + 0x10000 ) : 695 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); 696 }, 697 698 // CSS string/identifier serialization 699 // https://drafts.csswg.org/cssom/#common-serializing-idioms 700 rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, 701 fcssescape = function( ch, asCodePoint ) { 702 if ( asCodePoint ) { 703 704 // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER 705 if ( ch === "\0" ) { 706 return "\uFFFD"; 707 } 708 709 // Control characters and (dependent upon position) numbers get escaped as code points 710 return ch.slice( 0, -1 ) + "\\" + 711 ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; 712 } 713 714 // Other potentially-special ASCII characters get backslash-escaped 715 return "\\" + ch; 716 }, 717 718 // Used for iframes 719 // See setDocument() 720 // Removing the function wrapper causes a "Permission Denied" 721 // error in IE 722 unloadHandler = function() { 723 setDocument(); 724 }, 725 726 inDisabledFieldset = addCombinator( 727 function( elem ) { 728 return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; 729 }, 730 { dir: "parentNode", next: "legend" } 731 ); 732 733// Optimize for push.apply( _, NodeList ) 734try { 735 push.apply( 736 ( arr = slice.call( preferredDoc.childNodes ) ), 737 preferredDoc.childNodes 738 ); 739 740 // Support: Android<4.0 741 // Detect silently failing push.apply 742 // eslint-disable-next-line no-unused-expressions 743 arr[ preferredDoc.childNodes.length ].nodeType; 744} catch ( e ) { 745 push = { apply: arr.length ? 746 747 // Leverage slice if possible 748 function( target, els ) { 749 pushNative.apply( target, slice.call( els ) ); 750 } : 751 752 // Support: IE<9 753 // Otherwise append directly 754 function( target, els ) { 755 var j = target.length, 756 i = 0; 757 758 // Can't trust NodeList.length 759 while ( ( target[ j++ ] = els[ i++ ] ) ) {} 760 target.length = j - 1; 761 } 762 }; 763} 764 765function Sizzle( selector, context, results, seed ) { 766 var m, i, elem, nid, match, groups, newSelector, 767 newContext = context && context.ownerDocument, 768 769 // nodeType defaults to 9, since context defaults to document 770 nodeType = context ? context.nodeType : 9; 771 772 results = results || []; 773 774 // Return early from calls with invalid selector or context 775 if ( typeof selector !== "string" || !selector || 776 nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { 777 778 return results; 779 } 780 781 // Try to shortcut find operations (as opposed to filters) in HTML documents 782 if ( !seed ) { 783 setDocument( context ); 784 context = context || document; 785 786 if ( documentIsHTML ) { 787 788 // If the selector is sufficiently simple, try using a "get*By*" DOM method 789 // (excepting DocumentFragment context, where the methods don't exist) 790 if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { 791 792 // ID selector 793 if ( ( m = match[ 1 ] ) ) { 794 795 // Document context 796 if ( nodeType === 9 ) { 797 if ( ( elem = context.getElementById( m ) ) ) { 798 799 // Support: IE, Opera, Webkit 800 // TODO: identify versions 801 // getElementById can match elements by name instead of ID 802 if ( elem.id === m ) { 803 results.push( elem ); 804 return results; 805 } 806 } else { 807 return results; 808 } 809 810 // Element context 811 } else { 812 813 // Support: IE, Opera, Webkit 814 // TODO: identify versions 815 // getElementById can match elements by name instead of ID 816 if ( newContext && ( elem = newContext.getElementById( m ) ) && 817 contains( context, elem ) && 818 elem.id === m ) { 819 820 results.push( elem ); 821 return results; 822 } 823 } 824 825 // Type selector 826 } else if ( match[ 2 ] ) { 827 push.apply( results, context.getElementsByTagName( selector ) ); 828 return results; 829 830 // Class selector 831 } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && 832 context.getElementsByClassName ) { 833 834 push.apply( results, context.getElementsByClassName( m ) ); 835 return results; 836 } 837 } 838 839 // Take advantage of querySelectorAll 840 if ( support.qsa && 841 !nonnativeSelectorCache[ selector + " " ] && 842 ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && 843 844 // Support: IE 8 only 845 // Exclude object elements 846 ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { 847 848 newSelector = selector; 849 newContext = context; 850 851 // qSA considers elements outside a scoping root when evaluating child or 852 // descendant combinators, which is not what we want. 853 // In such cases, we work around the behavior by prefixing every selector in the 854 // list with an ID selector referencing the scope context. 855 // The technique has to be used as well when a leading combinator is used 856 // as such selectors are not recognized by querySelectorAll. 857 // Thanks to Andrew Dupont for this technique. 858 if ( nodeType === 1 && 859 ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { 860 861 // Expand context for sibling selectors 862 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || 863 context; 864 865 // We can use :scope instead of the ID hack if the browser 866 // supports it & if we're not changing the context. 867 if ( newContext !== context || !support.scope ) { 868 869 // Capture the context ID, setting it first if necessary 870 if ( ( nid = context.getAttribute( "id" ) ) ) { 871 nid = nid.replace( rcssescape, fcssescape ); 872 } else { 873 context.setAttribute( "id", ( nid = expando ) ); 874 } 875 } 876 877 // Prefix every selector in the list 878 groups = tokenize( selector ); 879 i = groups.length; 880 while ( i-- ) { 881 groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + 882 toSelector( groups[ i ] ); 883 } 884 newSelector = groups.join( "," ); 885 } 886 887 try { 888 push.apply( results, 889 newContext.querySelectorAll( newSelector ) 890 ); 891 return results; 892 } catch ( qsaError ) { 893 nonnativeSelectorCache( selector, true ); 894 } finally { 895 if ( nid === expando ) { 896 context.removeAttribute( "id" ); 897 } 898 } 899 } 900 } 901 } 902 903 // All others 904 return select( selector.replace( rtrim, "$1" ), context, results, seed ); 905} 906 907/** 908 * Create key-value caches of limited size 909 * @returns {function(string, object)} Returns the Object data after storing it on itself with 910 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) 911 * deleting the oldest entry 912 */ 913function createCache() { 914 var keys = []; 915 916 function cache( key, value ) { 917 918 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) 919 if ( keys.push( key + " " ) > Expr.cacheLength ) { 920 921 // Only keep the most recent entries 922 delete cache[ keys.shift() ]; 923 } 924 return ( cache[ key + " " ] = value ); 925 } 926 return cache; 927} 928 929/** 930 * Mark a function for special use by Sizzle 931 * @param {Function} fn The function to mark 932 */ 933function markFunction( fn ) { 934 fn[ expando ] = true; 935 return fn; 936} 937 938/** 939 * Support testing using an element 940 * @param {Function} fn Passed the created element and returns a boolean result 941 */ 942function assert( fn ) { 943 var el = document.createElement( "fieldset" ); 944 945 try { 946 return !!fn( el ); 947 } catch ( e ) { 948 return false; 949 } finally { 950 951 // Remove from its parent by default 952 if ( el.parentNode ) { 953 el.parentNode.removeChild( el ); 954 } 955 956 // release memory in IE 957 el = null; 958 } 959} 960 961/** 962 * Adds the same handler for all of the specified attrs 963 * @param {String} attrs Pipe-separated list of attributes 964 * @param {Function} handler The method that will be applied 965 */ 966function addHandle( attrs, handler ) { 967 var arr = attrs.split( "|" ), 968 i = arr.length; 969 970 while ( i-- ) { 971 Expr.attrHandle[ arr[ i ] ] = handler; 972 } 973} 974 975/** 976 * Checks document order of two siblings 977 * @param {Element} a 978 * @param {Element} b 979 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b 980 */ 981function siblingCheck( a, b ) { 982 var cur = b && a, 983 diff = cur && a.nodeType === 1 && b.nodeType === 1 && 984 a.sourceIndex - b.sourceIndex; 985 986 // Use IE sourceIndex if available on both nodes 987 if ( diff ) { 988 return diff; 989 } 990 991 // Check if b follows a 992 if ( cur ) { 993 while ( ( cur = cur.nextSibling ) ) { 994 if ( cur === b ) { 995 return -1; 996 } 997 } 998 } 999 1000 return a ? 1 : -1; 1001} 1002 1003/** 1004 * Returns a function to use in pseudos for input types 1005 * @param {String} type 1006 */ 1007function createInputPseudo( type ) { 1008 return function( elem ) { 1009 var name = elem.nodeName.toLowerCase(); 1010 return name === "input" && elem.type === type; 1011 }; 1012} 1013 1014/** 1015 * Returns a function to use in pseudos for buttons 1016 * @param {String} type 1017 */ 1018function createButtonPseudo( type ) { 1019 return function( elem ) { 1020 var name = elem.nodeName.toLowerCase(); 1021 return ( name === "input" || name === "button" ) && elem.type === type; 1022 }; 1023} 1024 1025/** 1026 * Returns a function to use in pseudos for :enabled/:disabled 1027 * @param {Boolean} disabled true for :disabled; false for :enabled 1028 */ 1029function createDisabledPseudo( disabled ) { 1030 1031 // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable 1032 return function( elem ) { 1033 1034 // Only certain elements can match :enabled or :disabled 1035 // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled 1036 // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled 1037 if ( "form" in elem ) { 1038 1039 // Check for inherited disabledness on relevant non-disabled elements: 1040 // * listed form-associated elements in a disabled fieldset 1041 // https://html.spec.whatwg.org/multipage/forms.html#category-listed 1042 // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled 1043 // * option elements in a disabled optgroup 1044 // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled 1045 // All such elements have a "form" property. 1046 if ( elem.parentNode && elem.disabled === false ) { 1047 1048 // Option elements defer to a parent optgroup if present 1049 if ( "label" in elem ) { 1050 if ( "label" in elem.parentNode ) { 1051 return elem.parentNode.disabled === disabled; 1052 } else { 1053 return elem.disabled === disabled; 1054 } 1055 } 1056 1057 // Support: IE 6 - 11 1058 // Use the isDisabled shortcut property to check for disabled fieldset ancestors 1059 return elem.isDisabled === disabled || 1060 1061 // Where there is no isDisabled, check manually 1062 /* jshint -W018 */ 1063 elem.isDisabled !== !disabled && 1064 inDisabledFieldset( elem ) === disabled; 1065 } 1066 1067 return elem.disabled === disabled; 1068 1069 // Try to winnow out elements that can't be disabled before trusting the disabled property. 1070 // Some victims get caught in our net (label, legend, menu, track), but it shouldn't 1071 // even exist on them, let alone have a boolean value. 1072 } else if ( "label" in elem ) { 1073 return elem.disabled === disabled; 1074 } 1075 1076 // Remaining elements are neither :enabled nor :disabled 1077 return false; 1078 }; 1079} 1080 1081/** 1082 * Returns a function to use in pseudos for positionals 1083 * @param {Function} fn 1084 */ 1085function createPositionalPseudo( fn ) { 1086 return markFunction( function( argument ) { 1087 argument = +argument; 1088 return markFunction( function( seed, matches ) { 1089 var j, 1090 matchIndexes = fn( [], seed.length, argument ), 1091 i = matchIndexes.length; 1092 1093 // Match elements found at the specified indexes 1094 while ( i-- ) { 1095 if ( seed[ ( j = matchIndexes[ i ] ) ] ) { 1096 seed[ j ] = !( matches[ j ] = seed[ j ] ); 1097 } 1098 } 1099 } ); 1100 } ); 1101} 1102 1103/** 1104 * Checks a node for validity as a Sizzle context 1105 * @param {Element|Object=} context 1106 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value 1107 */ 1108function testContext( context ) { 1109 return context && typeof context.getElementsByTagName !== "undefined" && context; 1110} 1111 1112// Expose support vars for convenience 1113support = Sizzle.support = {}; 1114 1115/** 1116 * Detects XML nodes 1117 * @param {Element|Object} elem An element or a document 1118 * @returns {Boolean} True iff elem is a non-HTML XML node 1119 */ 1120isXML = Sizzle.isXML = function( elem ) { 1121 var namespace = elem && elem.namespaceURI, 1122 docElem = elem && ( elem.ownerDocument || elem ).documentElement; 1123 1124 // Support: IE <=8 1125 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes 1126 // https://bugs.jquery.com/ticket/4833 1127 return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); 1128}; 1129 1130/** 1131 * Sets document-related variables once based on the current document 1132 * @param {Element|Object} [doc] An element or document object to use to set the document 1133 * @returns {Object} Returns the current document 1134 */ 1135setDocument = Sizzle.setDocument = function( node ) { 1136 var hasCompare, subWindow, 1137 doc = node ? node.ownerDocument || node : preferredDoc; 1138 1139 // Return early if doc is invalid or already selected 1140 // Support: IE 11+, Edge 17 - 18+ 1141 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1142 // two documents; shallow comparisons work. 1143 // eslint-disable-next-line eqeqeq 1144 if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { 1145 return document; 1146 } 1147 1148 // Update global variables 1149 document = doc; 1150 docElem = document.documentElement; 1151 documentIsHTML = !isXML( document ); 1152 1153 // Support: IE 9 - 11+, Edge 12 - 18+ 1154 // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) 1155 // Support: IE 11+, Edge 17 - 18+ 1156 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1157 // two documents; shallow comparisons work. 1158 // eslint-disable-next-line eqeqeq 1159 if ( preferredDoc != document && 1160 ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { 1161 1162 // Support: IE 11, Edge 1163 if ( subWindow.addEventListener ) { 1164 subWindow.addEventListener( "unload", unloadHandler, false ); 1165 1166 // Support: IE 9 - 10 only 1167 } else if ( subWindow.attachEvent ) { 1168 subWindow.attachEvent( "onunload", unloadHandler ); 1169 } 1170 } 1171 1172 // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, 1173 // Safari 4 - 5 only, Opera <=11.6 - 12.x only 1174 // IE/Edge & older browsers don't support the :scope pseudo-class. 1175 // Support: Safari 6.0 only 1176 // Safari 6.0 supports :scope but it's an alias of :root there. 1177 support.scope = assert( function( el ) { 1178 docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); 1179 return typeof el.querySelectorAll !== "undefined" && 1180 !el.querySelectorAll( ":scope fieldset div" ).length; 1181 } ); 1182 1183 /* Attributes 1184 ---------------------------------------------------------------------- */ 1185 1186 // Support: IE<8 1187 // Verify that getAttribute really returns attributes and not properties 1188 // (excepting IE8 booleans) 1189 support.attributes = assert( function( el ) { 1190 el.className = "i"; 1191 return !el.getAttribute( "className" ); 1192 } ); 1193 1194 /* getElement(s)By* 1195 ---------------------------------------------------------------------- */ 1196 1197 // Check if getElementsByTagName("*") returns only elements 1198 support.getElementsByTagName = assert( function( el ) { 1199 el.appendChild( document.createComment( "" ) ); 1200 return !el.getElementsByTagName( "*" ).length; 1201 } ); 1202 1203 // Support: IE<9 1204 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); 1205 1206 // Support: IE<10 1207 // Check if getElementById returns elements by name 1208 // The broken getElementById methods don't pick up programmatically-set names, 1209 // so use a roundabout getElementsByName test 1210 support.getById = assert( function( el ) { 1211 docElem.appendChild( el ).id = expando; 1212 return !document.getElementsByName || !document.getElementsByName( expando ).length; 1213 } ); 1214 1215 // ID filter and find 1216 if ( support.getById ) { 1217 Expr.filter[ "ID" ] = function( id ) { 1218 var attrId = id.replace( runescape, funescape ); 1219 return function( elem ) { 1220 return elem.getAttribute( "id" ) === attrId; 1221 }; 1222 }; 1223 Expr.find[ "ID" ] = function( id, context ) { 1224 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { 1225 var elem = context.getElementById( id ); 1226 return elem ? [ elem ] : []; 1227 } 1228 }; 1229 } else { 1230 Expr.filter[ "ID" ] = function( id ) { 1231 var attrId = id.replace( runescape, funescape ); 1232 return function( elem ) { 1233 var node = typeof elem.getAttributeNode !== "undefined" && 1234 elem.getAttributeNode( "id" ); 1235 return node && node.value === attrId; 1236 }; 1237 }; 1238 1239 // Support: IE 6 - 7 only 1240 // getElementById is not reliable as a find shortcut 1241 Expr.find[ "ID" ] = function( id, context ) { 1242 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { 1243 var node, i, elems, 1244 elem = context.getElementById( id ); 1245 1246 if ( elem ) { 1247 1248 // Verify the id attribute 1249 node = elem.getAttributeNode( "id" ); 1250 if ( node && node.value === id ) { 1251 return [ elem ]; 1252 } 1253 1254 // Fall back on getElementsByName 1255 elems = context.getElementsByName( id ); 1256 i = 0; 1257 while ( ( elem = elems[ i++ ] ) ) { 1258 node = elem.getAttributeNode( "id" ); 1259 if ( node && node.value === id ) { 1260 return [ elem ]; 1261 } 1262 } 1263 } 1264 1265 return []; 1266 } 1267 }; 1268 } 1269 1270 // Tag 1271 Expr.find[ "TAG" ] = support.getElementsByTagName ? 1272 function( tag, context ) { 1273 if ( typeof context.getElementsByTagName !== "undefined" ) { 1274 return context.getElementsByTagName( tag ); 1275 1276 // DocumentFragment nodes don't have gEBTN 1277 } else if ( support.qsa ) { 1278 return context.querySelectorAll( tag ); 1279 } 1280 } : 1281 1282 function( tag, context ) { 1283 var elem, 1284 tmp = [], 1285 i = 0, 1286 1287 // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too 1288 results = context.getElementsByTagName( tag ); 1289 1290 // Filter out possible comments 1291 if ( tag === "*" ) { 1292 while ( ( elem = results[ i++ ] ) ) { 1293 if ( elem.nodeType === 1 ) { 1294 tmp.push( elem ); 1295 } 1296 } 1297 1298 return tmp; 1299 } 1300 return results; 1301 }; 1302 1303 // Class 1304 Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { 1305 if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { 1306 return context.getElementsByClassName( className ); 1307 } 1308 }; 1309 1310 /* QSA/matchesSelector 1311 ---------------------------------------------------------------------- */ 1312 1313 // QSA and matchesSelector support 1314 1315 // matchesSelector(:active) reports false when true (IE9/Opera 11.5) 1316 rbuggyMatches = []; 1317 1318 // qSa(:focus) reports false when true (Chrome 21) 1319 // We allow this because of a bug in IE8/9 that throws an error 1320 // whenever `document.activeElement` is accessed on an iframe 1321 // So, we allow :focus to pass through QSA all the time to avoid the IE error 1322 // See https://bugs.jquery.com/ticket/13378 1323 rbuggyQSA = []; 1324 1325 if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { 1326 1327 // Build QSA regex 1328 // Regex strategy adopted from Diego Perini 1329 assert( function( el ) { 1330 1331 var input; 1332 1333 // Select is set to empty string on purpose 1334 // This is to test IE's treatment of not explicitly 1335 // setting a boolean content attribute, 1336 // since its presence should be enough 1337 // https://bugs.jquery.com/ticket/12359 1338 docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" + 1339 "<select id='" + expando + "-\r\\' msallowcapture=''>" + 1340 "<option selected=''></option></select>"; 1341 1342 // Support: IE8, Opera 11-12.16 1343 // Nothing should be selected when empty strings follow ^= or $= or *= 1344 // The test attribute must be unknown in Opera but "safe" for WinRT 1345 // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section 1346 if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { 1347 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); 1348 } 1349 1350 // Support: IE8 1351 // Boolean attributes and "value" are not treated correctly 1352 if ( !el.querySelectorAll( "[selected]" ).length ) { 1353 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); 1354 } 1355 1356 // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ 1357 if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { 1358 rbuggyQSA.push( "~=" ); 1359 } 1360 1361 // Support: IE 11+, Edge 15 - 18+ 1362 // IE 11/Edge don't find elements on a `[name='']` query in some cases. 1363 // Adding a temporary attribute to the document before the selection works 1364 // around the issue. 1365 // Interestingly, IE 10 & older don't seem to have the issue. 1366 input = document.createElement( "input" ); 1367 input.setAttribute( "name", "" ); 1368 el.appendChild( input ); 1369 if ( !el.querySelectorAll( "[name='']" ).length ) { 1370 rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + 1371 whitespace + "*(?:''|\"\")" ); 1372 } 1373 1374 // Webkit/Opera - :checked should return selected option elements 1375 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 1376 // IE8 throws error here and will not see later tests 1377 if ( !el.querySelectorAll( ":checked" ).length ) { 1378 rbuggyQSA.push( ":checked" ); 1379 } 1380 1381 // Support: Safari 8+, iOS 8+ 1382 // https://bugs.webkit.org/show_bug.cgi?id=136851 1383 // In-page `selector#id sibling-combinator selector` fails 1384 if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { 1385 rbuggyQSA.push( ".#.+[+~]" ); 1386 } 1387 1388 // Support: Firefox <=3.6 - 5 only 1389 // Old Firefox doesn't throw on a badly-escaped identifier. 1390 el.querySelectorAll( "\\\f" ); 1391 rbuggyQSA.push( "[\\r\\n\\f]" ); 1392 } ); 1393 1394 assert( function( el ) { 1395 el.innerHTML = "<a href='' disabled='disabled'></a>" + 1396 "<select disabled='disabled'><option/></select>"; 1397 1398 // Support: Windows 8 Native Apps 1399 // The type and name attributes are restricted during .innerHTML assignment 1400 var input = document.createElement( "input" ); 1401 input.setAttribute( "type", "hidden" ); 1402 el.appendChild( input ).setAttribute( "name", "D" ); 1403 1404 // Support: IE8 1405 // Enforce case-sensitivity of name attribute 1406 if ( el.querySelectorAll( "[name=d]" ).length ) { 1407 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); 1408 } 1409 1410 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) 1411 // IE8 throws error here and will not see later tests 1412 if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { 1413 rbuggyQSA.push( ":enabled", ":disabled" ); 1414 } 1415 1416 // Support: IE9-11+ 1417 // IE's :disabled selector does not pick up the children of disabled fieldsets 1418 docElem.appendChild( el ).disabled = true; 1419 if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { 1420 rbuggyQSA.push( ":enabled", ":disabled" ); 1421 } 1422 1423 // Support: Opera 10 - 11 only 1424 // Opera 10-11 does not throw on post-comma invalid pseudos 1425 el.querySelectorAll( "*,:x" ); 1426 rbuggyQSA.push( ",.*:" ); 1427 } ); 1428 } 1429 1430 if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || 1431 docElem.webkitMatchesSelector || 1432 docElem.mozMatchesSelector || 1433 docElem.oMatchesSelector || 1434 docElem.msMatchesSelector ) ) ) ) { 1435 1436 assert( function( el ) { 1437 1438 // Check to see if it's possible to do matchesSelector 1439 // on a disconnected node (IE 9) 1440 support.disconnectedMatch = matches.call( el, "*" ); 1441 1442 // This should fail with an exception 1443 // Gecko does not error, returns false instead 1444 matches.call( el, "[s!='']:x" ); 1445 rbuggyMatches.push( "!=", pseudos ); 1446 } ); 1447 } 1448 1449 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); 1450 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); 1451 1452 /* Contains 1453 ---------------------------------------------------------------------- */ 1454 hasCompare = rnative.test( docElem.compareDocumentPosition ); 1455 1456 // Element contains another 1457 // Purposefully self-exclusive 1458 // As in, an element does not contain itself 1459 contains = hasCompare || rnative.test( docElem.contains ) ? 1460 function( a, b ) { 1461 var adown = a.nodeType === 9 ? a.documentElement : a, 1462 bup = b && b.parentNode; 1463 return a === bup || !!( bup && bup.nodeType === 1 && ( 1464 adown.contains ? 1465 adown.contains( bup ) : 1466 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 1467 ) ); 1468 } : 1469 function( a, b ) { 1470 if ( b ) { 1471 while ( ( b = b.parentNode ) ) { 1472 if ( b === a ) { 1473 return true; 1474 } 1475 } 1476 } 1477 return false; 1478 }; 1479 1480 /* Sorting 1481 ---------------------------------------------------------------------- */ 1482 1483 // Document order sorting 1484 sortOrder = hasCompare ? 1485 function( a, b ) { 1486 1487 // Flag for duplicate removal 1488 if ( a === b ) { 1489 hasDuplicate = true; 1490 return 0; 1491 } 1492 1493 // Sort on method existence if only one input has compareDocumentPosition 1494 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; 1495 if ( compare ) { 1496 return compare; 1497 } 1498 1499 // Calculate position if both inputs belong to the same document 1500 // Support: IE 11+, Edge 17 - 18+ 1501 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1502 // two documents; shallow comparisons work. 1503 // eslint-disable-next-line eqeqeq 1504 compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? 1505 a.compareDocumentPosition( b ) : 1506 1507 // Otherwise we know they are disconnected 1508 1; 1509 1510 // Disconnected nodes 1511 if ( compare & 1 || 1512 ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { 1513 1514 // Choose the first element that is related to our preferred document 1515 // Support: IE 11+, Edge 17 - 18+ 1516 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1517 // two documents; shallow comparisons work. 1518 // eslint-disable-next-line eqeqeq 1519 if ( a == document || a.ownerDocument == preferredDoc && 1520 contains( preferredDoc, a ) ) { 1521 return -1; 1522 } 1523 1524 // Support: IE 11+, Edge 17 - 18+ 1525 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1526 // two documents; shallow comparisons work. 1527 // eslint-disable-next-line eqeqeq 1528 if ( b == document || b.ownerDocument == preferredDoc && 1529 contains( preferredDoc, b ) ) { 1530 return 1; 1531 } 1532 1533 // Maintain original order 1534 return sortInput ? 1535 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 1536 0; 1537 } 1538 1539 return compare & 4 ? -1 : 1; 1540 } : 1541 function( a, b ) { 1542 1543 // Exit early if the nodes are identical 1544 if ( a === b ) { 1545 hasDuplicate = true; 1546 return 0; 1547 } 1548 1549 var cur, 1550 i = 0, 1551 aup = a.parentNode, 1552 bup = b.parentNode, 1553 ap = [ a ], 1554 bp = [ b ]; 1555 1556 // Parentless nodes are either documents or disconnected 1557 if ( !aup || !bup ) { 1558 1559 // Support: IE 11+, Edge 17 - 18+ 1560 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1561 // two documents; shallow comparisons work. 1562 /* eslint-disable eqeqeq */ 1563 return a == document ? -1 : 1564 b == document ? 1 : 1565 /* eslint-enable eqeqeq */ 1566 aup ? -1 : 1567 bup ? 1 : 1568 sortInput ? 1569 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 1570 0; 1571 1572 // If the nodes are siblings, we can do a quick check 1573 } else if ( aup === bup ) { 1574 return siblingCheck( a, b ); 1575 } 1576 1577 // Otherwise we need full lists of their ancestors for comparison 1578 cur = a; 1579 while ( ( cur = cur.parentNode ) ) { 1580 ap.unshift( cur ); 1581 } 1582 cur = b; 1583 while ( ( cur = cur.parentNode ) ) { 1584 bp.unshift( cur ); 1585 } 1586 1587 // Walk down the tree looking for a discrepancy 1588 while ( ap[ i ] === bp[ i ] ) { 1589 i++; 1590 } 1591 1592 return i ? 1593 1594 // Do a sibling check if the nodes have a common ancestor 1595 siblingCheck( ap[ i ], bp[ i ] ) : 1596 1597 // Otherwise nodes in our document sort first 1598 // Support: IE 11+, Edge 17 - 18+ 1599 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1600 // two documents; shallow comparisons work. 1601 /* eslint-disable eqeqeq */ 1602 ap[ i ] == preferredDoc ? -1 : 1603 bp[ i ] == preferredDoc ? 1 : 1604 /* eslint-enable eqeqeq */ 1605 0; 1606 }; 1607 1608 return document; 1609}; 1610 1611Sizzle.matches = function( expr, elements ) { 1612 return Sizzle( expr, null, null, elements ); 1613}; 1614 1615Sizzle.matchesSelector = function( elem, expr ) { 1616 setDocument( elem ); 1617 1618 if ( support.matchesSelector && documentIsHTML && 1619 !nonnativeSelectorCache[ expr + " " ] && 1620 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && 1621 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { 1622 1623 try { 1624 var ret = matches.call( elem, expr ); 1625 1626 // IE 9's matchesSelector returns false on disconnected nodes 1627 if ( ret || support.disconnectedMatch || 1628 1629 // As well, disconnected nodes are said to be in a document 1630 // fragment in IE 9 1631 elem.document && elem.document.nodeType !== 11 ) { 1632 return ret; 1633 } 1634 } catch ( e ) { 1635 nonnativeSelectorCache( expr, true ); 1636 } 1637 } 1638 1639 return Sizzle( expr, document, null, [ elem ] ).length > 0; 1640}; 1641 1642Sizzle.contains = function( context, elem ) { 1643 1644 // Set document vars if needed 1645 // Support: IE 11+, Edge 17 - 18+ 1646 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1647 // two documents; shallow comparisons work. 1648 // eslint-disable-next-line eqeqeq 1649 if ( ( context.ownerDocument || context ) != document ) { 1650 setDocument( context ); 1651 } 1652 return contains( context, elem ); 1653}; 1654 1655Sizzle.attr = function( elem, name ) { 1656 1657 // Set document vars if needed 1658 // Support: IE 11+, Edge 17 - 18+ 1659 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 1660 // two documents; shallow comparisons work. 1661 // eslint-disable-next-line eqeqeq 1662 if ( ( elem.ownerDocument || elem ) != document ) { 1663 setDocument( elem ); 1664 } 1665 1666 var fn = Expr.attrHandle[ name.toLowerCase() ], 1667 1668 // Don't get fooled by Object.prototype properties (jQuery #13807) 1669 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? 1670 fn( elem, name, !documentIsHTML ) : 1671 undefined; 1672 1673 return val !== undefined ? 1674 val : 1675 support.attributes || !documentIsHTML ? 1676 elem.getAttribute( name ) : 1677 ( val = elem.getAttributeNode( name ) ) && val.specified ? 1678 val.value : 1679 null; 1680}; 1681 1682Sizzle.escape = function( sel ) { 1683 return ( sel + "" ).replace( rcssescape, fcssescape ); 1684}; 1685 1686Sizzle.error = function( msg ) { 1687 throw new Error( "Syntax error, unrecognized expression: " + msg ); 1688}; 1689 1690/** 1691 * Document sorting and removing duplicates 1692 * @param {ArrayLike} results 1693 */ 1694Sizzle.uniqueSort = function( results ) { 1695 var elem, 1696 duplicates = [], 1697 j = 0, 1698 i = 0; 1699 1700 // Unless we *know* we can detect duplicates, assume their presence 1701 hasDuplicate = !support.detectDuplicates; 1702 sortInput = !support.sortStable && results.slice( 0 ); 1703 results.sort( sortOrder ); 1704 1705 if ( hasDuplicate ) { 1706 while ( ( elem = results[ i++ ] ) ) { 1707 if ( elem === results[ i ] ) { 1708 j = duplicates.push( i ); 1709 } 1710 } 1711 while ( j-- ) { 1712 results.splice( duplicates[ j ], 1 ); 1713 } 1714 } 1715 1716 // Clear input after sorting to release objects 1717 // See https://github.com/jquery/sizzle/pull/225 1718 sortInput = null; 1719 1720 return results; 1721}; 1722 1723/** 1724 * Utility function for retrieving the text value of an array of DOM nodes 1725 * @param {Array|Element} elem 1726 */ 1727getText = Sizzle.getText = function( elem ) { 1728 var node, 1729 ret = "", 1730 i = 0, 1731 nodeType = elem.nodeType; 1732 1733 if ( !nodeType ) { 1734 1735 // If no nodeType, this is expected to be an array 1736 while ( ( node = elem[ i++ ] ) ) { 1737 1738 // Do not traverse comment nodes 1739 ret += getText( node ); 1740 } 1741 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { 1742 1743 // Use textContent for elements 1744 // innerText usage removed for consistency of new lines (jQuery #11153) 1745 if ( typeof elem.textContent === "string" ) { 1746 return elem.textContent; 1747 } else { 1748 1749 // Traverse its children 1750 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 1751 ret += getText( elem ); 1752 } 1753 } 1754 } else if ( nodeType === 3 || nodeType === 4 ) { 1755 return elem.nodeValue; 1756 } 1757 1758 // Do not include comment or processing instruction nodes 1759 1760 return ret; 1761}; 1762 1763Expr = Sizzle.selectors = { 1764 1765 // Can be adjusted by the user 1766 cacheLength: 50, 1767 1768 createPseudo: markFunction, 1769 1770 match: matchExpr, 1771 1772 attrHandle: {}, 1773 1774 find: {}, 1775 1776 relative: { 1777 ">": { dir: "parentNode", first: true }, 1778 " ": { dir: "parentNode" }, 1779 "+": { dir: "previousSibling", first: true }, 1780 "~": { dir: "previousSibling" } 1781 }, 1782 1783 preFilter: { 1784 "ATTR": function( match ) { 1785 match[ 1 ] = match[ 1 ].replace( runescape, funescape ); 1786 1787 // Move the given value to match[3] whether quoted or unquoted 1788 match[ 3 ] = ( match[ 3 ] || match[ 4 ] || 1789 match[ 5 ] || "" ).replace( runescape, funescape ); 1790 1791 if ( match[ 2 ] === "~=" ) { 1792 match[ 3 ] = " " + match[ 3 ] + " "; 1793 } 1794 1795 return match.slice( 0, 4 ); 1796 }, 1797 1798 "CHILD": function( match ) { 1799 1800 /* matches from matchExpr["CHILD"] 1801 1 type (only|nth|...) 1802 2 what (child|of-type) 1803 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 1804 4 xn-component of xn+y argument ([+-]?\d*n|) 1805 5 sign of xn-component 1806 6 x of xn-component 1807 7 sign of y-component 1808 8 y of y-component 1809 */ 1810 match[ 1 ] = match[ 1 ].toLowerCase(); 1811 1812 if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { 1813 1814 // nth-* requires argument 1815 if ( !match[ 3 ] ) { 1816 Sizzle.error( match[ 0 ] ); 1817 } 1818 1819 // numeric x and y parameters for Expr.filter.CHILD 1820 // remember that false/true cast respectively to 0/1 1821 match[ 4 ] = +( match[ 4 ] ? 1822 match[ 5 ] + ( match[ 6 ] || 1 ) : 1823 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); 1824 match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); 1825 1826 // other types prohibit arguments 1827 } else if ( match[ 3 ] ) { 1828 Sizzle.error( match[ 0 ] ); 1829 } 1830 1831 return match; 1832 }, 1833 1834 "PSEUDO": function( match ) { 1835 var excess, 1836 unquoted = !match[ 6 ] && match[ 2 ]; 1837 1838 if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { 1839 return null; 1840 } 1841 1842 // Accept quoted arguments as-is 1843 if ( match[ 3 ] ) { 1844 match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; 1845 1846 // Strip excess characters from unquoted arguments 1847 } else if ( unquoted && rpseudo.test( unquoted ) && 1848 1849 // Get excess from tokenize (recursively) 1850 ( excess = tokenize( unquoted, true ) ) && 1851 1852 // advance to the next closing parenthesis 1853 ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { 1854 1855 // excess is a negative index 1856 match[ 0 ] = match[ 0 ].slice( 0, excess ); 1857 match[ 2 ] = unquoted.slice( 0, excess ); 1858 } 1859 1860 // Return only captures needed by the pseudo filter method (type and argument) 1861 return match.slice( 0, 3 ); 1862 } 1863 }, 1864 1865 filter: { 1866 1867 "TAG": function( nodeNameSelector ) { 1868 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); 1869 return nodeNameSelector === "*" ? 1870 function() { 1871 return true; 1872 } : 1873 function( elem ) { 1874 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; 1875 }; 1876 }, 1877 1878 "CLASS": function( className ) { 1879 var pattern = classCache[ className + " " ]; 1880 1881 return pattern || 1882 ( pattern = new RegExp( "(^|" + whitespace + 1883 ")" + className + "(" + whitespace + "|$)" ) ) && classCache( 1884 className, function( elem ) { 1885 return pattern.test( 1886 typeof elem.className === "string" && elem.className || 1887 typeof elem.getAttribute !== "undefined" && 1888 elem.getAttribute( "class" ) || 1889 "" 1890 ); 1891 } ); 1892 }, 1893 1894 "ATTR": function( name, operator, check ) { 1895 return function( elem ) { 1896 var result = Sizzle.attr( elem, name ); 1897 1898 if ( result == null ) { 1899 return operator === "!="; 1900 } 1901 if ( !operator ) { 1902 return true; 1903 } 1904 1905 result += ""; 1906 1907 /* eslint-disable max-len */ 1908 1909 return operator === "=" ? result === check : 1910 operator === "!=" ? result !== check : 1911 operator === "^=" ? check && result.indexOf( check ) === 0 : 1912 operator === "*=" ? check && result.indexOf( check ) > -1 : 1913 operator === "$=" ? check && result.slice( -check.length ) === check : 1914 operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : 1915 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : 1916 false; 1917 /* eslint-enable max-len */ 1918 1919 }; 1920 }, 1921 1922 "CHILD": function( type, what, _argument, first, last ) { 1923 var simple = type.slice( 0, 3 ) !== "nth", 1924 forward = type.slice( -4 ) !== "last", 1925 ofType = what === "of-type"; 1926 1927 return first === 1 && last === 0 ? 1928 1929 // Shortcut for :nth-*(n) 1930 function( elem ) { 1931 return !!elem.parentNode; 1932 } : 1933 1934 function( elem, _context, xml ) { 1935 var cache, uniqueCache, outerCache, node, nodeIndex, start, 1936 dir = simple !== forward ? "nextSibling" : "previousSibling", 1937 parent = elem.parentNode, 1938 name = ofType && elem.nodeName.toLowerCase(), 1939 useCache = !xml && !ofType, 1940 diff = false; 1941 1942 if ( parent ) { 1943 1944 // :(first|last|only)-(child|of-type) 1945 if ( simple ) { 1946 while ( dir ) { 1947 node = elem; 1948 while ( ( node = node[ dir ] ) ) { 1949 if ( ofType ? 1950 node.nodeName.toLowerCase() === name : 1951 node.nodeType === 1 ) { 1952 1953 return false; 1954 } 1955 } 1956 1957 // Reverse direction for :only-* (if we haven't yet done so) 1958 start = dir = type === "only" && !start && "nextSibling"; 1959 } 1960 return true; 1961 } 1962 1963 start = [ forward ? parent.firstChild : parent.lastChild ]; 1964 1965 // non-xml :nth-child(...) stores cache data on `parent` 1966 if ( forward && useCache ) { 1967 1968 // Seek `elem` from a previously-cached index 1969 1970 // ...in a gzip-friendly way 1971 node = parent; 1972 outerCache = node[ expando ] || ( node[ expando ] = {} ); 1973 1974 // Support: IE <9 only 1975 // Defend against cloned attroperties (jQuery gh-1709) 1976 uniqueCache = outerCache[ node.uniqueID ] || 1977 ( outerCache[ node.uniqueID ] = {} ); 1978 1979 cache = uniqueCache[ type ] || []; 1980 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 1981 diff = nodeIndex && cache[ 2 ]; 1982 node = nodeIndex && parent.childNodes[ nodeIndex ]; 1983 1984 while ( ( node = ++nodeIndex && node && node[ dir ] || 1985 1986 // Fallback to seeking `elem` from the start 1987 ( diff = nodeIndex = 0 ) || start.pop() ) ) { 1988 1989 // When found, cache indexes on `parent` and break 1990 if ( node.nodeType === 1 && ++diff && node === elem ) { 1991 uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; 1992 break; 1993 } 1994 } 1995 1996 } else { 1997 1998 // Use previously-cached element index if available 1999 if ( useCache ) { 2000 2001 // ...in a gzip-friendly way 2002 node = elem; 2003 outerCache = node[ expando ] || ( node[ expando ] = {} ); 2004 2005 // Support: IE <9 only 2006 // Defend against cloned attroperties (jQuery gh-1709) 2007 uniqueCache = outerCache[ node.uniqueID ] || 2008 ( outerCache[ node.uniqueID ] = {} ); 2009 2010 cache = uniqueCache[ type ] || []; 2011 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 2012 diff = nodeIndex; 2013 } 2014 2015 // xml :nth-child(...) 2016 // or :nth-last-child(...) or :nth(-last)?-of-type(...) 2017 if ( diff === false ) { 2018 2019 // Use the same loop as above to seek `elem` from the start 2020 while ( ( node = ++nodeIndex && node && node[ dir ] || 2021 ( diff = nodeIndex = 0 ) || start.pop() ) ) { 2022 2023 if ( ( ofType ? 2024 node.nodeName.toLowerCase() === name : 2025 node.nodeType === 1 ) && 2026 ++diff ) { 2027 2028 // Cache the index of each encountered element 2029 if ( useCache ) { 2030 outerCache = node[ expando ] || 2031 ( node[ expando ] = {} ); 2032 2033 // Support: IE <9 only 2034 // Defend against cloned attroperties (jQuery gh-1709) 2035 uniqueCache = outerCache[ node.uniqueID ] || 2036 ( outerCache[ node.uniqueID ] = {} ); 2037 2038 uniqueCache[ type ] = [ dirruns, diff ]; 2039 } 2040 2041 if ( node === elem ) { 2042 break; 2043 } 2044 } 2045 } 2046 } 2047 } 2048 2049 // Incorporate the offset, then check against cycle size 2050 diff -= last; 2051 return diff === first || ( diff % first === 0 && diff / first >= 0 ); 2052 } 2053 }; 2054 }, 2055 2056 "PSEUDO": function( pseudo, argument ) { 2057 2058 // pseudo-class names are case-insensitive 2059 // http://www.w3.org/TR/selectors/#pseudo-classes 2060 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters 2061 // Remember that setFilters inherits from pseudos 2062 var args, 2063 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || 2064 Sizzle.error( "unsupported pseudo: " + pseudo ); 2065 2066 // The user may use createPseudo to indicate that 2067 // arguments are needed to create the filter function 2068 // just as Sizzle does 2069 if ( fn[ expando ] ) { 2070 return fn( argument ); 2071 } 2072 2073 // But maintain support for old signatures 2074 if ( fn.length > 1 ) { 2075 args = [ pseudo, pseudo, "", argument ]; 2076 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? 2077 markFunction( function( seed, matches ) { 2078 var idx, 2079 matched = fn( seed, argument ), 2080 i = matched.length; 2081 while ( i-- ) { 2082 idx = indexOf( seed, matched[ i ] ); 2083 seed[ idx ] = !( matches[ idx ] = matched[ i ] ); 2084 } 2085 } ) : 2086 function( elem ) { 2087 return fn( elem, 0, args ); 2088 }; 2089 } 2090 2091 return fn; 2092 } 2093 }, 2094 2095 pseudos: { 2096 2097 // Potentially complex pseudos 2098 "not": markFunction( function( selector ) { 2099 2100 // Trim the selector passed to compile 2101 // to avoid treating leading and trailing 2102 // spaces as combinators 2103 var input = [], 2104 results = [], 2105 matcher = compile( selector.replace( rtrim, "$1" ) ); 2106 2107 return matcher[ expando ] ? 2108 markFunction( function( seed, matches, _context, xml ) { 2109 var elem, 2110 unmatched = matcher( seed, null, xml, [] ), 2111 i = seed.length; 2112 2113 // Match elements unmatched by `matcher` 2114 while ( i-- ) { 2115 if ( ( elem = unmatched[ i ] ) ) { 2116 seed[ i ] = !( matches[ i ] = elem ); 2117 } 2118 } 2119 } ) : 2120 function( elem, _context, xml ) { 2121 input[ 0 ] = elem; 2122 matcher( input, null, xml, results ); 2123 2124 // Don't keep the element (issue #299) 2125 input[ 0 ] = null; 2126 return !results.pop(); 2127 }; 2128 } ), 2129 2130 "has": markFunction( function( selector ) { 2131 return function( elem ) { 2132 return Sizzle( selector, elem ).length > 0; 2133 }; 2134 } ), 2135 2136 "contains": markFunction( function( text ) { 2137 text = text.replace( runescape, funescape ); 2138 return function( elem ) { 2139 return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; 2140 }; 2141 } ), 2142 2143 // "Whether an element is represented by a :lang() selector 2144 // is based solely on the element's language value 2145 // being equal to the identifier C, 2146 // or beginning with the identifier C immediately followed by "-". 2147 // The matching of C against the element's language value is performed case-insensitively. 2148 // The identifier C does not have to be a valid language name." 2149 // http://www.w3.org/TR/selectors/#lang-pseudo 2150 "lang": markFunction( function( lang ) { 2151 2152 // lang value must be a valid identifier 2153 if ( !ridentifier.test( lang || "" ) ) { 2154 Sizzle.error( "unsupported lang: " + lang ); 2155 } 2156 lang = lang.replace( runescape, funescape ).toLowerCase(); 2157 return function( elem ) { 2158 var elemLang; 2159 do { 2160 if ( ( elemLang = documentIsHTML ? 2161 elem.lang : 2162 elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { 2163 2164 elemLang = elemLang.toLowerCase(); 2165 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; 2166 } 2167 } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); 2168 return false; 2169 }; 2170 } ), 2171 2172 // Miscellaneous 2173 "target": function( elem ) { 2174 var hash = window.location && window.location.hash; 2175 return hash && hash.slice( 1 ) === elem.id; 2176 }, 2177 2178 "root": function( elem ) { 2179 return elem === docElem; 2180 }, 2181 2182 "focus": function( elem ) { 2183 return elem === document.activeElement && 2184 ( !document.hasFocus || document.hasFocus() ) && 2185 !!( elem.type || elem.href || ~elem.tabIndex ); 2186 }, 2187 2188 // Boolean properties 2189 "enabled": createDisabledPseudo( false ), 2190 "disabled": createDisabledPseudo( true ), 2191 2192 "checked": function( elem ) { 2193 2194 // In CSS3, :checked should return both checked and selected elements 2195 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 2196 var nodeName = elem.nodeName.toLowerCase(); 2197 return ( nodeName === "input" && !!elem.checked ) || 2198 ( nodeName === "option" && !!elem.selected ); 2199 }, 2200 2201 "selected": function( elem ) { 2202 2203 // Accessing this property makes selected-by-default 2204 // options in Safari work properly 2205 if ( elem.parentNode ) { 2206 // eslint-disable-next-line no-unused-expressions 2207 elem.parentNode.selectedIndex; 2208 } 2209 2210 return elem.selected === true; 2211 }, 2212 2213 // Contents 2214 "empty": function( elem ) { 2215 2216 // http://www.w3.org/TR/selectors/#empty-pseudo 2217 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), 2218 // but not by others (comment: 8; processing instruction: 7; etc.) 2219 // nodeType < 6 works because attributes (2) do not appear as children 2220 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 2221 if ( elem.nodeType < 6 ) { 2222 return false; 2223 } 2224 } 2225 return true; 2226 }, 2227 2228 "parent": function( elem ) { 2229 return !Expr.pseudos[ "empty" ]( elem ); 2230 }, 2231 2232 // Element/input types 2233 "header": function( elem ) { 2234 return rheader.test( elem.nodeName ); 2235 }, 2236 2237 "input": function( elem ) { 2238 return rinputs.test( elem.nodeName ); 2239 }, 2240 2241 "button": function( elem ) { 2242 var name = elem.nodeName.toLowerCase(); 2243 return name === "input" && elem.type === "button" || name === "button"; 2244 }, 2245 2246 "text": function( elem ) { 2247 var attr; 2248 return elem.nodeName.toLowerCase() === "input" && 2249 elem.type === "text" && 2250 2251 // Support: IE<8 2252 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" 2253 ( ( attr = elem.getAttribute( "type" ) ) == null || 2254 attr.toLowerCase() === "text" ); 2255 }, 2256 2257 // Position-in-collection 2258 "first": createPositionalPseudo( function() { 2259 return [ 0 ]; 2260 } ), 2261 2262 "last": createPositionalPseudo( function( _matchIndexes, length ) { 2263 return [ length - 1 ]; 2264 } ), 2265 2266 "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { 2267 return [ argument < 0 ? argument + length : argument ]; 2268 } ), 2269 2270 "even": createPositionalPseudo( function( matchIndexes, length ) { 2271 var i = 0; 2272 for ( ; i < length; i += 2 ) { 2273 matchIndexes.push( i ); 2274 } 2275 return matchIndexes; 2276 } ), 2277 2278 "odd": createPositionalPseudo( function( matchIndexes, length ) { 2279 var i = 1; 2280 for ( ; i < length; i += 2 ) { 2281 matchIndexes.push( i ); 2282 } 2283 return matchIndexes; 2284 } ), 2285 2286 "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { 2287 var i = argument < 0 ? 2288 argument + length : 2289 argument > length ? 2290 length : 2291 argument; 2292 for ( ; --i >= 0; ) { 2293 matchIndexes.push( i ); 2294 } 2295 return matchIndexes; 2296 } ), 2297 2298 "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { 2299 var i = argument < 0 ? argument + length : argument; 2300 for ( ; ++i < length; ) { 2301 matchIndexes.push( i ); 2302 } 2303 return matchIndexes; 2304 } ) 2305 } 2306}; 2307 2308Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; 2309 2310// Add button/input type pseudos 2311for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { 2312 Expr.pseudos[ i ] = createInputPseudo( i ); 2313} 2314for ( i in { submit: true, reset: true } ) { 2315 Expr.pseudos[ i ] = createButtonPseudo( i ); 2316} 2317 2318// Easy API for creating new setFilters 2319function setFilters() {} 2320setFilters.prototype = Expr.filters = Expr.pseudos; 2321Expr.setFilters = new setFilters(); 2322 2323tokenize = Sizzle.tokenize = function( selector, parseOnly ) { 2324 var matched, match, tokens, type, 2325 soFar, groups, preFilters, 2326 cached = tokenCache[ selector + " " ]; 2327 2328 if ( cached ) { 2329 return parseOnly ? 0 : cached.slice( 0 ); 2330 } 2331 2332 soFar = selector; 2333 groups = []; 2334 preFilters = Expr.preFilter; 2335 2336 while ( soFar ) { 2337 2338 // Comma and first run 2339 if ( !matched || ( match = rcomma.exec( soFar ) ) ) { 2340 if ( match ) { 2341 2342 // Don't consume trailing commas as valid 2343 soFar = soFar.slice( match[ 0 ].length ) || soFar; 2344 } 2345 groups.push( ( tokens = [] ) ); 2346 } 2347 2348 matched = false; 2349 2350 // Combinators 2351 if ( ( match = rcombinators.exec( soFar ) ) ) { 2352 matched = match.shift(); 2353 tokens.push( { 2354 value: matched, 2355 2356 // Cast descendant combinators to space 2357 type: match[ 0 ].replace( rtrim, " " ) 2358 } ); 2359 soFar = soFar.slice( matched.length ); 2360 } 2361 2362 // Filters 2363 for ( type in Expr.filter ) { 2364 if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || 2365 ( match = preFilters[ type ]( match ) ) ) ) { 2366 matched = match.shift(); 2367 tokens.push( { 2368 value: matched, 2369 type: type, 2370 matches: match 2371 } ); 2372 soFar = soFar.slice( matched.length ); 2373 } 2374 } 2375 2376 if ( !matched ) { 2377 break; 2378 } 2379 } 2380 2381 // Return the length of the invalid excess 2382 // if we're just parsing 2383 // Otherwise, throw an error or return tokens 2384 return parseOnly ? 2385 soFar.length : 2386 soFar ? 2387 Sizzle.error( selector ) : 2388 2389 // Cache the tokens 2390 tokenCache( selector, groups ).slice( 0 ); 2391}; 2392 2393function toSelector( tokens ) { 2394 var i = 0, 2395 len = tokens.length, 2396 selector = ""; 2397 for ( ; i < len; i++ ) { 2398 selector += tokens[ i ].value; 2399 } 2400 return selector; 2401} 2402 2403function addCombinator( matcher, combinator, base ) { 2404 var dir = combinator.dir, 2405 skip = combinator.next, 2406 key = skip || dir, 2407 checkNonElements = base && key === "parentNode", 2408 doneName = done++; 2409 2410 return combinator.first ? 2411 2412 // Check against closest ancestor/preceding element 2413 function( elem, context, xml ) { 2414 while ( ( elem = elem[ dir ] ) ) { 2415 if ( elem.nodeType === 1 || checkNonElements ) { 2416 return matcher( elem, context, xml ); 2417 } 2418 } 2419 return false; 2420 } : 2421 2422 // Check against all ancestor/preceding elements 2423 function( elem, context, xml ) { 2424 var oldCache, uniqueCache, outerCache, 2425 newCache = [ dirruns, doneName ]; 2426 2427 // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching 2428 if ( xml ) { 2429 while ( ( elem = elem[ dir ] ) ) { 2430 if ( elem.nodeType === 1 || checkNonElements ) { 2431 if ( matcher( elem, context, xml ) ) { 2432 return true; 2433 } 2434 } 2435 } 2436 } else { 2437 while ( ( elem = elem[ dir ] ) ) { 2438 if ( elem.nodeType === 1 || checkNonElements ) { 2439 outerCache = elem[ expando ] || ( elem[ expando ] = {} ); 2440 2441 // Support: IE <9 only 2442 // Defend against cloned attroperties (jQuery gh-1709) 2443 uniqueCache = outerCache[ elem.uniqueID ] || 2444 ( outerCache[ elem.uniqueID ] = {} ); 2445 2446 if ( skip && skip === elem.nodeName.toLowerCase() ) { 2447 elem = elem[ dir ] || elem; 2448 } else if ( ( oldCache = uniqueCache[ key ] ) && 2449 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { 2450 2451 // Assign to newCache so results back-propagate to previous elements 2452 return ( newCache[ 2 ] = oldCache[ 2 ] ); 2453 } else { 2454 2455 // Reuse newcache so results back-propagate to previous elements 2456 uniqueCache[ key ] = newCache; 2457 2458 // A match means we're done; a fail means we have to keep checking 2459 if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { 2460 return true; 2461 } 2462 } 2463 } 2464 } 2465 } 2466 return false; 2467 }; 2468} 2469 2470function elementMatcher( matchers ) { 2471 return matchers.length > 1 ? 2472 function( elem, context, xml ) { 2473 var i = matchers.length; 2474 while ( i-- ) { 2475 if ( !matchers[ i ]( elem, context, xml ) ) { 2476 return false; 2477 } 2478 } 2479 return true; 2480 } : 2481 matchers[ 0 ]; 2482} 2483 2484function multipleContexts( selector, contexts, results ) { 2485 var i = 0, 2486 len = contexts.length; 2487 for ( ; i < len; i++ ) { 2488 Sizzle( selector, contexts[ i ], results ); 2489 } 2490 return results; 2491} 2492 2493function condense( unmatched, map, filter, context, xml ) { 2494 var elem, 2495 newUnmatched = [], 2496 i = 0, 2497 len = unmatched.length, 2498 mapped = map != null; 2499 2500 for ( ; i < len; i++ ) { 2501 if ( ( elem = unmatched[ i ] ) ) { 2502 if ( !filter || filter( elem, context, xml ) ) { 2503 newUnmatched.push( elem ); 2504 if ( mapped ) { 2505 map.push( i ); 2506 } 2507 } 2508 } 2509 } 2510 2511 return newUnmatched; 2512} 2513 2514function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { 2515 if ( postFilter && !postFilter[ expando ] ) { 2516 postFilter = setMatcher( postFilter ); 2517 } 2518 if ( postFinder && !postFinder[ expando ] ) { 2519 postFinder = setMatcher( postFinder, postSelector ); 2520 } 2521 return markFunction( function( seed, results, context, xml ) { 2522 var temp, i, elem, 2523 preMap = [], 2524 postMap = [], 2525 preexisting = results.length, 2526 2527 // Get initial elements from seed or context 2528 elems = seed || multipleContexts( 2529 selector || "*", 2530 context.nodeType ? [ context ] : context, 2531 [] 2532 ), 2533 2534 // Prefilter to get matcher input, preserving a map for seed-results synchronization 2535 matcherIn = preFilter && ( seed || !selector ) ? 2536 condense( elems, preMap, preFilter, context, xml ) : 2537 elems, 2538 2539 matcherOut = matcher ? 2540 2541 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, 2542 postFinder || ( seed ? preFilter : preexisting || postFilter ) ? 2543 2544 // ...intermediate processing is necessary 2545 [] : 2546 2547 // ...otherwise use results directly 2548 results : 2549 matcherIn; 2550 2551 // Find primary matches 2552 if ( matcher ) { 2553 matcher( matcherIn, matcherOut, context, xml ); 2554 } 2555 2556 // Apply postFilter 2557 if ( postFilter ) { 2558 temp = condense( matcherOut, postMap ); 2559 postFilter( temp, [], context, xml ); 2560 2561 // Un-match failing elements by moving them back to matcherIn 2562 i = temp.length; 2563 while ( i-- ) { 2564 if ( ( elem = temp[ i ] ) ) { 2565 matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); 2566 } 2567 } 2568 } 2569 2570 if ( seed ) { 2571 if ( postFinder || preFilter ) { 2572 if ( postFinder ) { 2573 2574 // Get the final matcherOut by condensing this intermediate into postFinder contexts 2575 temp = []; 2576 i = matcherOut.length; 2577 while ( i-- ) { 2578 if ( ( elem = matcherOut[ i ] ) ) { 2579 2580 // Restore matcherIn since elem is not yet a final match 2581 temp.push( ( matcherIn[ i ] = elem ) ); 2582 } 2583 } 2584 postFinder( null, ( matcherOut = [] ), temp, xml ); 2585 } 2586 2587 // Move matched elements from seed to results to keep them synchronized 2588 i = matcherOut.length; 2589 while ( i-- ) { 2590 if ( ( elem = matcherOut[ i ] ) && 2591 ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { 2592 2593 seed[ temp ] = !( results[ temp ] = elem ); 2594 } 2595 } 2596 } 2597 2598 // Add elements to results, through postFinder if defined 2599 } else { 2600 matcherOut = condense( 2601 matcherOut === results ? 2602 matcherOut.splice( preexisting, matcherOut.length ) : 2603 matcherOut 2604 ); 2605 if ( postFinder ) { 2606 postFinder( null, results, matcherOut, xml ); 2607 } else { 2608 push.apply( results, matcherOut ); 2609 } 2610 } 2611 } ); 2612} 2613 2614function matcherFromTokens( tokens ) { 2615 var checkContext, matcher, j, 2616 len = tokens.length, 2617 leadingRelative = Expr.relative[ tokens[ 0 ].type ], 2618 implicitRelative = leadingRelative || Expr.relative[ " " ], 2619 i = leadingRelative ? 1 : 0, 2620 2621 // The foundational matcher ensures that elements are reachable from top-level context(s) 2622 matchContext = addCombinator( function( elem ) { 2623 return elem === checkContext; 2624 }, implicitRelative, true ), 2625 matchAnyContext = addCombinator( function( elem ) { 2626 return indexOf( checkContext, elem ) > -1; 2627 }, implicitRelative, true ), 2628 matchers = [ function( elem, context, xml ) { 2629 var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( 2630 ( checkContext = context ).nodeType ? 2631 matchContext( elem, context, xml ) : 2632 matchAnyContext( elem, context, xml ) ); 2633 2634 // Avoid hanging onto element (issue #299) 2635 checkContext = null; 2636 return ret; 2637 } ]; 2638 2639 for ( ; i < len; i++ ) { 2640 if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { 2641 matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; 2642 } else { 2643 matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); 2644 2645 // Return special upon seeing a positional matcher 2646 if ( matcher[ expando ] ) { 2647 2648 // Find the next relative operator (if any) for proper handling 2649 j = ++i; 2650 for ( ; j < len; j++ ) { 2651 if ( Expr.relative[ tokens[ j ].type ] ) { 2652 break; 2653 } 2654 } 2655 return setMatcher( 2656 i > 1 && elementMatcher( matchers ), 2657 i > 1 && toSelector( 2658 2659 // If the preceding token was a descendant combinator, insert an implicit any-element `*` 2660 tokens 2661 .slice( 0, i - 1 ) 2662 .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) 2663 ).replace( rtrim, "$1" ), 2664 matcher, 2665 i < j && matcherFromTokens( tokens.slice( i, j ) ), 2666 j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), 2667 j < len && toSelector( tokens ) 2668 ); 2669 } 2670 matchers.push( matcher ); 2671 } 2672 } 2673 2674 return elementMatcher( matchers ); 2675} 2676 2677function matcherFromGroupMatchers( elementMatchers, setMatchers ) { 2678 var bySet = setMatchers.length > 0, 2679 byElement = elementMatchers.length > 0, 2680 superMatcher = function( seed, context, xml, results, outermost ) { 2681 var elem, j, matcher, 2682 matchedCount = 0, 2683 i = "0", 2684 unmatched = seed && [], 2685 setMatched = [], 2686 contextBackup = outermostContext, 2687 2688 // We must always have either seed elements or outermost context 2689 elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), 2690 2691 // Use integer dirruns iff this is the outermost matcher 2692 dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), 2693 len = elems.length; 2694 2695 if ( outermost ) { 2696 2697 // Support: IE 11+, Edge 17 - 18+ 2698 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 2699 // two documents; shallow comparisons work. 2700 // eslint-disable-next-line eqeqeq 2701 outermostContext = context == document || context || outermost; 2702 } 2703 2704 // Add elements passing elementMatchers directly to results 2705 // Support: IE<9, Safari 2706 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id 2707 for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { 2708 if ( byElement && elem ) { 2709 j = 0; 2710 2711 // Support: IE 11+, Edge 17 - 18+ 2712 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 2713 // two documents; shallow comparisons work. 2714 // eslint-disable-next-line eqeqeq 2715 if ( !context && elem.ownerDocument != document ) { 2716 setDocument( elem ); 2717 xml = !documentIsHTML; 2718 } 2719 while ( ( matcher = elementMatchers[ j++ ] ) ) { 2720 if ( matcher( elem, context || document, xml ) ) { 2721 results.push( elem ); 2722 break; 2723 } 2724 } 2725 if ( outermost ) { 2726 dirruns = dirrunsUnique; 2727 } 2728 } 2729 2730 // Track unmatched elements for set filters 2731 if ( bySet ) { 2732 2733 // They will have gone through all possible matchers 2734 if ( ( elem = !matcher && elem ) ) { 2735 matchedCount--; 2736 } 2737 2738 // Lengthen the array for every element, matched or not 2739 if ( seed ) { 2740 unmatched.push( elem ); 2741 } 2742 } 2743 } 2744 2745 // `i` is now the count of elements visited above, and adding it to `matchedCount` 2746 // makes the latter nonnegative. 2747 matchedCount += i; 2748 2749 // Apply set filters to unmatched elements 2750 // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` 2751 // equals `i`), unless we didn't visit _any_ elements in the above loop because we have 2752 // no element matchers and no seed. 2753 // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that 2754 // case, which will result in a "00" `matchedCount` that differs from `i` but is also 2755 // numerically zero. 2756 if ( bySet && i !== matchedCount ) { 2757 j = 0; 2758 while ( ( matcher = setMatchers[ j++ ] ) ) { 2759 matcher( unmatched, setMatched, context, xml ); 2760 } 2761 2762 if ( seed ) { 2763 2764 // Reintegrate element matches to eliminate the need for sorting 2765 if ( matchedCount > 0 ) { 2766 while ( i-- ) { 2767 if ( !( unmatched[ i ] || setMatched[ i ] ) ) { 2768 setMatched[ i ] = pop.call( results ); 2769 } 2770 } 2771 } 2772 2773 // Discard index placeholder values to get only actual matches 2774 setMatched = condense( setMatched ); 2775 } 2776 2777 // Add matches to results 2778 push.apply( results, setMatched ); 2779 2780 // Seedless set matches succeeding multiple successful matchers stipulate sorting 2781 if ( outermost && !seed && setMatched.length > 0 && 2782 ( matchedCount + setMatchers.length ) > 1 ) { 2783 2784 Sizzle.uniqueSort( results ); 2785 } 2786 } 2787 2788 // Override manipulation of globals by nested matchers 2789 if ( outermost ) { 2790 dirruns = dirrunsUnique; 2791 outermostContext = contextBackup; 2792 } 2793 2794 return unmatched; 2795 }; 2796 2797 return bySet ? 2798 markFunction( superMatcher ) : 2799 superMatcher; 2800} 2801 2802compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { 2803 var i, 2804 setMatchers = [], 2805 elementMatchers = [], 2806 cached = compilerCache[ selector + " " ]; 2807 2808 if ( !cached ) { 2809 2810 // Generate a function of recursive functions that can be used to check each element 2811 if ( !match ) { 2812 match = tokenize( selector ); 2813 } 2814 i = match.length; 2815 while ( i-- ) { 2816 cached = matcherFromTokens( match[ i ] ); 2817 if ( cached[ expando ] ) { 2818 setMatchers.push( cached ); 2819 } else { 2820 elementMatchers.push( cached ); 2821 } 2822 } 2823 2824 // Cache the compiled function 2825 cached = compilerCache( 2826 selector, 2827 matcherFromGroupMatchers( elementMatchers, setMatchers ) 2828 ); 2829 2830 // Save selector and tokenization 2831 cached.selector = selector; 2832 } 2833 return cached; 2834}; 2835 2836/** 2837 * A low-level selection function that works with Sizzle's compiled 2838 * selector functions 2839 * @param {String|Function} selector A selector or a pre-compiled 2840 * selector function built with Sizzle.compile 2841 * @param {Element} context 2842 * @param {Array} [results] 2843 * @param {Array} [seed] A set of elements to match against 2844 */ 2845select = Sizzle.select = function( selector, context, results, seed ) { 2846 var i, tokens, token, type, find, 2847 compiled = typeof selector === "function" && selector, 2848 match = !seed && tokenize( ( selector = compiled.selector || selector ) ); 2849 2850 results = results || []; 2851 2852 // Try to minimize operations if there is only one selector in the list and no seed 2853 // (the latter of which guarantees us context) 2854 if ( match.length === 1 ) { 2855 2856 // Reduce context if the leading compound selector is an ID 2857 tokens = match[ 0 ] = match[ 0 ].slice( 0 ); 2858 if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && 2859 context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { 2860 2861 context = ( Expr.find[ "ID" ]( token.matches[ 0 ] 2862 .replace( runescape, funescape ), context ) || [] )[ 0 ]; 2863 if ( !context ) { 2864 return results; 2865 2866 // Precompiled matchers will still verify ancestry, so step up a level 2867 } else if ( compiled ) { 2868 context = context.parentNode; 2869 } 2870 2871 selector = selector.slice( tokens.shift().value.length ); 2872 } 2873 2874 // Fetch a seed set for right-to-left matching 2875 i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; 2876 while ( i-- ) { 2877 token = tokens[ i ]; 2878 2879 // Abort if we hit a combinator 2880 if ( Expr.relative[ ( type = token.type ) ] ) { 2881 break; 2882 } 2883 if ( ( find = Expr.find[ type ] ) ) { 2884 2885 // Search, expanding context for leading sibling combinators 2886 if ( ( seed = find( 2887 token.matches[ 0 ].replace( runescape, funescape ), 2888 rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || 2889 context 2890 ) ) ) { 2891 2892 // If seed is empty or no tokens remain, we can return early 2893 tokens.splice( i, 1 ); 2894 selector = seed.length && toSelector( tokens ); 2895 if ( !selector ) { 2896 push.apply( results, seed ); 2897 return results; 2898 } 2899 2900 break; 2901 } 2902 } 2903 } 2904 } 2905 2906 // Compile and execute a filtering function if one is not provided 2907 // Provide `match` to avoid retokenization if we modified the selector above 2908 ( compiled || compile( selector, match ) )( 2909 seed, 2910 context, 2911 !documentIsHTML, 2912 results, 2913 !context || rsibling.test( selector ) && testContext( context.parentNode ) || context 2914 ); 2915 return results; 2916}; 2917 2918// One-time assignments 2919 2920// Sort stability 2921support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; 2922 2923// Support: Chrome 14-35+ 2924// Always assume duplicates if they aren't passed to the comparison function 2925support.detectDuplicates = !!hasDuplicate; 2926 2927// Initialize against the default document 2928setDocument(); 2929 2930// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) 2931// Detached nodes confoundingly follow *each other* 2932support.sortDetached = assert( function( el ) { 2933 2934 // Should return 1, but returns 4 (following) 2935 return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; 2936} ); 2937 2938// Support: IE<8 2939// Prevent attribute/property "interpolation" 2940// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 2941if ( !assert( function( el ) { 2942 el.innerHTML = "<a href='#'></a>"; 2943 return el.firstChild.getAttribute( "href" ) === "#"; 2944} ) ) { 2945 addHandle( "type|href|height|width", function( elem, name, isXML ) { 2946 if ( !isXML ) { 2947 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); 2948 } 2949 } ); 2950} 2951 2952// Support: IE<9 2953// Use defaultValue in place of getAttribute("value") 2954if ( !support.attributes || !assert( function( el ) { 2955 el.innerHTML = "<input/>"; 2956 el.firstChild.setAttribute( "value", "" ); 2957 return el.firstChild.getAttribute( "value" ) === ""; 2958} ) ) { 2959 addHandle( "value", function( elem, _name, isXML ) { 2960 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { 2961 return elem.defaultValue; 2962 } 2963 } ); 2964} 2965 2966// Support: IE<9 2967// Use getAttributeNode to fetch booleans when getAttribute lies 2968if ( !assert( function( el ) { 2969 return el.getAttribute( "disabled" ) == null; 2970} ) ) { 2971 addHandle( booleans, function( elem, name, isXML ) { 2972 var val; 2973 if ( !isXML ) { 2974 return elem[ name ] === true ? name.toLowerCase() : 2975 ( val = elem.getAttributeNode( name ) ) && val.specified ? 2976 val.value : 2977 null; 2978 } 2979 } ); 2980} 2981 2982return Sizzle; 2983 2984} )( window ); 2985 2986 2987 2988jQuery.find = Sizzle; 2989jQuery.expr = Sizzle.selectors; 2990 2991// Deprecated 2992jQuery.expr[ ":" ] = jQuery.expr.pseudos; 2993jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; 2994jQuery.text = Sizzle.getText; 2995jQuery.isXMLDoc = Sizzle.isXML; 2996jQuery.contains = Sizzle.contains; 2997jQuery.escapeSelector = Sizzle.escape; 2998 2999 3000 3001 3002var dir = function( elem, dir, until ) { 3003 var matched = [], 3004 truncate = until !== undefined; 3005 3006 while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { 3007 if ( elem.nodeType === 1 ) { 3008 if ( truncate && jQuery( elem ).is( until ) ) { 3009 break; 3010 } 3011 matched.push( elem ); 3012 } 3013 } 3014 return matched; 3015}; 3016 3017 3018var siblings = function( n, elem ) { 3019 var matched = []; 3020 3021 for ( ; n; n = n.nextSibling ) { 3022 if ( n.nodeType === 1 && n !== elem ) { 3023 matched.push( n ); 3024 } 3025 } 3026 3027 return matched; 3028}; 3029 3030 3031var rneedsContext = jQuery.expr.match.needsContext; 3032 3033 3034 3035function nodeName( elem, name ) { 3036 3037 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 3038 3039} 3040var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); 3041 3042 3043 3044// Implement the identical functionality for filter and not 3045function winnow( elements, qualifier, not ) { 3046 if ( isFunction( qualifier ) ) { 3047 return jQuery.grep( elements, function( elem, i ) { 3048 return !!qualifier.call( elem, i, elem ) !== not; 3049 } ); 3050 } 3051 3052 // Single element 3053 if ( qualifier.nodeType ) { 3054 return jQuery.grep( elements, function( elem ) { 3055 return ( elem === qualifier ) !== not; 3056 } ); 3057 } 3058 3059 // Arraylike of elements (jQuery, arguments, Array) 3060 if ( typeof qualifier !== "string" ) { 3061 return jQuery.grep( elements, function( elem ) { 3062 return ( indexOf.call( qualifier, elem ) > -1 ) !== not; 3063 } ); 3064 } 3065 3066 // Filtered directly for both simple and complex selectors 3067 return jQuery.filter( qualifier, elements, not ); 3068} 3069 3070jQuery.filter = function( expr, elems, not ) { 3071 var elem = elems[ 0 ]; 3072 3073 if ( not ) { 3074 expr = ":not(" + expr + ")"; 3075 } 3076 3077 if ( elems.length === 1 && elem.nodeType === 1 ) { 3078 return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; 3079 } 3080 3081 return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { 3082 return elem.nodeType === 1; 3083 } ) ); 3084}; 3085 3086jQuery.fn.extend( { 3087 find: function( selector ) { 3088 var i, ret, 3089 len = this.length, 3090 self = this; 3091 3092 if ( typeof selector !== "string" ) {
vendor: 4,670 bytes, lines 3093-3278
3093 return this.pushStack( jQuery( selector ).filter( function() { 3094 for ( i = 0; i < len; i++ ) { 3095 if ( jQuery.contains( self[ i ], this ) ) { 3096 return true; 3097 } 3098 } 3099 } ) ); 3100 } 3101 3102 ret = this.pushStack( [] ); 3103 3104 for ( i = 0; i < len; i++ ) { 3105 jQuery.find( selector, self[ i ], ret ); 3106 } 3107 3108 return len > 1 ? jQuery.uniqueSort( ret ) : ret; 3109 }, 3110 filter: function( selector ) { 3111 return this.pushStack( winnow( this, selector || [], false ) ); 3112 }, 3113 not: function( selector ) { 3114 return this.pushStack( winnow( this, selector || [], true ) ); 3115 }, 3116 is: function( selector ) { 3117 return !!winnow( 3118 this, 3119 3120 // If this is a positional/relative selector, check membership in the returned set 3121 // so $("p:first").is("p:last") won't return true for a doc with two "p". 3122 typeof selector === "string" && rneedsContext.test( selector ) ? 3123 jQuery( selector ) : 3124 selector || [], 3125 false 3126 ).length; 3127 } 3128} ); 3129 3130 3131// Initialize a jQuery object 3132 3133 3134// A central reference to the root jQuery(document) 3135var rootjQuery, 3136 3137 // A simple way to check for HTML strings 3138 // Prioritize #id over <tag> to avoid XSS via location.hash (trac-9521) 3139 // Strict HTML recognition (trac-11290: must start with <) 3140 // Shortcut simple #id case for speed 3141 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, 3142 3143 init = jQuery.fn.init = function( selector, context, root ) { 3144 var match, elem; 3145 3146 // HANDLE: $(""), $(null), $(undefined), $(false) 3147 if ( !selector ) { 3148 return this; 3149 } 3150 3151 // Method init() accepts an alternate rootjQuery 3152 // so migrate can support jQuery.sub (gh-2101) 3153 root = root || rootjQuery; 3154 3155 // Handle HTML strings 3156 if ( typeof selector === "string" ) { 3157 if ( selector[ 0 ] === "<" && 3158 selector[ selector.length - 1 ] === ">" && 3159 selector.length >= 3 ) { 3160 3161 // Assume that strings that start and end with <> are HTML and skip the regex check 3162 match = [ null, selector, null ]; 3163 3164 } else { 3165 match = rquickExpr.exec( selector ); 3166 } 3167 3168 // Match html or make sure no context is specified for #id 3169 if ( match && ( match[ 1 ] || !context ) ) { 3170 3171 // HANDLE: $(html) -> $(array) 3172 if ( match[ 1 ] ) { 3173 context = context instanceof jQuery ? context[ 0 ] : context; 3174 3175 // Option to run scripts is true for back-compat 3176 // Intentionally let the error be thrown if parseHTML is not present 3177 jQuery.merge( this, jQuery.parseHTML( 3178 match[ 1 ], 3179 context && context.nodeType ? context.ownerDocument || context : document, 3180 true 3181 ) ); 3182 3183 // HANDLE: $(html, props) 3184 if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { 3185 for ( match in context ) { 3186 3187 // Properties of context are called as methods if possible 3188 if ( isFunction( this[ match ] ) ) { 3189 this[ match ]( context[ match ] ); 3190 3191 // ...and otherwise set as attributes 3192 } else { 3193 this.attr( match, context[ match ] ); 3194 } 3195 } 3196 } 3197 3198 return this; 3199 3200 // HANDLE: $(#id) 3201 } else { 3202 elem = document.getElementById( match[ 2 ] ); 3203 3204 if ( elem ) { 3205 3206 // Inject the element directly into the jQuery object 3207 this[ 0 ] = elem; 3208 this.length = 1; 3209 } 3210 return this; 3211 } 3212 3213 // HANDLE: $(expr, $(...)) 3214 } else if ( !context || context.jquery ) { 3215 return ( context || root ).find( selector ); 3216 3217 // HANDLE: $(expr, context) 3218 // (which is just equivalent to: $(context).find(expr) 3219 } else { 3220 return this.constructor( context ).find( selector ); 3221 } 3222 3223 // HANDLE: $(DOMElement) 3224 } else if ( selector.nodeType ) { 3225 this[ 0 ] = selector; 3226 this.length = 1; 3227 return this; 3228 3229 // HANDLE: $(function) 3230 // Shortcut for document ready 3231 } else if ( isFunction( selector ) ) { 3232 return root.ready !== undefined ? 3233 root.ready( selector ) : 3234 3235 // Execute immediately if ready is not present 3236 selector( jQuery ); 3237 } 3238 3239 return jQuery.makeArray( selector, this ); 3240 }; 3241 3242// Give the init function the jQuery prototype for later instantiation 3243init.prototype = jQuery.fn; 3244 3245// Initialize central reference 3246rootjQuery = jQuery( document ); 3247 3248 3249var rparentsprev = /^(?:parents|prev(?:Until|All))/, 3250 3251 // Methods guaranteed to produce a unique set when starting from a unique set 3252 guaranteedUnique = { 3253 children: true, 3254 contents: true, 3255 next: true, 3256 prev: true 3257 }; 3258 3259jQuery.fn.extend( { 3260 has: function( target ) { 3261 var targets = jQuery( target, this ), 3262 l = targets.length; 3263 3264 return this.filter( function() { 3265 var i = 0; 3266 for ( ; i < l; i++ ) { 3267 if ( jQuery.contains( this, targets[ i ] ) ) { 3268 return true; 3269 } 3270 } 3271 } ); 3272 }, 3273 3274 closest: function( selectors, context ) { 3275 var cur, 3276 i = 0, 3277 l = this.length, 3278 matched = [],
vendor: 15,549 bytes, lines 3279-3864
3279 targets = typeof selectors !== "string" && jQuery( selectors ); 3280 3281 // Positional selectors never match, since there's no _selection_ context 3282 if ( !rneedsContext.test( selectors ) ) { 3283 for ( ; i < l; i++ ) { 3284 for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { 3285 3286 // Always skip document fragments 3287 if ( cur.nodeType < 11 && ( targets ? 3288 targets.index( cur ) > -1 : 3289 3290 // Don't pass non-elements to Sizzle 3291 cur.nodeType === 1 && 3292 jQuery.find.matchesSelector( cur, selectors ) ) ) { 3293 3294 matched.push( cur ); 3295 break; 3296 } 3297 } 3298 } 3299 } 3300 3301 return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); 3302 }, 3303 3304 // Determine the position of an element within the set 3305 index: function( elem ) { 3306 3307 // No argument, return index in parent 3308 if ( !elem ) { 3309 return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; 3310 } 3311 3312 // Index in selector 3313 if ( typeof elem === "string" ) { 3314 return indexOf.call( jQuery( elem ), this[ 0 ] ); 3315 } 3316 3317 // Locate the position of the desired element 3318 return indexOf.call( this, 3319 3320 // If it receives a jQuery object, the first element is used 3321 elem.jquery ? elem[ 0 ] : elem 3322 ); 3323 }, 3324 3325 add: function( selector, context ) { 3326 return this.pushStack( 3327 jQuery.uniqueSort( 3328 jQuery.merge( this.get(), jQuery( selector, context ) ) 3329 ) 3330 ); 3331 }, 3332 3333 addBack: function( selector ) { 3334 return this.add( selector == null ? 3335 this.prevObject : this.prevObject.filter( selector ) 3336 ); 3337 } 3338} ); 3339 3340function sibling( cur, dir ) { 3341 while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} 3342 return cur; 3343} 3344 3345jQuery.each( { 3346 parent: function( elem ) { 3347 var parent = elem.parentNode; 3348 return parent && parent.nodeType !== 11 ? parent : null; 3349 }, 3350 parents: function( elem ) { 3351 return dir( elem, "parentNode" ); 3352 }, 3353 parentsUntil: function( elem, _i, until ) { 3354 return dir( elem, "parentNode", until ); 3355 }, 3356 next: function( elem ) { 3357 return sibling( elem, "nextSibling" ); 3358 }, 3359 prev: function( elem ) { 3360 return sibling( elem, "previousSibling" ); 3361 }, 3362 nextAll: function( elem ) { 3363 return dir( elem, "nextSibling" ); 3364 }, 3365 prevAll: function( elem ) { 3366 return dir( elem, "previousSibling" ); 3367 }, 3368 nextUntil: function( elem, _i, until ) { 3369 return dir( elem, "nextSibling", until ); 3370 }, 3371 prevUntil: function( elem, _i, until ) { 3372 return dir( elem, "previousSibling", until ); 3373 }, 3374 siblings: function( elem ) { 3375 return siblings( ( elem.parentNode || {} ).firstChild, elem ); 3376 }, 3377 children: function( elem ) { 3378 return siblings( elem.firstChild ); 3379 }, 3380 contents: function( elem ) { 3381 if ( elem.contentDocument != null && 3382 3383 // Support: IE 11+ 3384 // <object> elements with no `data` attribute has an object 3385 // `contentDocument` with a `null` prototype. 3386 getProto( elem.contentDocument ) ) { 3387 3388 return elem.contentDocument; 3389 } 3390 3391 // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only 3392 // Treat the template element as a regular one in browsers that 3393 // don't support it. 3394 if ( nodeName( elem, "template" ) ) { 3395 elem = elem.content || elem; 3396 } 3397 3398 return jQuery.merge( [], elem.childNodes ); 3399 } 3400}, function( name, fn ) { 3401 jQuery.fn[ name ] = function( until, selector ) { 3402 var matched = jQuery.map( this, fn, until ); 3403 3404 if ( name.slice( -5 ) !== "Until" ) { 3405 selector = until; 3406 } 3407 3408 if ( selector && typeof selector === "string" ) { 3409 matched = jQuery.filter( selector, matched ); 3410 } 3411 3412 if ( this.length > 1 ) { 3413 3414 // Remove duplicates 3415 if ( !guaranteedUnique[ name ] ) { 3416 jQuery.uniqueSort( matched ); 3417 } 3418 3419 // Reverse order for parents* and prev-derivatives 3420 if ( rparentsprev.test( name ) ) { 3421 matched.reverse(); 3422 } 3423 } 3424 3425 return this.pushStack( matched ); 3426 }; 3427} ); 3428var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); 3429 3430 3431 3432// Convert String-formatted options into Object-formatted ones 3433function createOptions( options ) { 3434 var object = {}; 3435 jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { 3436 object[ flag ] = true; 3437 } ); 3438 return object; 3439} 3440 3441/* 3442 * Create a callback list using the following parameters: 3443 * 3444 * options: an optional list of space-separated options that will change how 3445 * the callback list behaves or a more traditional option object 3446 * 3447 * By default a callback list will act like an event callback list and can be 3448 * "fired" multiple times. 3449 * 3450 * Possible options: 3451 * 3452 * once: will ensure the callback list can only be fired once (like a Deferred) 3453 * 3454 * memory: will keep track of previous values and will call any callback added 3455 * after the list has been fired right away with the latest "memorized" 3456 * values (like a Deferred) 3457 * 3458 * unique: will ensure a callback can only be added once (no duplicate in the list) 3459 * 3460 * stopOnFalse: interrupt callings when a callback returns false 3461 * 3462 */ 3463jQuery.Callbacks = function( options ) { 3464 3465 // Convert options from String-formatted to Object-formatted if needed 3466 // (we check in cache first) 3467 options = typeof options === "string" ? 3468 createOptions( options ) : 3469 jQuery.extend( {}, options ); 3470 3471 var // Flag to know if list is currently firing 3472 firing, 3473 3474 // Last fire value for non-forgettable lists 3475 memory, 3476 3477 // Flag to know if list was already fired 3478 fired, 3479 3480 // Flag to prevent firing 3481 locked, 3482 3483 // Actual callback list 3484 list = [], 3485 3486 // Queue of execution data for repeatable lists 3487 queue = [], 3488 3489 // Index of currently firing callback (modified by add/remove as needed) 3490 firingIndex = -1, 3491 3492 // Fire callbacks 3493 fire = function() { 3494 3495 // Enforce single-firing 3496 locked = locked || options.once; 3497 3498 // Execute callbacks for all pending executions, 3499 // respecting firingIndex overrides and runtime changes 3500 fired = firing = true; 3501 for ( ; queue.length; firingIndex = -1 ) { 3502 memory = queue.shift(); 3503 while ( ++firingIndex < list.length ) { 3504 3505 // Run callback and check for early termination 3506 if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && 3507 options.stopOnFalse ) { 3508 3509 // Jump to end and forget the data so .add doesn't re-fire 3510 firingIndex = list.length; 3511 memory = false; 3512 } 3513 } 3514 } 3515 3516 // Forget the data if we're done with it 3517 if ( !options.memory ) { 3518 memory = false; 3519 } 3520 3521 firing = false; 3522 3523 // Clean up if we're done firing for good 3524 if ( locked ) { 3525 3526 // Keep an empty list if we have data for future add calls 3527 if ( memory ) { 3528 list = []; 3529 3530 // Otherwise, this object is spent 3531 } else { 3532 list = ""; 3533 } 3534 } 3535 }, 3536 3537 // Actual Callbacks object 3538 self = { 3539 3540 // Add a callback or a collection of callbacks to the list 3541 add: function() { 3542 if ( list ) { 3543 3544 // If we have memory from a past run, we should fire after adding 3545 if ( memory && !firing ) { 3546 firingIndex = list.length - 1; 3547 queue.push( memory ); 3548 } 3549 3550 ( function add( args ) { 3551 jQuery.each( args, function( _, arg ) { 3552 if ( isFunction( arg ) ) { 3553 if ( !options.unique || !self.has( arg ) ) { 3554 list.push( arg ); 3555 } 3556 } else if ( arg && arg.length && toType( arg ) !== "string" ) { 3557 3558 // Inspect recursively 3559 add( arg ); 3560 } 3561 } ); 3562 } )( arguments ); 3563 3564 if ( memory && !firing ) { 3565 fire(); 3566 } 3567 } 3568 return this; 3569 }, 3570 3571 // Remove a callback from the list 3572 remove: function() { 3573 jQuery.each( arguments, function( _, arg ) { 3574 var index; 3575 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { 3576 list.splice( index, 1 ); 3577 3578 // Handle firing indexes 3579 if ( index <= firingIndex ) { 3580 firingIndex--; 3581 } 3582 } 3583 } ); 3584 return this; 3585 }, 3586 3587 // Check if a given callback is in the list. 3588 // If no argument is given, return whether or not list has callbacks attached. 3589 has: function( fn ) { 3590 return fn ? 3591 jQuery.inArray( fn, list ) > -1 : 3592 list.length > 0; 3593 }, 3594 3595 // Remove all callbacks from the list 3596 empty: function() { 3597 if ( list ) { 3598 list = []; 3599 } 3600 return this; 3601 }, 3602 3603 // Disable .fire and .add 3604 // Abort any current/pending executions 3605 // Clear all callbacks and values 3606 disable: function() { 3607 locked = queue = []; 3608 list = memory = ""; 3609 return this; 3610 }, 3611 disabled: function() { 3612 return !list; 3613 }, 3614 3615 // Disable .fire 3616 // Also disable .add unless we have memory (since it would have no effect) 3617 // Abort any pending executions 3618 lock: function() { 3619 locked = queue = []; 3620 if ( !memory && !firing ) { 3621 list = memory = ""; 3622 } 3623 return this; 3624 }, 3625 locked: function() { 3626 return !!locked; 3627 }, 3628 3629 // Call all callbacks with the given context and arguments 3630 fireWith: function( context, args ) { 3631 if ( !locked ) { 3632 args = args || []; 3633 args = [ context, args.slice ? args.slice() : args ]; 3634 queue.push( args ); 3635 if ( !firing ) { 3636 fire(); 3637 } 3638 } 3639 return this; 3640 }, 3641 3642 // Call all the callbacks with the given arguments 3643 fire: function() { 3644 self.fireWith( this, arguments ); 3645 return this; 3646 }, 3647 3648 // To know if the callbacks have already been called at least once 3649 fired: function() { 3650 return !!fired; 3651 } 3652 }; 3653 3654 return self; 3655}; 3656 3657 3658function Identity( v ) { 3659 return v; 3660} 3661function Thrower( ex ) { 3662 throw ex; 3663} 3664 3665function adoptValue( value, resolve, reject, noValue ) { 3666 var method; 3667 3668 try { 3669 3670 // Check for promise aspect first to privilege synchronous behavior 3671 if ( value && isFunction( ( method = value.promise ) ) ) { 3672 method.call( value ).done( resolve ).fail( reject ); 3673 3674 // Other thenables 3675 } else if ( value && isFunction( ( method = value.then ) ) ) { 3676 method.call( value, resolve, reject ); 3677 3678 // Other non-thenables 3679 } else { 3680 3681 // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: 3682 // * false: [ value ].slice( 0 ) => resolve( value ) 3683 // * true: [ value ].slice( 1 ) => resolve() 3684 resolve.apply( undefined, [ value ].slice( noValue ) ); 3685 } 3686 3687 // For Promises/A+, convert exceptions into rejections 3688 // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in 3689 // Deferred#then to conditionally suppress rejection. 3690 } catch ( value ) { 3691 3692 // Support: Android 4.0 only 3693 // Strict mode functions invoked without .call/.apply get global-object context 3694 reject.apply( undefined, [ value ] ); 3695 } 3696} 3697 3698jQuery.extend( { 3699 3700 Deferred: function( func ) { 3701 var tuples = [ 3702 3703 // action, add listener, callbacks, 3704 // ... .then handlers, argument index, [final state] 3705 [ "notify", "progress", jQuery.Callbacks( "memory" ), 3706 jQuery.Callbacks( "memory" ), 2 ], 3707 [ "resolve", "done", jQuery.Callbacks( "once memory" ), 3708 jQuery.Callbacks( "once memory" ), 0, "resolved" ], 3709 [ "reject", "fail", jQuery.Callbacks( "once memory" ), 3710 jQuery.Callbacks( "once memory" ), 1, "rejected" ] 3711 ], 3712 state = "pending", 3713 promise = { 3714 state: function() { 3715 return state; 3716 }, 3717 always: function() { 3718 deferred.done( arguments ).fail( arguments ); 3719 return this; 3720 }, 3721 "catch": function( fn ) { 3722 return promise.then( null, fn ); 3723 }, 3724 3725 // Keep pipe for back-compat 3726 pipe: function( /* fnDone, fnFail, fnProgress */ ) { 3727 var fns = arguments; 3728 3729 return jQuery.Deferred( function( newDefer ) { 3730 jQuery.each( tuples, function( _i, tuple ) { 3731 3732 // Map tuples (progress, done, fail) to arguments (done, fail, progress) 3733 var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; 3734 3735 // deferred.progress(function() { bind to newDefer or newDefer.notify }) 3736 // deferred.done(function() { bind to newDefer or newDefer.resolve }) 3737 // deferred.fail(function() { bind to newDefer or newDefer.reject }) 3738 deferred[ tuple[ 1 ] ]( function() { 3739 var returned = fn && fn.apply( this, arguments ); 3740 if ( returned && isFunction( returned.promise ) ) { 3741 returned.promise() 3742 .progress( newDefer.notify ) 3743 .done( newDefer.resolve ) 3744 .fail( newDefer.reject ); 3745 } else { 3746 newDefer[ tuple[ 0 ] + "With" ]( 3747 this, 3748 fn ? [ returned ] : arguments 3749 ); 3750 } 3751 } ); 3752 } ); 3753 fns = null; 3754 } ).promise(); 3755 }, 3756 then: function( onFulfilled, onRejected, onProgress ) { 3757 var maxDepth = 0; 3758 function resolve( depth, deferred, handler, special ) { 3759 return function() { 3760 var that = this, 3761 args = arguments, 3762 mightThrow = function() { 3763 var returned, then; 3764 3765 // Support: Promises/A+ section 2.3.3.3.3 3766 // https://promisesaplus.com/#point-59 3767 // Ignore double-resolution attempts 3768 if ( depth < maxDepth ) { 3769 return; 3770 } 3771 3772 returned = handler.apply( that, args ); 3773 3774 // Support: Promises/A+ section 2.3.1 3775 // https://promisesaplus.com/#point-48 3776 if ( returned === deferred.promise() ) { 3777 throw new TypeError( "Thenable self-resolution" ); 3778 } 3779 3780 // Support: Promises/A+ sections 2.3.3.1, 3.5 3781 // https://promisesaplus.com/#point-54 3782 // https://promisesaplus.com/#point-75 3783 // Retrieve `then` only once 3784 then = returned && 3785 3786 // Support: Promises/A+ section 2.3.4 3787 // https://promisesaplus.com/#point-64 3788 // Only check objects and functions for thenability 3789 ( typeof returned === "object" || 3790 typeof returned === "function" ) && 3791 returned.then; 3792 3793 // Handle a returned thenable 3794 if ( isFunction( then ) ) { 3795 3796 // Special processors (notify) just wait for resolution 3797 if ( special ) { 3798 then.call( 3799 returned, 3800 resolve( maxDepth, deferred, Identity, special ), 3801 resolve( maxDepth, deferred, Thrower, special ) 3802 ); 3803 3804 // Normal processors (resolve) also hook into progress 3805 } else { 3806 3807 // ...and disregard older resolution values 3808 maxDepth++; 3809 3810 then.call( 3811 returned, 3812 resolve( maxDepth, deferred, Identity, special ), 3813 resolve( maxDepth, deferred, Thrower, special ), 3814 resolve( maxDepth, deferred, Identity, 3815 deferred.notifyWith ) 3816 ); 3817 } 3818 3819 // Handle all other returned values 3820 } else { 3821 3822 // Only substitute handlers pass on context 3823 // and multiple values (non-spec behavior) 3824 if ( handler !== Identity ) { 3825 that = undefined; 3826 args = [ returned ]; 3827 } 3828 3829 // Process the value(s) 3830 // Default process is resolve 3831 ( special || deferred.resolveWith )( that, args ); 3832 } 3833 }, 3834 3835 // Only normal processors (resolve) catch and reject exceptions 3836 process = special ? 3837 mightThrow : 3838 function() { 3839 try { 3840 mightThrow(); 3841 } catch ( e ) { 3842 3843 if ( jQuery.Deferred.exceptionHook ) { 3844 jQuery.Deferred.exceptionHook( e, 3845 process.stackTrace ); 3846 } 3847 3848 // Support: Promises/A+ section 2.3.3.3.4.1 3849 // https://promisesaplus.com/#point-61 3850 // Ignore post-resolution exceptions 3851 if ( depth + 1 >= maxDepth ) { 3852 3853 // Only substitute handlers pass on context 3854 // and multiple values (non-spec behavior) 3855 if ( handler !== Thrower ) { 3856 that = undefined; 3857 args = [ e ]; 3858 } 3859 3860 deferred.rejectWith( that, args ); 3861 } 3862 } 3863 }; 3864
vendor: 10,679 bytes, lines 3865-4313
3865 // Support: Promises/A+ section 2.3.3.3.1 3866 // https://promisesaplus.com/#point-57 3867 // Re-resolve promises immediately to dodge false rejection from 3868 // subsequent errors 3869 if ( depth ) { 3870 process(); 3871 } else { 3872 3873 // Call an optional hook to record the stack, in case of exception 3874 // since it's otherwise lost when execution goes async 3875 if ( jQuery.Deferred.getStackHook ) { 3876 process.stackTrace = jQuery.Deferred.getStackHook(); 3877 } 3878 window.setTimeout( process ); 3879 } 3880 }; 3881 } 3882 3883 return jQuery.Deferred( function( newDefer ) { 3884 3885 // progress_handlers.add( ... ) 3886 tuples[ 0 ][ 3 ].add( 3887 resolve( 3888 0, 3889 newDefer, 3890 isFunction( onProgress ) ? 3891 onProgress : 3892 Identity, 3893 newDefer.notifyWith 3894 ) 3895 ); 3896 3897 // fulfilled_handlers.add( ... ) 3898 tuples[ 1 ][ 3 ].add( 3899 resolve( 3900 0, 3901 newDefer, 3902 isFunction( onFulfilled ) ? 3903 onFulfilled : 3904 Identity 3905 ) 3906 ); 3907 3908 // rejected_handlers.add( ... ) 3909 tuples[ 2 ][ 3 ].add( 3910 resolve( 3911 0, 3912 newDefer, 3913 isFunction( onRejected ) ? 3914 onRejected : 3915 Thrower 3916 ) 3917 ); 3918 } ).promise(); 3919 }, 3920 3921 // Get a promise for this deferred 3922 // If obj is provided, the promise aspect is added to the object 3923 promise: function( obj ) { 3924 return obj != null ? jQuery.extend( obj, promise ) : promise; 3925 } 3926 }, 3927 deferred = {}; 3928 3929 // Add list-specific methods 3930 jQuery.each( tuples, function( i, tuple ) { 3931 var list = tuple[ 2 ], 3932 stateString = tuple[ 5 ]; 3933 3934 // promise.progress = list.add 3935 // promise.done = list.add 3936 // promise.fail = list.add 3937 promise[ tuple[ 1 ] ] = list.add; 3938 3939 // Handle state 3940 if ( stateString ) { 3941 list.add( 3942 function() { 3943 3944 // state = "resolved" (i.e., fulfilled) 3945 // state = "rejected" 3946 state = stateString; 3947 }, 3948 3949 // rejected_callbacks.disable 3950 // fulfilled_callbacks.disable 3951 tuples[ 3 - i ][ 2 ].disable, 3952 3953 // rejected_handlers.disable 3954 // fulfilled_handlers.disable 3955 tuples[ 3 - i ][ 3 ].disable, 3956 3957 // progress_callbacks.lock 3958 tuples[ 0 ][ 2 ].lock, 3959 3960 // progress_handlers.lock 3961 tuples[ 0 ][ 3 ].lock 3962 ); 3963 } 3964 3965 // progress_handlers.fire 3966 // fulfilled_handlers.fire 3967 // rejected_handlers.fire 3968 list.add( tuple[ 3 ].fire ); 3969 3970 // deferred.notify = function() { deferred.notifyWith(...) } 3971 // deferred.resolve = function() { deferred.resolveWith(...) } 3972 // deferred.reject = function() { deferred.rejectWith(...) } 3973 deferred[ tuple[ 0 ] ] = function() { 3974 deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); 3975 return this; 3976 }; 3977 3978 // deferred.notifyWith = list.fireWith 3979 // deferred.resolveWith = list.fireWith 3980 // deferred.rejectWith = list.fireWith 3981 deferred[ tuple[ 0 ] + "With" ] = list.fireWith; 3982 } ); 3983 3984 // Make the deferred a promise 3985 promise.promise( deferred ); 3986 3987 // Call given func if any 3988 if ( func ) { 3989 func.call( deferred, deferred ); 3990 } 3991 3992 // All done! 3993 return deferred; 3994 }, 3995 3996 // Deferred helper 3997 when: function( singleValue ) { 3998 var 3999 4000 // count of uncompleted subordinates 4001 remaining = arguments.length, 4002 4003 // count of unprocessed arguments 4004 i = remaining, 4005 4006 // subordinate fulfillment data 4007 resolveContexts = Array( i ), 4008 resolveValues = slice.call( arguments ), 4009 4010 // the primary Deferred 4011 primary = jQuery.Deferred(), 4012 4013 // subordinate callback factory 4014 updateFunc = function( i ) { 4015 return function( value ) { 4016 resolveContexts[ i ] = this; 4017 resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; 4018 if ( !( --remaining ) ) { 4019 primary.resolveWith( resolveContexts, resolveValues ); 4020 } 4021 }; 4022 }; 4023 4024 // Single- and empty arguments are adopted like Promise.resolve 4025 if ( remaining <= 1 ) { 4026 adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, 4027 !remaining ); 4028 4029 // Use .then() to unwrap secondary thenables (cf. gh-3000) 4030 if ( primary.state() === "pending" || 4031 isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { 4032 4033 return primary.then(); 4034 } 4035 } 4036 4037 // Multiple arguments are aggregated like Promise.all array elements 4038 while ( i-- ) { 4039 adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); 4040 } 4041 4042 return primary.promise(); 4043 } 4044} ); 4045 4046 4047// These usually indicate a programmer mistake during development, 4048// warn about them ASAP rather than swallowing them by default. 4049var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; 4050 4051jQuery.Deferred.exceptionHook = function( error, stack ) { 4052 4053 // Support: IE 8 - 9 only 4054 // Console exists when dev tools are open, which can happen at any time 4055 if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { 4056 window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); 4057 } 4058}; 4059 4060 4061 4062 4063jQuery.readyException = function( error ) { 4064 window.setTimeout( function() { 4065 throw error; 4066 } ); 4067}; 4068 4069 4070 4071 4072// The deferred used on DOM ready 4073var readyList = jQuery.Deferred(); 4074 4075jQuery.fn.ready = function( fn ) { 4076 4077 readyList 4078 .then( fn ) 4079 4080 // Wrap jQuery.readyException in a function so that the lookup 4081 // happens at the time of error handling instead of callback 4082 // registration. 4083 .catch( function( error ) { 4084 jQuery.readyException( error ); 4085 } ); 4086 4087 return this; 4088}; 4089 4090jQuery.extend( { 4091 4092 // Is the DOM ready to be used? Set to true once it occurs. 4093 isReady: false, 4094 4095 // A counter to track how many items to wait for before 4096 // the ready event fires. See trac-6781 4097 readyWait: 1, 4098 4099 // Handle when the DOM is ready 4100 ready: function( wait ) { 4101 4102 // Abort if there are pending holds or we're already ready 4103 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { 4104 return; 4105 } 4106 4107 // Remember that the DOM is ready 4108 jQuery.isReady = true; 4109 4110 // If a normal DOM Ready event fired, decrement, and wait if need be 4111 if ( wait !== true && --jQuery.readyWait > 0 ) { 4112 return; 4113 } 4114 4115 // If there are functions bound, to execute 4116 readyList.resolveWith( document, [ jQuery ] ); 4117 } 4118} ); 4119 4120jQuery.ready.then = readyList.then; 4121 4122// The ready event handler and self cleanup method 4123function completed() { 4124 document.removeEventListener( "DOMContentLoaded", completed ); 4125 window.removeEventListener( "load", completed ); 4126 jQuery.ready(); 4127} 4128 4129// Catch cases where $(document).ready() is called 4130// after the browser event has already occurred. 4131// Support: IE <=9 - 10 only 4132// Older IE sometimes signals "interactive" too soon 4133if ( document.readyState === "complete" || 4134 ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { 4135 4136 // Handle it asynchronously to allow scripts the opportunity to delay ready 4137 window.setTimeout( jQuery.ready ); 4138 4139} else { 4140 4141 // Use the handy event callback 4142 document.addEventListener( "DOMContentLoaded", completed ); 4143 4144 // A fallback to window.onload, that will always work 4145 window.addEventListener( "load", completed ); 4146} 4147 4148 4149 4150 4151// Multifunctional method to get and set values of a collection 4152// The value/s can optionally be executed if it's a function 4153var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { 4154 var i = 0, 4155 len = elems.length, 4156 bulk = key == null; 4157 4158 // Sets many values 4159 if ( toType( key ) === "object" ) { 4160 chainable = true; 4161 for ( i in key ) { 4162 access( elems, fn, i, key[ i ], true, emptyGet, raw ); 4163 } 4164 4165 // Sets one value 4166 } else if ( value !== undefined ) { 4167 chainable = true; 4168 4169 if ( !isFunction( value ) ) { 4170 raw = true; 4171 } 4172 4173 if ( bulk ) { 4174 4175 // Bulk operations run against the entire set 4176 if ( raw ) { 4177 fn.call( elems, value ); 4178 fn = null; 4179 4180 // ...except when executing function values 4181 } else { 4182 bulk = fn; 4183 fn = function( elem, _key, value ) { 4184 return bulk.call( jQuery( elem ), value ); 4185 }; 4186 } 4187 } 4188 4189 if ( fn ) { 4190 for ( ; i < len; i++ ) { 4191 fn( 4192 elems[ i ], key, raw ? 4193 value : 4194 value.call( elems[ i ], i, fn( elems[ i ], key ) ) 4195 ); 4196 } 4197 } 4198 } 4199 4200 if ( chainable ) { 4201 return elems; 4202 } 4203 4204 // Gets 4205 if ( bulk ) { 4206 return fn.call( elems ); 4207 } 4208 4209 return len ? fn( elems[ 0 ], key ) : emptyGet; 4210}; 4211 4212 4213// Matches dashed string for camelizing 4214var rmsPrefix = /^-ms-/, 4215 rdashAlpha = /-([a-z])/g; 4216 4217// Used by camelCase as callback to replace() 4218function fcamelCase( _all, letter ) { 4219 return letter.toUpperCase(); 4220} 4221 4222// Convert dashed to camelCase; used by the css and data modules 4223// Support: IE <=9 - 11, Edge 12 - 15 4224// Microsoft forgot to hump their vendor prefix (trac-9572) 4225function camelCase( string ) { 4226 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 4227} 4228var acceptData = function( owner ) { 4229 4230 // Accepts only: 4231 // - Node 4232 // - Node.ELEMENT_NODE 4233 // - Node.DOCUMENT_NODE 4234 // - Object 4235 // - Any 4236 return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); 4237}; 4238 4239 4240 4241 4242function Data() { 4243 this.expando = jQuery.expando + Data.uid++; 4244} 4245 4246Data.uid = 1; 4247 4248Data.prototype = { 4249 4250 cache: function( owner ) { 4251 4252 // Check if the owner object already has a cache 4253 var value = owner[ this.expando ]; 4254 4255 // If not, create one 4256 if ( !value ) { 4257 value = {}; 4258 4259 // We can accept data for non-element nodes in modern browsers, 4260 // but we should not, see trac-8335. 4261 // Always return an empty object. 4262 if ( acceptData( owner ) ) { 4263 4264 // If it is a node unlikely to be stringify-ed or looped over 4265 // use plain assignment 4266 if ( owner.nodeType ) { 4267 owner[ this.expando ] = value; 4268 4269 // Otherwise secure it in a non-enumerable property 4270 // configurable must be true to allow the property to be 4271 // deleted when data is removed 4272 } else { 4273 Object.defineProperty( owner, this.expando, { 4274 value: value, 4275 configurable: true 4276 } ); 4277 } 4278 } 4279 } 4280 4281 return value; 4282 }, 4283 set: function( owner, data, value ) { 4284 var prop, 4285 cache = this.cache( owner ); 4286 4287 // Handle: [ owner, key, value ] args 4288 // Always use camelCase key (gh-2257) 4289 if ( typeof data === "string" ) { 4290 cache[ camelCase( data ) ] = value; 4291 4292 // Handle: [ owner, { properties } ] args 4293 } else { 4294 4295 // Copy the properties one-by-one to the cache object 4296 for ( prop in data ) { 4297 cache[ camelCase( prop ) ] = data[ prop ]; 4298 } 4299 } 4300 return cache; 4301 }, 4302 get: function( owner, key ) { 4303 return key === undefined ? 4304 this.cache( owner ) : 4305 4306 // Always use camelCase key (gh-2257) 4307 owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; 4308 }, 4309 access: function( owner, key, value ) { 4310 4311 // In cases where either: 4312 // 4313 // 1. No key was specified
vendor: 4,579 bytes, lines 4314-4497
4314 // 2. A string key was specified, but no value provided 4315 // 4316 // Take the "read" path and allow the get method to determine 4317 // which value to return, respectively either: 4318 // 4319 // 1. The entire cache object 4320 // 2. The data stored at the key 4321 // 4322 if ( key === undefined || 4323 ( ( key && typeof key === "string" ) && value === undefined ) ) { 4324 4325 return this.get( owner, key ); 4326 } 4327 4328 // When the key is not a string, or both a key and value 4329 // are specified, set or extend (existing objects) with either: 4330 // 4331 // 1. An object of properties 4332 // 2. A key and value 4333 // 4334 this.set( owner, key, value ); 4335 4336 // Since the "set" path can have two possible entry points 4337 // return the expected data based on which path was taken[*] 4338 return value !== undefined ? value : key; 4339 }, 4340 remove: function( owner, key ) { 4341 var i, 4342 cache = owner[ this.expando ]; 4343 4344 if ( cache === undefined ) { 4345 return; 4346 } 4347 4348 if ( key !== undefined ) { 4349 4350 // Support array or space separated string of keys 4351 if ( Array.isArray( key ) ) { 4352 4353 // If key is an array of keys... 4354 // We always set camelCase keys, so remove that. 4355 key = key.map( camelCase ); 4356 } else { 4357 key = camelCase( key ); 4358 4359 // If a key with the spaces exists, use it. 4360 // Otherwise, create an array by matching non-whitespace 4361 key = key in cache ? 4362 [ key ] : 4363 ( key.match( rnothtmlwhite ) || [] ); 4364 } 4365 4366 i = key.length; 4367 4368 while ( i-- ) { 4369 delete cache[ key[ i ] ]; 4370 } 4371 } 4372 4373 // Remove the expando if there's no more data 4374 if ( key === undefined || jQuery.isEmptyObject( cache ) ) { 4375 4376 // Support: Chrome <=35 - 45 4377 // Webkit & Blink performance suffers when deleting properties 4378 // from DOM nodes, so set to undefined instead 4379 // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) 4380 if ( owner.nodeType ) { 4381 owner[ this.expando ] = undefined; 4382 } else { 4383 delete owner[ this.expando ]; 4384 } 4385 } 4386 }, 4387 hasData: function( owner ) { 4388 var cache = owner[ this.expando ]; 4389 return cache !== undefined && !jQuery.isEmptyObject( cache ); 4390 } 4391}; 4392var dataPriv = new Data(); 4393 4394var dataUser = new Data(); 4395 4396 4397 4398// Implementation Summary 4399// 4400// 1. Enforce API surface and semantic compatibility with 1.9.x branch 4401// 2. Improve the module's maintainability by reducing the storage 4402// paths to a single mechanism. 4403// 3. Use the same single mechanism to support "private" and "user" data. 4404// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) 4405// 5. Avoid exposing implementation details on user objects (eg. expando properties) 4406// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 4407 4408var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, 4409 rmultiDash = /[A-Z]/g; 4410 4411function getData( data ) { 4412 if ( data === "true" ) { 4413 return true; 4414 } 4415 4416 if ( data === "false" ) { 4417 return false; 4418 } 4419 4420 if ( data === "null" ) { 4421 return null; 4422 } 4423 4424 // Only convert to a number if it doesn't change the string 4425 if ( data === +data + "" ) { 4426 return +data; 4427 } 4428 4429 if ( rbrace.test( data ) ) { 4430 return JSON.parse( data ); 4431 } 4432 4433 return data; 4434} 4435 4436function dataAttr( elem, key, data ) { 4437 var name; 4438 4439 // If nothing was found internally, try to fetch any 4440 // data from the HTML5 data-* attribute 4441 if ( data === undefined && elem.nodeType === 1 ) { 4442 name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); 4443 data = elem.getAttribute( name ); 4444 4445 if ( typeof data === "string" ) { 4446 try { 4447 data = getData( data ); 4448 } catch ( e ) {} 4449 4450 // Make sure we set the data so it isn't changed later 4451 dataUser.set( elem, key, data ); 4452 } else { 4453 data = undefined; 4454 } 4455 } 4456 return data; 4457} 4458 4459jQuery.extend( { 4460 hasData: function( elem ) { 4461 return dataUser.hasData( elem ) || dataPriv.hasData( elem ); 4462 }, 4463 4464 data: function( elem, name, data ) { 4465 return dataUser.access( elem, name, data ); 4466 }, 4467 4468 removeData: function( elem, name ) { 4469 dataUser.remove( elem, name ); 4470 }, 4471 4472 // TODO: Now that all calls to _data and _removeData have been replaced 4473 // with direct calls to dataPriv methods, these can be deprecated. 4474 _data: function( elem, name, data ) { 4475 return dataPriv.access( elem, name, data ); 4476 }, 4477 4478 _removeData: function( elem, name ) { 4479 dataPriv.remove( elem, name ); 4480 } 4481} ); 4482 4483jQuery.fn.extend( { 4484 data: function( key, value ) { 4485 var i, name, data, 4486 elem = this[ 0 ], 4487 attrs = elem && elem.attributes; 4488 4489 // Gets all values 4490 if ( key === undefined ) { 4491 if ( this.length ) { 4492 data = dataUser.get( elem ); 4493 4494 if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { 4495 i = attrs.length; 4496 while ( i-- ) { 4497
vendor: 4,119 bytes, lines 4498-4672
4498 // Support: IE 11 only 4499 // The attrs elements can be null (trac-14894) 4500 if ( attrs[ i ] ) { 4501 name = attrs[ i ].name; 4502 if ( name.indexOf( "data-" ) === 0 ) { 4503 name = camelCase( name.slice( 5 ) ); 4504 dataAttr( elem, name, data[ name ] ); 4505 } 4506 } 4507 } 4508 dataPriv.set( elem, "hasDataAttrs", true ); 4509 } 4510 } 4511 4512 return data; 4513 } 4514 4515 // Sets multiple values 4516 if ( typeof key === "object" ) { 4517 return this.each( function() { 4518 dataUser.set( this, key ); 4519 } ); 4520 } 4521 4522 return access( this, function( value ) { 4523 var data; 4524 4525 // The calling jQuery object (element matches) is not empty 4526 // (and therefore has an element appears at this[ 0 ]) and the 4527 // `value` parameter was not undefined. An empty jQuery object 4528 // will result in `undefined` for elem = this[ 0 ] which will 4529 // throw an exception if an attempt to read a data cache is made. 4530 if ( elem && value === undefined ) { 4531 4532 // Attempt to get data from the cache 4533 // The key will always be camelCased in Data 4534 data = dataUser.get( elem, key ); 4535 if ( data !== undefined ) { 4536 return data; 4537 } 4538 4539 // Attempt to "discover" the data in 4540 // HTML5 custom data-* attrs 4541 data = dataAttr( elem, key ); 4542 if ( data !== undefined ) { 4543 return data; 4544 } 4545 4546 // We tried really hard, but the data doesn't exist. 4547 return; 4548 } 4549 4550 // Set the data... 4551 this.each( function() { 4552 4553 // We always store the camelCased key 4554 dataUser.set( this, key, value ); 4555 } ); 4556 }, null, value, arguments.length > 1, null, true ); 4557 }, 4558 4559 removeData: function( key ) { 4560 return this.each( function() { 4561 dataUser.remove( this, key ); 4562 } ); 4563 } 4564} ); 4565 4566 4567jQuery.extend( { 4568 queue: function( elem, type, data ) { 4569 var queue; 4570 4571 if ( elem ) { 4572 type = ( type || "fx" ) + "queue"; 4573 queue = dataPriv.get( elem, type ); 4574 4575 // Speed up dequeue by getting out quickly if this is just a lookup 4576 if ( data ) { 4577 if ( !queue || Array.isArray( data ) ) { 4578 queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); 4579 } else { 4580 queue.push( data ); 4581 } 4582 } 4583 return queue || []; 4584 } 4585 }, 4586 4587 dequeue: function( elem, type ) { 4588 type = type || "fx"; 4589 4590 var queue = jQuery.queue( elem, type ), 4591 startLength = queue.length, 4592 fn = queue.shift(), 4593 hooks = jQuery._queueHooks( elem, type ), 4594 next = function() { 4595 jQuery.dequeue( elem, type ); 4596 }; 4597 4598 // If the fx queue is dequeued, always remove the progress sentinel 4599 if ( fn === "inprogress" ) { 4600 fn = queue.shift(); 4601 startLength--; 4602 } 4603 4604 if ( fn ) { 4605 4606 // Add a progress sentinel to prevent the fx queue from being 4607 // automatically dequeued 4608 if ( type === "fx" ) { 4609 queue.unshift( "inprogress" ); 4610 } 4611 4612 // Clear up the last queue stop function 4613 delete hooks.stop; 4614 fn.call( elem, next, hooks ); 4615 } 4616 4617 if ( !startLength && hooks ) { 4618 hooks.empty.fire(); 4619 } 4620 }, 4621 4622 // Not public - generate a queueHooks object, or return the current one 4623 _queueHooks: function( elem, type ) { 4624 var key = type + "queueHooks"; 4625 return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { 4626 empty: jQuery.Callbacks( "once memory" ).add( function() { 4627 dataPriv.remove( elem, [ type + "queue", key ] ); 4628 } ) 4629 } ); 4630 } 4631} ); 4632 4633jQuery.fn.extend( { 4634 queue: function( type, data ) { 4635 var setter = 2; 4636 4637 if ( typeof type !== "string" ) { 4638 data = type; 4639 type = "fx"; 4640 setter--; 4641 } 4642 4643 if ( arguments.length < setter ) { 4644 return jQuery.queue( this[ 0 ], type ); 4645 } 4646 4647 return data === undefined ? 4648 this : 4649 this.each( function() { 4650 var queue = jQuery.queue( this, type, data ); 4651 4652 // Ensure a hooks for this queue 4653 jQuery._queueHooks( this, type ); 4654 4655 if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { 4656 jQuery.dequeue( this, type ); 4657 } 4658 } ); 4659 }, 4660 dequeue: function( type ) { 4661 return this.each( function() { 4662 jQuery.dequeue( this, type ); 4663 } ); 4664 }, 4665 clearQueue: function( type ) { 4666 return this.queue( type || "fx", [] ); 4667 }, 4668 4669 // Get a promise resolved when queues of a certain type 4670 // are emptied (fx is the type by default) 4671 promise: function( type, obj ) { 4672 var tmp,
vendor: 6,339 bytes, lines 4673-4921
4673 count = 1, 4674 defer = jQuery.Deferred(), 4675 elements = this, 4676 i = this.length, 4677 resolve = function() { 4678 if ( !( --count ) ) { 4679 defer.resolveWith( elements, [ elements ] ); 4680 } 4681 }; 4682 4683 if ( typeof type !== "string" ) { 4684 obj = type; 4685 type = undefined; 4686 } 4687 type = type || "fx"; 4688 4689 while ( i-- ) { 4690 tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); 4691 if ( tmp && tmp.empty ) { 4692 count++; 4693 tmp.empty.add( resolve ); 4694 } 4695 } 4696 resolve(); 4697 return defer.promise( obj ); 4698 } 4699} ); 4700var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; 4701 4702var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); 4703 4704 4705var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; 4706 4707var documentElement = document.documentElement; 4708 4709 4710 4711 var isAttached = function( elem ) { 4712 return jQuery.contains( elem.ownerDocument, elem ); 4713 }, 4714 composed = { composed: true }; 4715 4716 // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only 4717 // Check attachment across shadow DOM boundaries when possible (gh-3504) 4718 // Support: iOS 10.0-10.2 only 4719 // Early iOS 10 versions support `attachShadow` but not `getRootNode`, 4720 // leading to errors. We need to check for `getRootNode`. 4721 if ( documentElement.getRootNode ) { 4722 isAttached = function( elem ) { 4723 return jQuery.contains( elem.ownerDocument, elem ) || 4724 elem.getRootNode( composed ) === elem.ownerDocument; 4725 }; 4726 } 4727var isHiddenWithinTree = function( elem, el ) { 4728 4729 // isHiddenWithinTree might be called from jQuery#filter function; 4730 // in that case, element will be second argument 4731 elem = el || elem; 4732 4733 // Inline style trumps all 4734 return elem.style.display === "none" || 4735 elem.style.display === "" && 4736 4737 // Otherwise, check computed style 4738 // Support: Firefox <=43 - 45 4739 // Disconnected elements can have computed display: none, so first confirm that elem is 4740 // in the document. 4741 isAttached( elem ) && 4742 4743 jQuery.css( elem, "display" ) === "none"; 4744 }; 4745 4746 4747 4748function adjustCSS( elem, prop, valueParts, tween ) { 4749 var adjusted, scale, 4750 maxIterations = 20, 4751 currentValue = tween ? 4752 function() { 4753 return tween.cur(); 4754 } : 4755 function() { 4756 return jQuery.css( elem, prop, "" ); 4757 }, 4758 initial = currentValue(), 4759 unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), 4760 4761 // Starting value computation is required for potential unit mismatches 4762 initialInUnit = elem.nodeType && 4763 ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && 4764 rcssNum.exec( jQuery.css( elem, prop ) ); 4765 4766 if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { 4767 4768 // Support: Firefox <=54 4769 // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) 4770 initial = initial / 2; 4771 4772 // Trust units reported by jQuery.css 4773 unit = unit || initialInUnit[ 3 ]; 4774 4775 // Iteratively approximate from a nonzero starting point 4776 initialInUnit = +initial || 1; 4777 4778 while ( maxIterations-- ) { 4779 4780 // Evaluate and update our best guess (doubling guesses that zero out). 4781 // Finish if the scale equals or crosses 1 (making the old*new product non-positive). 4782 jQuery.style( elem, prop, initialInUnit + unit ); 4783 if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { 4784 maxIterations = 0; 4785 } 4786 initialInUnit = initialInUnit / scale; 4787 4788 } 4789 4790 initialInUnit = initialInUnit * 2; 4791 jQuery.style( elem, prop, initialInUnit + unit ); 4792 4793 // Make sure we update the tween properties later on 4794 valueParts = valueParts || []; 4795 } 4796 4797 if ( valueParts ) { 4798 initialInUnit = +initialInUnit || +initial || 0; 4799 4800 // Apply relative offset (+=/-=) if specified 4801 adjusted = valueParts[ 1 ] ? 4802 initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : 4803 +valueParts[ 2 ]; 4804 if ( tween ) { 4805 tween.unit = unit; 4806 tween.start = initialInUnit; 4807 tween.end = adjusted; 4808 } 4809 } 4810 return adjusted; 4811} 4812 4813 4814var defaultDisplayMap = {}; 4815 4816function getDefaultDisplay( elem ) { 4817 var temp, 4818 doc = elem.ownerDocument, 4819 nodeName = elem.nodeName, 4820 display = defaultDisplayMap[ nodeName ]; 4821 4822 if ( display ) { 4823 return display; 4824 } 4825 4826 temp = doc.body.appendChild( doc.createElement( nodeName ) ); 4827 display = jQuery.css( temp, "display" ); 4828 4829 temp.parentNode.removeChild( temp ); 4830 4831 if ( display === "none" ) { 4832 display = "block"; 4833 } 4834 defaultDisplayMap[ nodeName ] = display; 4835 4836 return display; 4837} 4838 4839function showHide( elements, show ) { 4840 var display, elem, 4841 values = [], 4842 index = 0, 4843 length = elements.length; 4844 4845 // Determine new display value for elements that need to change 4846 for ( ; index < length; index++ ) { 4847 elem = elements[ index ]; 4848 if ( !elem.style ) { 4849 continue; 4850 } 4851 4852 display = elem.style.display; 4853 if ( show ) { 4854 4855 // Since we force visibility upon cascade-hidden elements, an immediate (and slow) 4856 // check is required in this first loop unless we have a nonempty display value (either 4857 // inline or about-to-be-restored) 4858 if ( display === "none" ) { 4859 values[ index ] = dataPriv.get( elem, "display" ) || null; 4860 if ( !values[ index ] ) { 4861 elem.style.display = ""; 4862 } 4863 } 4864 if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { 4865 values[ index ] = getDefaultDisplay( elem ); 4866 } 4867 } else { 4868 if ( display !== "none" ) { 4869 values[ index ] = "none"; 4870 4871 // Remember what we're overwriting 4872 dataPriv.set( elem, "display", display ); 4873 } 4874 } 4875 } 4876 4877 // Set the display of the elements in a second loop to avoid constant reflow 4878 for ( index = 0; index < length; index++ ) { 4879 if ( values[ index ] != null ) { 4880 elements[ index ].style.display = values[ index ]; 4881 } 4882 } 4883 4884 return elements; 4885} 4886 4887jQuery.fn.extend( { 4888 show: function() { 4889 return showHide( this, true ); 4890 }, 4891 hide: function() { 4892 return showHide( this ); 4893 }, 4894 toggle: function( state ) { 4895 if ( typeof state === "boolean" ) { 4896 return state ? this.show() : this.hide(); 4897 } 4898 4899 return this.each( function() { 4900 if ( isHiddenWithinTree( this ) ) { 4901 jQuery( this ).show(); 4902 } else { 4903 jQuery( this ).hide(); 4904 } 4905 } ); 4906 } 4907} ); 4908var rcheckableType = ( /^(?:checkbox|radio)$/i ); 4909 4910var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); 4911 4912var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); 4913 4914 4915 4916( function() { 4917 var fragment = document.createDocumentFragment(), 4918 div = fragment.appendChild( document.createElement( "div" ) ), 4919 input = document.createElement( "input" ); 4920 4921 // Support: Android 4.0 - 4.3 only
vendor: 4,796 bytes, lines 4922-5109
4922 // Check state lost if the name is set (trac-11217) 4923 // Support: Windows Web Apps (WWA) 4924 // `name` and `type` must use .setAttribute for WWA (trac-14901) 4925 input.setAttribute( "type", "radio" ); 4926 input.setAttribute( "checked", "checked" ); 4927 input.setAttribute( "name", "t" ); 4928 4929 div.appendChild( input ); 4930 4931 // Support: Android <=4.1 only 4932 // Older WebKit doesn't clone checked state correctly in fragments 4933 support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 4934 4935 // Support: IE <=11 only 4936 // Make sure textarea (and checkbox) defaultValue is properly cloned 4937 div.innerHTML = "<textarea>x</textarea>"; 4938 support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 4939 4940 // Support: IE <=9 only 4941 // IE <=9 replaces <option> tags with their contents when inserted outside of 4942 // the select element. 4943 div.innerHTML = "<option></option>"; 4944 support.option = !!div.lastChild; 4945} )(); 4946 4947 4948// We have to close these tags to support XHTML (trac-13200) 4949var wrapMap = { 4950 4951 // XHTML parsers do not magically insert elements in the 4952 // same way that tag soup parsers do. So we cannot shorten 4953 // this by omitting <tbody> or other required elements. 4954 thead: [ 1, "<table>", "</table>" ], 4955 col: [ 2, "<table><colgroup>", "</colgroup></table>" ], 4956 tr: [ 2, "<table><tbody>", "</tbody></table>" ], 4957 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], 4958 4959 _default: [ 0, "", "" ] 4960}; 4961 4962wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 4963wrapMap.th = wrapMap.td; 4964 4965// Support: IE <=9 only 4966if ( !support.option ) { 4967 wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ]; 4968} 4969 4970 4971function getAll( context, tag ) { 4972 4973 // Support: IE <=9 - 11 only 4974 // Use typeof to avoid zero-argument method invocation on host objects (trac-15151) 4975 var ret; 4976 4977 if ( typeof context.getElementsByTagName !== "undefined" ) { 4978 ret = context.getElementsByTagName( tag || "*" ); 4979 4980 } else if ( typeof context.querySelectorAll !== "undefined" ) { 4981 ret = context.querySelectorAll( tag || "*" ); 4982 4983 } else { 4984 ret = []; 4985 } 4986 4987 if ( tag === undefined || tag && nodeName( context, tag ) ) { 4988 return jQuery.merge( [ context ], ret ); 4989 } 4990 4991 return ret; 4992} 4993 4994 4995// Mark scripts as having already been evaluated 4996function setGlobalEval( elems, refElements ) { 4997 var i = 0, 4998 l = elems.length; 4999 5000 for ( ; i < l; i++ ) { 5001 dataPriv.set( 5002 elems[ i ], 5003 "globalEval", 5004 !refElements || dataPriv.get( refElements[ i ], "globalEval" ) 5005 ); 5006 } 5007} 5008 5009 5010var rhtml = /<|&#?\w+;/; 5011 5012function buildFragment( elems, context, scripts, selection, ignored ) { 5013 var elem, tmp, tag, wrap, attached, j, 5014 fragment = context.createDocumentFragment(), 5015 nodes = [], 5016 i = 0, 5017 l = elems.length; 5018 5019 for ( ; i < l; i++ ) { 5020 elem = elems[ i ]; 5021 5022 if ( elem || elem === 0 ) { 5023 5024 // Add nodes directly 5025 if ( toType( elem ) === "object" ) { 5026 5027 // Support: Android <=4.0 only, PhantomJS 1 only 5028 // push.apply(_, arraylike) throws on ancient WebKit 5029 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); 5030 5031 // Convert non-html into a text node 5032 } else if ( !rhtml.test( elem ) ) { 5033 nodes.push( context.createTextNode( elem ) ); 5034 5035 // Convert html into DOM nodes 5036 } else { 5037 tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); 5038 5039 // Deserialize a standard representation 5040 tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); 5041 wrap = wrapMap[ tag ] || wrapMap._default; 5042 tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; 5043 5044 // Descend through wrappers to the right content 5045 j = wrap[ 0 ]; 5046 while ( j-- ) { 5047 tmp = tmp.lastChild; 5048 } 5049 5050 // Support: Android <=4.0 only, PhantomJS 1 only 5051 // push.apply(_, arraylike) throws on ancient WebKit 5052 jQuery.merge( nodes, tmp.childNodes ); 5053 5054 // Remember the top-level container 5055 tmp = fragment.firstChild; 5056 5057 // Ensure the created nodes are orphaned (trac-12392) 5058 tmp.textContent = ""; 5059 } 5060 } 5061 } 5062 5063 // Remove wrapper from fragment 5064 fragment.textContent = ""; 5065 5066 i = 0; 5067 while ( ( elem = nodes[ i++ ] ) ) { 5068 5069 // Skip elements already in the context collection (trac-4087) 5070 if ( selection && jQuery.inArray( elem, selection ) > -1 ) { 5071 if ( ignored ) { 5072 ignored.push( elem ); 5073 } 5074 continue; 5075 } 5076 5077 attached = isAttached( elem ); 5078 5079 // Append to fragment 5080 tmp = getAll( fragment.appendChild( elem ), "script" ); 5081 5082 // Preserve script evaluation history 5083 if ( attached ) { 5084 setGlobalEval( tmp ); 5085 } 5086 5087 // Capture executables 5088 if ( scripts ) { 5089 j = 0; 5090 while ( ( elem = tmp[ j++ ] ) ) { 5091 if ( rscriptType.test( elem.type || "" ) ) { 5092 scripts.push( elem ); 5093 } 5094 } 5095 } 5096 } 5097 5098 return fragment; 5099} 5100 5101 5102var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; 5103 5104function returnTrue() { 5105 return true; 5106} 5107 5108function returnFalse() { 5109 return false;
vendor: 10,171 bytes, lines 5110-5464
5110} 5111 5112// Support: IE <=9 - 11+ 5113// focus() and blur() are asynchronous, except when they are no-op. 5114// So expect focus to be synchronous when the element is already active, 5115// and blur to be synchronous when the element is not already active. 5116// (focus and blur are always synchronous in other supported browsers, 5117// this just defines when we can count on it). 5118function expectSync( elem, type ) { 5119 return ( elem === safeActiveElement() ) === ( type === "focus" ); 5120} 5121 5122// Support: IE <=9 only 5123// Accessing document.activeElement can throw unexpectedly 5124// https://bugs.jquery.com/ticket/13393 5125function safeActiveElement() { 5126 try { 5127 return document.activeElement; 5128 } catch ( err ) { } 5129} 5130 5131function on( elem, types, selector, data, fn, one ) { 5132 var origFn, type; 5133 5134 // Types can be a map of types/handlers 5135 if ( typeof types === "object" ) { 5136 5137 // ( types-Object, selector, data ) 5138 if ( typeof selector !== "string" ) { 5139 5140 // ( types-Object, data ) 5141 data = data || selector; 5142 selector = undefined; 5143 } 5144 for ( type in types ) { 5145 on( elem, type, selector, data, types[ type ], one ); 5146 } 5147 return elem; 5148 } 5149 5150 if ( data == null && fn == null ) { 5151 5152 // ( types, fn ) 5153 fn = selector; 5154 data = selector = undefined; 5155 } else if ( fn == null ) { 5156 if ( typeof selector === "string" ) { 5157 5158 // ( types, selector, fn ) 5159 fn = data; 5160 data = undefined; 5161 } else { 5162 5163 // ( types, data, fn ) 5164 fn = data; 5165 data = selector; 5166 selector = undefined; 5167 } 5168 } 5169 if ( fn === false ) { 5170 fn = returnFalse; 5171 } else if ( !fn ) { 5172 return elem; 5173 } 5174 5175 if ( one === 1 ) { 5176 origFn = fn; 5177 fn = function( event ) { 5178 5179 // Can use an empty set, since event contains the info 5180 jQuery().off( event ); 5181 return origFn.apply( this, arguments ); 5182 }; 5183 5184 // Use same guid so caller can remove using origFn 5185 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); 5186 } 5187 return elem.each( function() { 5188 jQuery.event.add( this, types, fn, data, selector ); 5189 } ); 5190} 5191 5192/* 5193 * Helper functions for managing events -- not part of the public interface. 5194 * Props to Dean Edwards' addEvent library for many of the ideas. 5195 */ 5196jQuery.event = { 5197 5198 global: {}, 5199 5200 add: function( elem, types, handler, data, selector ) { 5201 5202 var handleObjIn, eventHandle, tmp, 5203 events, t, handleObj, 5204 special, handlers, type, namespaces, origType, 5205 elemData = dataPriv.get( elem ); 5206 5207 // Only attach events to objects that accept data 5208 if ( !acceptData( elem ) ) { 5209 return; 5210 } 5211 5212 // Caller can pass in an object of custom data in lieu of the handler 5213 if ( handler.handler ) { 5214 handleObjIn = handler; 5215 handler = handleObjIn.handler; 5216 selector = handleObjIn.selector; 5217 } 5218 5219 // Ensure that invalid selectors throw exceptions at attach time 5220 // Evaluate against documentElement in case elem is a non-element node (e.g., document) 5221 if ( selector ) { 5222 jQuery.find.matchesSelector( documentElement, selector ); 5223 } 5224 5225 // Make sure that the handler has a unique ID, used to find/remove it later 5226 if ( !handler.guid ) { 5227 handler.guid = jQuery.guid++; 5228 } 5229 5230 // Init the element's event structure and main handler, if this is the first 5231 if ( !( events = elemData.events ) ) { 5232 events = elemData.events = Object.create( null ); 5233 } 5234 if ( !( eventHandle = elemData.handle ) ) { 5235 eventHandle = elemData.handle = function( e ) { 5236 5237 // Discard the second event of a jQuery.event.trigger() and 5238 // when an event is called after a page has unloaded 5239 return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? 5240 jQuery.event.dispatch.apply( elem, arguments ) : undefined; 5241 }; 5242 } 5243 5244 // Handle multiple events separated by a space 5245 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; 5246 t = types.length; 5247 while ( t-- ) { 5248 tmp = rtypenamespace.exec( types[ t ] ) || []; 5249 type = origType = tmp[ 1 ]; 5250 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 5251 5252 // There *must* be a type, no attaching namespace-only handlers 5253 if ( !type ) { 5254 continue; 5255 } 5256 5257 // If event changes its type, use the special event handlers for the changed type 5258 special = jQuery.event.special[ type ] || {}; 5259 5260 // If selector defined, determine special event api type, otherwise given type 5261 type = ( selector ? special.delegateType : special.bindType ) || type; 5262 5263 // Update special based on newly reset type 5264 special = jQuery.event.special[ type ] || {}; 5265 5266 // handleObj is passed to all event handlers 5267 handleObj = jQuery.extend( { 5268 type: type, 5269 origType: origType, 5270 data: data, 5271 handler: handler, 5272 guid: handler.guid, 5273 selector: selector, 5274 needsContext: selector && jQuery.expr.match.needsContext.test( selector ), 5275 namespace: namespaces.join( "." ) 5276 }, handleObjIn ); 5277 5278 // Init the event handler queue if we're the first 5279 if ( !( handlers = events[ type ] ) ) { 5280 handlers = events[ type ] = []; 5281 handlers.delegateCount = 0; 5282 5283 // Only use addEventListener if the special events handler returns false 5284 if ( !special.setup || 5285 special.setup.call( elem, data, namespaces, eventHandle ) === false ) { 5286 5287 if ( elem.addEventListener ) { 5288 elem.addEventListener( type, eventHandle ); 5289 } 5290 } 5291 } 5292 5293 if ( special.add ) { 5294 special.add.call( elem, handleObj ); 5295 5296 if ( !handleObj.handler.guid ) { 5297 handleObj.handler.guid = handler.guid; 5298 } 5299 } 5300 5301 // Add to the element's handler list, delegates in front 5302 if ( selector ) { 5303 handlers.splice( handlers.delegateCount++, 0, handleObj ); 5304 } else { 5305 handlers.push( handleObj ); 5306 } 5307 5308 // Keep track of which events have ever been used, for event optimization 5309 jQuery.event.global[ type ] = true; 5310 } 5311 5312 }, 5313 5314 // Detach an event or set of events from an element 5315 remove: function( elem, types, handler, selector, mappedTypes ) { 5316 5317 var j, origCount, tmp, 5318 events, t, handleObj, 5319 special, handlers, type, namespaces, origType, 5320 elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); 5321 5322 if ( !elemData || !( events = elemData.events ) ) { 5323 return; 5324 } 5325 5326 // Once for each type.namespace in types; type may be omitted 5327 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; 5328 t = types.length; 5329 while ( t-- ) { 5330 tmp = rtypenamespace.exec( types[ t ] ) || []; 5331 type = origType = tmp[ 1 ]; 5332 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 5333 5334 // Unbind all events (on this namespace, if provided) for the element 5335 if ( !type ) { 5336 for ( type in events ) { 5337 jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); 5338 } 5339 continue; 5340 } 5341 5342 special = jQuery.event.special[ type ] || {}; 5343 type = ( selector ? special.delegateType : special.bindType ) || type; 5344 handlers = events[ type ] || []; 5345 tmp = tmp[ 2 ] && 5346 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); 5347 5348 // Remove matching events 5349 origCount = j = handlers.length; 5350 while ( j-- ) { 5351 handleObj = handlers[ j ]; 5352 5353 if ( ( mappedTypes || origType === handleObj.origType ) && 5354 ( !handler || handler.guid === handleObj.guid ) && 5355 ( !tmp || tmp.test( handleObj.namespace ) ) && 5356 ( !selector || selector === handleObj.selector || 5357 selector === "**" && handleObj.selector ) ) { 5358 handlers.splice( j, 1 ); 5359 5360 if ( handleObj.selector ) { 5361 handlers.delegateCount--; 5362 } 5363 if ( special.remove ) { 5364 special.remove.call( elem, handleObj ); 5365 } 5366 } 5367 } 5368 5369 // Remove generic event handler if we removed something and no more handlers exist 5370 // (avoids potential for endless recursion during removal of special event handlers) 5371 if ( origCount && !handlers.length ) { 5372 if ( !special.teardown || 5373 special.teardown.call( elem, namespaces, elemData.handle ) === false ) { 5374 5375 jQuery.removeEvent( elem, type, elemData.handle ); 5376 } 5377 5378 delete events[ type ]; 5379 } 5380 } 5381 5382 // Remove data and the expando if it's no longer used 5383 if ( jQuery.isEmptyObject( events ) ) { 5384 dataPriv.remove( elem, "handle events" ); 5385 } 5386 }, 5387 5388 dispatch: function( nativeEvent ) { 5389 5390 var i, j, ret, matched, handleObj, handlerQueue, 5391 args = new Array( arguments.length ), 5392 5393 // Make a writable jQuery.Event from the native event object 5394 event = jQuery.event.fix( nativeEvent ), 5395 5396 handlers = ( 5397 dataPriv.get( this, "events" ) || Object.create( null ) 5398 )[ event.type ] || [], 5399 special = jQuery.event.special[ event.type ] || {}; 5400 5401 // Use the fix-ed jQuery.Event rather than the (read-only) native event 5402 args[ 0 ] = event; 5403 5404 for ( i = 1; i < arguments.length; i++ ) { 5405 args[ i ] = arguments[ i ]; 5406 } 5407 5408 event.delegateTarget = this; 5409 5410 // Call the preDispatch hook for the mapped type, and let it bail if desired 5411 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { 5412 return; 5413 } 5414 5415 // Determine handlers 5416 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); 5417 5418 // Run delegates first; they may want to stop propagation beneath us 5419 i = 0; 5420 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { 5421 event.currentTarget = matched.elem; 5422 5423 j = 0; 5424 while ( ( handleObj = matched.handlers[ j++ ] ) && 5425 !event.isImmediatePropagationStopped() ) { 5426 5427 // If the event is namespaced, then each handler is only invoked if it is 5428 // specially universal or its namespaces are a superset of the event's. 5429 if ( !event.rnamespace || handleObj.namespace === false || 5430 event.rnamespace.test( handleObj.namespace ) ) { 5431 5432 event.handleObj = handleObj; 5433 event.data = handleObj.data; 5434 5435 ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || 5436 handleObj.handler ).apply( matched.elem, args ); 5437 5438 if ( ret !== undefined ) { 5439 if ( ( event.result = ret ) === false ) { 5440 event.preventDefault(); 5441 event.stopPropagation(); 5442 } 5443 } 5444 } 5445 } 5446 } 5447 5448 // Call the postDispatch hook for the mapped type 5449 if ( special.postDispatch ) { 5450 special.postDispatch.call( this, event ); 5451 } 5452 5453 return event.result; 5454 }, 5455 5456 handlers: function( event, handlers ) { 5457 var i, handleObj, sel, matchedHandlers, matchedSelectors, 5458 handlerQueue = [], 5459 delegateCount = handlers.delegateCount, 5460 cur = event.target; 5461 5462 // Find delegate handlers 5463 if ( delegateCount && 5464
vendor: 21,304 bytes, lines 5465-6225
5465 // Support: IE <=9 5466 // Black-hole SVG <use> instance trees (trac-13180) 5467 cur.nodeType && 5468 5469 // Support: Firefox <=42 5470 // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) 5471 // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click 5472 // Support: IE 11 only 5473 // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) 5474 !( event.type === "click" && event.button >= 1 ) ) { 5475 5476 for ( ; cur !== this; cur = cur.parentNode || this ) { 5477 5478 // Don't check non-elements (trac-13208) 5479 // Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764) 5480 if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { 5481 matchedHandlers = []; 5482 matchedSelectors = {}; 5483 for ( i = 0; i < delegateCount; i++ ) { 5484 handleObj = handlers[ i ]; 5485 5486 // Don't conflict with Object.prototype properties (trac-13203) 5487 sel = handleObj.selector + " "; 5488 5489 if ( matchedSelectors[ sel ] === undefined ) { 5490 matchedSelectors[ sel ] = handleObj.needsContext ? 5491 jQuery( sel, this ).index( cur ) > -1 : 5492 jQuery.find( sel, this, null, [ cur ] ).length; 5493 } 5494 if ( matchedSelectors[ sel ] ) { 5495 matchedHandlers.push( handleObj ); 5496 } 5497 } 5498 if ( matchedHandlers.length ) { 5499 handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); 5500 } 5501 } 5502 } 5503 } 5504 5505 // Add the remaining (directly-bound) handlers 5506 cur = this; 5507 if ( delegateCount < handlers.length ) { 5508 handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); 5509 } 5510 5511 return handlerQueue; 5512 }, 5513 5514 addProp: function( name, hook ) { 5515 Object.defineProperty( jQuery.Event.prototype, name, { 5516 enumerable: true, 5517 configurable: true, 5518 5519 get: isFunction( hook ) ? 5520 function() { 5521 if ( this.originalEvent ) { 5522 return hook( this.originalEvent ); 5523 } 5524 } : 5525 function() { 5526 if ( this.originalEvent ) { 5527 return this.originalEvent[ name ]; 5528 } 5529 }, 5530 5531 set: function( value ) { 5532 Object.defineProperty( this, name, { 5533 enumerable: true, 5534 configurable: true, 5535 writable: true, 5536 value: value 5537 } ); 5538 } 5539 } ); 5540 }, 5541 5542 fix: function( originalEvent ) { 5543 return originalEvent[ jQuery.expando ] ? 5544 originalEvent : 5545 new jQuery.Event( originalEvent ); 5546 }, 5547 5548 special: { 5549 load: { 5550 5551 // Prevent triggered image.load events from bubbling to window.load 5552 noBubble: true 5553 }, 5554 click: { 5555 5556 // Utilize native event to ensure correct state for checkable inputs 5557 setup: function( data ) { 5558 5559 // For mutual compressibility with _default, replace `this` access with a local var. 5560 // `|| data` is dead code meant only to preserve the variable through minification. 5561 var el = this || data; 5562 5563 // Claim the first handler 5564 if ( rcheckableType.test( el.type ) && 5565 el.click && nodeName( el, "input" ) ) { 5566 5567 // dataPriv.set( el, "click", ... ) 5568 leverageNative( el, "click", returnTrue ); 5569 } 5570 5571 // Return false to allow normal processing in the caller 5572 return false; 5573 }, 5574 trigger: function( data ) { 5575 5576 // For mutual compressibility with _default, replace `this` access with a local var. 5577 // `|| data` is dead code meant only to preserve the variable through minification. 5578 var el = this || data; 5579 5580 // Force setup before triggering a click 5581 if ( rcheckableType.test( el.type ) && 5582 el.click && nodeName( el, "input" ) ) { 5583 5584 leverageNative( el, "click" ); 5585 } 5586 5587 // Return non-false to allow normal event-path propagation 5588 return true; 5589 }, 5590 5591 // For cross-browser consistency, suppress native .click() on links 5592 // Also prevent it if we're currently inside a leveraged native-event stack 5593 _default: function( event ) { 5594 var target = event.target; 5595 return rcheckableType.test( target.type ) && 5596 target.click && nodeName( target, "input" ) && 5597 dataPriv.get( target, "click" ) || 5598 nodeName( target, "a" ); 5599 } 5600 }, 5601 5602 beforeunload: { 5603 postDispatch: function( event ) { 5604 5605 // Support: Firefox 20+ 5606 // Firefox doesn't alert if the returnValue field is not set. 5607 if ( event.result !== undefined && event.originalEvent ) { 5608 event.originalEvent.returnValue = event.result; 5609 } 5610 } 5611 } 5612 } 5613}; 5614 5615// Ensure the presence of an event listener that handles manually-triggered 5616// synthetic events by interrupting progress until reinvoked in response to 5617// *native* events that it fires directly, ensuring that state changes have 5618// already occurred before other listeners are invoked. 5619function leverageNative( el, type, expectSync ) { 5620 5621 // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add 5622 if ( !expectSync ) { 5623 if ( dataPriv.get( el, type ) === undefined ) { 5624 jQuery.event.add( el, type, returnTrue ); 5625 } 5626 return; 5627 } 5628 5629 // Register the controller as a special universal handler for all event namespaces 5630 dataPriv.set( el, type, false ); 5631 jQuery.event.add( el, type, { 5632 namespace: false, 5633 handler: function( event ) { 5634 var notAsync, result, 5635 saved = dataPriv.get( this, type ); 5636 5637 if ( ( event.isTrigger & 1 ) && this[ type ] ) { 5638 5639 // Interrupt processing of the outer synthetic .trigger()ed event 5640 // Saved data should be false in such cases, but might be a leftover capture object 5641 // from an async native handler (gh-4350) 5642 if ( !saved.length ) { 5643 5644 // Store arguments for use when handling the inner native event 5645 // There will always be at least one argument (an event object), so this array 5646 // will not be confused with a leftover capture object. 5647 saved = slice.call( arguments ); 5648 dataPriv.set( this, type, saved ); 5649 5650 // Trigger the native event and capture its result 5651 // Support: IE <=9 - 11+ 5652 // focus() and blur() are asynchronous 5653 notAsync = expectSync( this, type ); 5654 this[ type ](); 5655 result = dataPriv.get( this, type ); 5656 if ( saved !== result || notAsync ) { 5657 dataPriv.set( this, type, false ); 5658 } else { 5659 result = {}; 5660 } 5661 if ( saved !== result ) { 5662 5663 // Cancel the outer synthetic event 5664 event.stopImmediatePropagation(); 5665 event.preventDefault(); 5666 5667 // Support: Chrome 86+ 5668 // In Chrome, if an element having a focusout handler is blurred by 5669 // clicking outside of it, it invokes the handler synchronously. If 5670 // that handler calls `.remove()` on the element, the data is cleared, 5671 // leaving `result` undefined. We need to guard against this. 5672 return result && result.value; 5673 } 5674 5675 // If this is an inner synthetic event for an event with a bubbling surrogate 5676 // (focus or blur), assume that the surrogate already propagated from triggering the 5677 // native event and prevent that from happening again here. 5678 // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the 5679 // bubbling surrogate propagates *after* the non-bubbling base), but that seems 5680 // less bad than duplication. 5681 } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { 5682 event.stopPropagation(); 5683 } 5684 5685 // If this is a native event triggered above, everything is now in order 5686 // Fire an inner synthetic event with the original arguments 5687 } else if ( saved.length ) { 5688 5689 // ...and capture the result 5690 dataPriv.set( this, type, { 5691 value: jQuery.event.trigger( 5692 5693 // Support: IE <=9 - 11+ 5694 // Extend with the prototype to reset the above stopImmediatePropagation() 5695 jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), 5696 saved.slice( 1 ), 5697 this 5698 ) 5699 } ); 5700 5701 // Abort handling of the native event 5702 event.stopImmediatePropagation(); 5703 } 5704 } 5705 } ); 5706} 5707 5708jQuery.removeEvent = function( elem, type, handle ) { 5709 5710 // This "if" is needed for plain objects 5711 if ( elem.removeEventListener ) { 5712 elem.removeEventListener( type, handle ); 5713 } 5714}; 5715 5716jQuery.Event = function( src, props ) { 5717 5718 // Allow instantiation without the 'new' keyword 5719 if ( !( this instanceof jQuery.Event ) ) { 5720 return new jQuery.Event( src, props ); 5721 } 5722 5723 // Event object 5724 if ( src && src.type ) { 5725 this.originalEvent = src; 5726 this.type = src.type; 5727 5728 // Events bubbling up the document may have been marked as prevented 5729 // by a handler lower down the tree; reflect the correct value. 5730 this.isDefaultPrevented = src.defaultPrevented || 5731 src.defaultPrevented === undefined && 5732 5733 // Support: Android <=2.3 only 5734 src.returnValue === false ? 5735 returnTrue : 5736 returnFalse; 5737 5738 // Create target properties 5739 // Support: Safari <=6 - 7 only 5740 // Target should not be a text node (trac-504, trac-13143) 5741 this.target = ( src.target && src.target.nodeType === 3 ) ? 5742 src.target.parentNode : 5743 src.target; 5744 5745 this.currentTarget = src.currentTarget; 5746 this.relatedTarget = src.relatedTarget; 5747 5748 // Event type 5749 } else { 5750 this.type = src; 5751 } 5752 5753 // Put explicitly provided properties onto the event object 5754 if ( props ) { 5755 jQuery.extend( this, props ); 5756 } 5757 5758 // Create a timestamp if incoming event doesn't have one 5759 this.timeStamp = src && src.timeStamp || Date.now(); 5760 5761 // Mark it as fixed 5762 this[ jQuery.expando ] = true; 5763}; 5764 5765// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 5766// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 5767jQuery.Event.prototype = { 5768 constructor: jQuery.Event, 5769 isDefaultPrevented: returnFalse, 5770 isPropagationStopped: returnFalse, 5771 isImmediatePropagationStopped: returnFalse, 5772 isSimulated: false, 5773 5774 preventDefault: function() { 5775 var e = this.originalEvent; 5776 5777 this.isDefaultPrevented = returnTrue; 5778 5779 if ( e && !this.isSimulated ) { 5780 e.preventDefault(); 5781 } 5782 }, 5783 stopPropagation: function() { 5784 var e = this.originalEvent; 5785 5786 this.isPropagationStopped = returnTrue; 5787 5788 if ( e && !this.isSimulated ) { 5789 e.stopPropagation(); 5790 } 5791 }, 5792 stopImmediatePropagation: function() { 5793 var e = this.originalEvent; 5794 5795 this.isImmediatePropagationStopped = returnTrue; 5796 5797 if ( e && !this.isSimulated ) { 5798 e.stopImmediatePropagation(); 5799 } 5800 5801 this.stopPropagation(); 5802 } 5803}; 5804 5805// Includes all common event props including KeyEvent and MouseEvent specific props 5806jQuery.each( { 5807 altKey: true, 5808 bubbles: true, 5809 cancelable: true, 5810 changedTouches: true, 5811 ctrlKey: true, 5812 detail: true, 5813 eventPhase: true, 5814 metaKey: true, 5815 pageX: true, 5816 pageY: true, 5817 shiftKey: true, 5818 view: true, 5819 "char": true, 5820 code: true, 5821 charCode: true, 5822 key: true, 5823 keyCode: true, 5824 button: true, 5825 buttons: true, 5826 clientX: true, 5827 clientY: true, 5828 offsetX: true, 5829 offsetY: true, 5830 pointerId: true, 5831 pointerType: true, 5832 screenX: true, 5833 screenY: true, 5834 targetTouches: true, 5835 toElement: true, 5836 touches: true, 5837 which: true 5838}, jQuery.event.addProp ); 5839 5840jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { 5841 jQuery.event.special[ type ] = { 5842 5843 // Utilize native event if possible so blur/focus sequence is correct 5844 setup: function() { 5845 5846 // Claim the first handler 5847 // dataPriv.set( this, "focus", ... ) 5848 // dataPriv.set( this, "blur", ... ) 5849 leverageNative( this, type, expectSync ); 5850 5851 // Return false to allow normal processing in the caller 5852 return false; 5853 }, 5854 trigger: function() { 5855 5856 // Force setup before trigger 5857 leverageNative( this, type ); 5858 5859 // Return non-false to allow normal event-path propagation 5860 return true; 5861 }, 5862 5863 // Suppress native focus or blur if we're currently inside 5864 // a leveraged native-event stack 5865 _default: function( event ) { 5866 return dataPriv.get( event.target, type ); 5867 }, 5868 5869 delegateType: delegateType 5870 }; 5871} ); 5872 5873// Create mouseenter/leave events using mouseover/out and event-time checks 5874// so that event delegation works in jQuery. 5875// Do the same for pointerenter/pointerleave and pointerover/pointerout 5876// 5877// Support: Safari 7 only 5878// Safari sends mouseenter too often; see: 5879// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 5880// for the description of the bug (it existed in older Chrome versions as well). 5881jQuery.each( { 5882 mouseenter: "mouseover", 5883 mouseleave: "mouseout", 5884 pointerenter: "pointerover", 5885 pointerleave: "pointerout" 5886}, function( orig, fix ) { 5887 jQuery.event.special[ orig ] = { 5888 delegateType: fix, 5889 bindType: fix, 5890 5891 handle: function( event ) { 5892 var ret, 5893 target = this, 5894 related = event.relatedTarget, 5895 handleObj = event.handleObj; 5896 5897 // For mouseenter/leave call the handler if related is outside the target. 5898 // NB: No relatedTarget if the mouse left/entered the browser window 5899 if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { 5900 event.type = handleObj.origType; 5901 ret = handleObj.handler.apply( this, arguments ); 5902 event.type = fix; 5903 } 5904 return ret; 5905 } 5906 }; 5907} ); 5908 5909jQuery.fn.extend( { 5910 5911 on: function( types, selector, data, fn ) { 5912 return on( this, types, selector, data, fn ); 5913 }, 5914 one: function( types, selector, data, fn ) { 5915 return on( this, types, selector, data, fn, 1 ); 5916 }, 5917 off: function( types, selector, fn ) { 5918 var handleObj, type; 5919 if ( types && types.preventDefault && types.handleObj ) { 5920 5921 // ( event ) dispatched jQuery.Event 5922 handleObj = types.handleObj; 5923 jQuery( types.delegateTarget ).off( 5924 handleObj.namespace ? 5925 handleObj.origType + "." + handleObj.namespace : 5926 handleObj.origType, 5927 handleObj.selector, 5928 handleObj.handler 5929 ); 5930 return this; 5931 } 5932 if ( typeof types === "object" ) { 5933 5934 // ( types-object [, selector] ) 5935 for ( type in types ) { 5936 this.off( type, selector, types[ type ] ); 5937 } 5938 return this; 5939 } 5940 if ( selector === false || typeof selector === "function" ) { 5941 5942 // ( types [, fn] ) 5943 fn = selector; 5944 selector = undefined; 5945 } 5946 if ( fn === false ) { 5947 fn = returnFalse; 5948 } 5949 return this.each( function() { 5950 jQuery.event.remove( this, types, fn, selector ); 5951 } ); 5952 } 5953} ); 5954 5955 5956var 5957 5958 // Support: IE <=10 - 11, Edge 12 - 13 only 5959 // In IE/Edge using regex groups here causes severe slowdowns. 5960 // See https://connect.microsoft.com/IE/feedback/details/1736512/ 5961 rnoInnerhtml = /<script|<style|<link/i, 5962 5963 // checked="checked" or checked 5964 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, 5965 5966 rcleanScript = /^\s*<!\[CDATA\[|\]\]>\s*$/g; 5967 5968// Prefer a tbody over its parent table for containing new rows 5969function manipulationTarget( elem, content ) { 5970 if ( nodeName( elem, "table" ) && 5971 nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { 5972 5973 return jQuery( elem ).children( "tbody" )[ 0 ] || elem; 5974 } 5975 5976 return elem; 5977} 5978 5979// Replace/restore the type attribute of script elements for safe DOM manipulation 5980function disableScript( elem ) { 5981 elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; 5982 return elem; 5983} 5984function restoreScript( elem ) { 5985 if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { 5986 elem.type = elem.type.slice( 5 ); 5987 } else { 5988 elem.removeAttribute( "type" ); 5989 } 5990 5991 return elem; 5992} 5993 5994function cloneCopyEvent( src, dest ) { 5995 var i, l, type, pdataOld, udataOld, udataCur, events; 5996 5997 if ( dest.nodeType !== 1 ) { 5998 return; 5999 } 6000 6001 // 1. Copy private data: events, handlers, etc. 6002 if ( dataPriv.hasData( src ) ) { 6003 pdataOld = dataPriv.get( src ); 6004 events = pdataOld.events; 6005 6006 if ( events ) { 6007 dataPriv.remove( dest, "handle events" ); 6008 6009 for ( type in events ) { 6010 for ( i = 0, l = events[ type ].length; i < l; i++ ) { 6011 jQuery.event.add( dest, type, events[ type ][ i ] ); 6012 } 6013 } 6014 } 6015 } 6016 6017 // 2. Copy user data 6018 if ( dataUser.hasData( src ) ) { 6019 udataOld = dataUser.access( src ); 6020 udataCur = jQuery.extend( {}, udataOld ); 6021 6022 dataUser.set( dest, udataCur ); 6023 } 6024} 6025 6026// Fix IE bugs, see support tests 6027function fixInput( src, dest ) { 6028 var nodeName = dest.nodeName.toLowerCase(); 6029 6030 // Fails to persist the checked state of a cloned checkbox or radio button. 6031 if ( nodeName === "input" && rcheckableType.test( src.type ) ) { 6032 dest.checked = src.checked; 6033 6034 // Fails to return the selected option to the default selected state when cloning options 6035 } else if ( nodeName === "input" || nodeName === "textarea" ) { 6036 dest.defaultValue = src.defaultValue; 6037 } 6038} 6039 6040function domManip( collection, args, callback, ignored ) { 6041 6042 // Flatten any nested arrays 6043 args = flat( args ); 6044 6045 var fragment, first, scripts, hasScripts, node, doc, 6046 i = 0, 6047 l = collection.length, 6048 iNoClone = l - 1, 6049 value = args[ 0 ], 6050 valueIsFunction = isFunction( value ); 6051 6052 // We can't cloneNode fragments that contain checked, in WebKit 6053 if ( valueIsFunction || 6054 ( l > 1 && typeof value === "string" && 6055 !support.checkClone && rchecked.test( value ) ) ) { 6056 return collection.each( function( index ) { 6057 var self = collection.eq( index ); 6058 if ( valueIsFunction ) { 6059 args[ 0 ] = value.call( this, index, self.html() ); 6060 } 6061 domManip( self, args, callback, ignored ); 6062 } ); 6063 } 6064 6065 if ( l ) { 6066 fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); 6067 first = fragment.firstChild; 6068 6069 if ( fragment.childNodes.length === 1 ) { 6070 fragment = first; 6071 } 6072 6073 // Require either new content or an interest in ignored elements to invoke the callback 6074 if ( first || ignored ) { 6075 scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); 6076 hasScripts = scripts.length; 6077 6078 // Use the original fragment for the last item 6079 // instead of the first because it can end up 6080 // being emptied incorrectly in certain situations (trac-8070). 6081 for ( ; i < l; i++ ) { 6082 node = fragment; 6083 6084 if ( i !== iNoClone ) { 6085 node = jQuery.clone( node, true, true ); 6086 6087 // Keep references to cloned scripts for later restoration 6088 if ( hasScripts ) { 6089 6090 // Support: Android <=4.0 only, PhantomJS 1 only 6091 // push.apply(_, arraylike) throws on ancient WebKit 6092 jQuery.merge( scripts, getAll( node, "script" ) ); 6093 } 6094 } 6095 6096 callback.call( collection[ i ], node, i ); 6097 } 6098 6099 if ( hasScripts ) { 6100 doc = scripts[ scripts.length - 1 ].ownerDocument; 6101 6102 // Reenable scripts 6103 jQuery.map( scripts, restoreScript ); 6104 6105 // Evaluate executable scripts on first document insertion 6106 for ( i = 0; i < hasScripts; i++ ) { 6107 node = scripts[ i ]; 6108 if ( rscriptType.test( node.type || "" ) && 6109 !dataPriv.access( node, "globalEval" ) && 6110 jQuery.contains( doc, node ) ) { 6111 6112 if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { 6113 6114 // Optional AJAX dependency, but won't run scripts if not present 6115 if ( jQuery._evalUrl && !node.noModule ) { 6116 jQuery._evalUrl( node.src, { 6117 nonce: node.nonce || node.getAttribute( "nonce" ) 6118 }, doc ); 6119 } 6120 } else { 6121 6122 // Unwrap a CDATA section containing script contents. This shouldn't be 6123 // needed as in XML documents they're already not visible when 6124 // inspecting element contents and in HTML documents they have no 6125 // meaning but we're preserving that logic for backwards compatibility. 6126 // This will be removed completely in 4.0. See gh-4904. 6127 DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); 6128 } 6129 } 6130 } 6131 } 6132 } 6133 } 6134 6135 return collection; 6136} 6137 6138function remove( elem, selector, keepData ) { 6139 var node, 6140 nodes = selector ? jQuery.filter( selector, elem ) : elem, 6141 i = 0; 6142 6143 for ( ; ( node = nodes[ i ] ) != null; i++ ) { 6144 if ( !keepData && node.nodeType === 1 ) { 6145 jQuery.cleanData( getAll( node ) ); 6146 } 6147 6148 if ( node.parentNode ) { 6149 if ( keepData && isAttached( node ) ) { 6150 setGlobalEval( getAll( node, "script" ) ); 6151 } 6152 node.parentNode.removeChild( node ); 6153 } 6154 } 6155 6156 return elem; 6157} 6158 6159jQuery.extend( { 6160 htmlPrefilter: function( html ) { 6161 return html; 6162 }, 6163 6164 clone: function( elem, dataAndEvents, deepDataAndEvents ) { 6165 var i, l, srcElements, destElements, 6166 clone = elem.cloneNode( true ), 6167 inPage = isAttached( elem ); 6168 6169 // Fix IE cloning issues 6170 if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && 6171 !jQuery.isXMLDoc( elem ) ) { 6172 6173 // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 6174 destElements = getAll( clone ); 6175 srcElements = getAll( elem ); 6176 6177 for ( i = 0, l = srcElements.length; i < l; i++ ) { 6178 fixInput( srcElements[ i ], destElements[ i ] ); 6179 } 6180 } 6181 6182 // Copy the events from the original to the clone 6183 if ( dataAndEvents ) { 6184 if ( deepDataAndEvents ) { 6185 srcElements = srcElements || getAll( elem ); 6186 destElements = destElements || getAll( clone ); 6187 6188 for ( i = 0, l = srcElements.length; i < l; i++ ) { 6189 cloneCopyEvent( srcElements[ i ], destElements[ i ] ); 6190 } 6191 } else { 6192 cloneCopyEvent( elem, clone ); 6193 } 6194 } 6195 6196 // Preserve script evaluation history 6197 destElements = getAll( clone, "script" ); 6198 if ( destElements.length > 0 ) { 6199 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); 6200 } 6201 6202 // Return the cloned set 6203 return clone; 6204 }, 6205 6206 cleanData: function( elems ) { 6207 var data, elem, type, 6208 special = jQuery.event.special, 6209 i = 0; 6210 6211 for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { 6212 if ( acceptData( elem ) ) { 6213 if ( ( data = elem[ dataPriv.expando ] ) ) { 6214 if ( data.events ) { 6215 for ( type in data.events ) { 6216 if ( special[ type ] ) { 6217 jQuery.event.remove( elem, type ); 6218 6219 // This is a shortcut to avoid jQuery.event.remove's overhead 6220 } else { 6221 jQuery.removeEvent( elem, type, data.handle ); 6222 } 6223 } 6224 } 6225
vendor: 1,119 bytes, lines 6226-6270
6226 // Support: Chrome <=35 - 45+ 6227 // Assign undefined instead of using delete, see Data#remove 6228 elem[ dataPriv.expando ] = undefined; 6229 } 6230 if ( elem[ dataUser.expando ] ) { 6231 6232 // Support: Chrome <=35 - 45+ 6233 // Assign undefined instead of using delete, see Data#remove 6234 elem[ dataUser.expando ] = undefined; 6235 } 6236 } 6237 } 6238 } 6239} ); 6240 6241jQuery.fn.extend( { 6242 detach: function( selector ) { 6243 return remove( this, selector, true ); 6244 }, 6245 6246 remove: function( selector ) { 6247 return remove( this, selector ); 6248 }, 6249 6250 text: function( value ) { 6251 return access( this, function( value ) { 6252 return value === undefined ? 6253 jQuery.text( this ) : 6254 this.empty().each( function() { 6255 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 6256 this.textContent = value; 6257 } 6258 } ); 6259 }, null, value, arguments.length ); 6260 }, 6261 6262 append: function() { 6263 return domManip( this, arguments, function( elem ) { 6264 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 6265 var target = manipulationTarget( this, elem ); 6266 target.appendChild( elem ); 6267 } 6268 } ); 6269 }, 6270
vendor: 4,664 bytes, lines 6271-6471
6271 prepend: function() { 6272 return domManip( this, arguments, function( elem ) { 6273 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 6274 var target = manipulationTarget( this, elem ); 6275 target.insertBefore( elem, target.firstChild ); 6276 } 6277 } ); 6278 }, 6279 6280 before: function() { 6281 return domManip( this, arguments, function( elem ) { 6282 if ( this.parentNode ) { 6283 this.parentNode.insertBefore( elem, this ); 6284 } 6285 } ); 6286 }, 6287 6288 after: function() { 6289 return domManip( this, arguments, function( elem ) { 6290 if ( this.parentNode ) { 6291 this.parentNode.insertBefore( elem, this.nextSibling ); 6292 } 6293 } ); 6294 }, 6295 6296 empty: function() { 6297 var elem, 6298 i = 0; 6299 6300 for ( ; ( elem = this[ i ] ) != null; i++ ) { 6301 if ( elem.nodeType === 1 ) { 6302 6303 // Prevent memory leaks 6304 jQuery.cleanData( getAll( elem, false ) ); 6305 6306 // Remove any remaining nodes 6307 elem.textContent = ""; 6308 } 6309 } 6310 6311 return this; 6312 }, 6313 6314 clone: function( dataAndEvents, deepDataAndEvents ) { 6315 dataAndEvents = dataAndEvents == null ? false : dataAndEvents; 6316 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; 6317 6318 return this.map( function() { 6319 return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); 6320 } ); 6321 }, 6322 6323 html: function( value ) { 6324 return access( this, function( value ) { 6325 var elem = this[ 0 ] || {}, 6326 i = 0, 6327 l = this.length; 6328 6329 if ( value === undefined && elem.nodeType === 1 ) { 6330 return elem.innerHTML; 6331 } 6332 6333 // See if we can take a shortcut and just use innerHTML 6334 if ( typeof value === "string" && !rnoInnerhtml.test( value ) && 6335 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { 6336 6337 value = jQuery.htmlPrefilter( value ); 6338 6339 try { 6340 for ( ; i < l; i++ ) { 6341 elem = this[ i ] || {}; 6342 6343 // Remove element nodes and prevent memory leaks 6344 if ( elem.nodeType === 1 ) { 6345 jQuery.cleanData( getAll( elem, false ) ); 6346 elem.innerHTML = value; 6347 } 6348 } 6349 6350 elem = 0; 6351 6352 // If using innerHTML throws an exception, use the fallback method 6353 } catch ( e ) {} 6354 } 6355 6356 if ( elem ) { 6357 this.empty().append( value ); 6358 } 6359 }, null, value, arguments.length ); 6360 }, 6361 6362 replaceWith: function() { 6363 var ignored = []; 6364 6365 // Make the changes, replacing each non-ignored context element with the new content 6366 return domManip( this, arguments, function( elem ) { 6367 var parent = this.parentNode; 6368 6369 if ( jQuery.inArray( this, ignored ) < 0 ) { 6370 jQuery.cleanData( getAll( this ) ); 6371 if ( parent ) { 6372 parent.replaceChild( elem, this ); 6373 } 6374 } 6375 6376 // Force callback invocation 6377 }, ignored ); 6378 } 6379} ); 6380 6381jQuery.each( { 6382 appendTo: "append", 6383 prependTo: "prepend", 6384 insertBefore: "before", 6385 insertAfter: "after", 6386 replaceAll: "replaceWith" 6387}, function( name, original ) { 6388 jQuery.fn[ name ] = function( selector ) { 6389 var elems, 6390 ret = [], 6391 insert = jQuery( selector ), 6392 last = insert.length - 1, 6393 i = 0; 6394 6395 for ( ; i <= last; i++ ) { 6396 elems = i === last ? this : this.clone( true ); 6397 jQuery( insert[ i ] )[ original ]( elems ); 6398 6399 // Support: Android <=4.0 only, PhantomJS 1 only 6400 // .get() because push.apply(_, arraylike) throws on ancient WebKit 6401 push.apply( ret, elems.get() ); 6402 } 6403 6404 return this.pushStack( ret ); 6405 }; 6406} ); 6407var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 6408 6409var rcustomProp = /^--/; 6410 6411 6412var getStyles = function( elem ) { 6413 6414 // Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150) 6415 // IE throws on elements created in popups 6416 // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" 6417 var view = elem.ownerDocument.defaultView; 6418 6419 if ( !view || !view.opener ) { 6420 view = window; 6421 } 6422 6423 return view.getComputedStyle( elem ); 6424 }; 6425 6426var swap = function( elem, options, callback ) { 6427 var ret, name, 6428 old = {}; 6429 6430 // Remember the old values, and insert the new ones 6431 for ( name in options ) { 6432 old[ name ] = elem.style[ name ]; 6433 elem.style[ name ] = options[ name ]; 6434 } 6435 6436 ret = callback.call( elem ); 6437 6438 // Revert the old values 6439 for ( name in options ) { 6440 elem.style[ name ] = old[ name ]; 6441 } 6442 6443 return ret; 6444}; 6445 6446 6447var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); 6448 6449var whitespace = "[\\x20\\t\\r\\n\\f]"; 6450 6451 6452var rtrimCSS = new RegExp( 6453 "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", 6454 "g" 6455); 6456 6457 6458 6459 6460( function() { 6461 6462 // Executing both pixelPosition & boxSizingReliable tests require only one layout 6463 // so they're executed at the same time to save the second computation. 6464 function computeStyleTests() { 6465 6466 // This is a singleton, we need to execute it only once 6467 if ( !div ) { 6468 return; 6469 } 6470 6471 container.style.cssText = "position:absolute;
vendor: 4,131 bytes, lines 6471-6590
6471left:-11111px;width:60px;" + 6472 "margin-top:1px;padding:0;border:0"; 6473 div.style.cssText = 6474 "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + 6475 "margin:auto;border:1px;padding:1px;" + 6476 "width:60%;top:1%"; 6477 documentElement.appendChild( container ).appendChild( div ); 6478 6479 var divStyle = window.getComputedStyle( div ); 6480 pixelPositionVal = divStyle.top !== "1%"; 6481 6482 // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 6483 reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; 6484 6485 // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 6486 // Some styles come back with percentage values, even though they shouldn't 6487 div.style.right = "60%"; 6488 pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; 6489 6490 // Support: IE 9 - 11 only 6491 // Detect misreporting of content dimensions for box-sizing:border-box elements 6492 boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; 6493 6494 // Support: IE 9 only 6495 // Detect overflow:scroll screwiness (gh-3699) 6496 // Support: Chrome <=64 6497 // Don't get tricked when zoom affects offsetWidth (gh-4029) 6498 div.style.position = "absolute"; 6499 scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; 6500 6501 documentElement.removeChild( container ); 6502 6503 // Nullify the div so it wouldn't be stored in the memory and 6504 // it will also be a sign that checks already performed 6505 div = null; 6506 } 6507 6508 function roundPixelMeasures( measure ) { 6509 return Math.round( parseFloat( measure ) ); 6510 } 6511 6512 var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, 6513 reliableTrDimensionsVal, reliableMarginLeftVal, 6514 container = document.createElement( "div" ), 6515 div = document.createElement( "div" ); 6516 6517 // Finish early in limited (non-browser) environments 6518 if ( !div.style ) { 6519 return; 6520 } 6521 6522 // Support: IE <=9 - 11 only 6523 // Style of cloned element affects source element cloned (trac-8908) 6524 div.style.backgroundClip = "content-box"; 6525 div.cloneNode( true ).style.backgroundClip = ""; 6526 support.clearCloneStyle = div.style.backgroundClip === "content-box"; 6527 6528 jQuery.extend( support, { 6529 boxSizingReliable: function() { 6530 computeStyleTests(); 6531 return boxSizingReliableVal; 6532 }, 6533 pixelBoxStyles: function() { 6534 computeStyleTests(); 6535 return pixelBoxStylesVal; 6536 }, 6537 pixelPosition: function() { 6538 computeStyleTests(); 6539 return pixelPositionVal; 6540 }, 6541 reliableMarginLeft: function() { 6542 computeStyleTests(); 6543 return reliableMarginLeftVal; 6544 }, 6545 scrollboxSize: function() { 6546 computeStyleTests(); 6547 return scrollboxSizeVal; 6548 }, 6549 6550 // Support: IE 9 - 11+, Edge 15 - 18+ 6551 // IE/Edge misreport `getComputedStyle` of table rows with width/height 6552 // set in CSS while `offset*` properties report correct values. 6553 // Behavior in IE 9 is more subtle than in newer versions & it passes 6554 // some versions of this test; make sure not to make it pass there! 6555 // 6556 // Support: Firefox 70+ 6557 // Only Firefox includes border widths 6558 // in computed dimensions. (gh-4529) 6559 reliableTrDimensions: function() { 6560 var table, tr, trChild, trStyle; 6561 if ( reliableTrDimensionsVal == null ) { 6562 table = document.createElement( "table" ); 6563 tr = document.createElement( "tr" ); 6564 trChild = document.createElement( "div" ); 6565 6566 table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; 6567 tr.style.cssText = "border:1px solid"; 6568 6569 // Support: Chrome 86+ 6570 // Height set through cssText does not get applied. 6571 // Computed height then comes back as 0. 6572 tr.style.height = "1px"; 6573 trChild.style.height = "9px"; 6574 6575 // Support: Android 8 Chrome 86+ 6576 // In our bodyBackground.html iframe, 6577 // display for all div elements is set to "inline", 6578 // which causes a problem only in Android 8 Chrome 86. 6579 // Ensuring the div is display: block 6580 // gets around this issue. 6581 trChild.style.display = "block"; 6582 6583 documentElement 6584 .appendChild( table ) 6585 .appendChild( tr ) 6586 .appendChild( trChild ); 6587 6588 trStyle = window.getComputedStyle( tr ); 6589 reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + 6590 parseInt( trStyle.borderTopWidth, 10 ) +
vendor: 11,424 bytes, lines 6591-6985
6591 parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; 6592 6593 documentElement.removeChild( table ); 6594 } 6595 return reliableTrDimensionsVal; 6596 } 6597 } ); 6598} )(); 6599 6600 6601function curCSS( elem, name, computed ) { 6602 var width, minWidth, maxWidth, ret, 6603 isCustomProp = rcustomProp.test( name ), 6604 6605 // Support: Firefox 51+ 6606 // Retrieving style before computed somehow 6607 // fixes an issue with getting wrong values 6608 // on detached elements 6609 style = elem.style; 6610 6611 computed = computed || getStyles( elem ); 6612 6613 // getPropertyValue is needed for: 6614 // .css('filter') (IE 9 only, trac-12537) 6615 // .css('--customProperty) (gh-3144) 6616 if ( computed ) { 6617 ret = computed.getPropertyValue( name ) || computed[ name ]; 6618 6619 // trim whitespace for custom property (issue gh-4926) 6620 if ( isCustomProp ) { 6621 6622 // rtrim treats U+000D CARRIAGE RETURN and U+000C FORM FEED 6623 // as whitespace while CSS does not, but this is not a problem 6624 // because CSS preprocessing replaces them with U+000A LINE FEED 6625 // (which *is* CSS whitespace) 6626 // https://www.w3.org/TR/css-syntax-3/#input-preprocessing 6627 ret = ret.replace( rtrimCSS, "$1" ); 6628 } 6629 6630 if ( ret === "" && !isAttached( elem ) ) { 6631 ret = jQuery.style( elem, name ); 6632 } 6633 6634 // A tribute to the "awesome hack by Dean Edwards" 6635 // Android Browser returns percentage for some values, 6636 // but width seems to be reliably pixels. 6637 // This is against the CSSOM draft spec: 6638 // https://drafts.csswg.org/cssom/#resolved-values 6639 if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { 6640 6641 // Remember the original values 6642 width = style.width; 6643 minWidth = style.minWidth; 6644 maxWidth = style.maxWidth; 6645 6646 // Put in the new values to get a computed value out 6647 style.minWidth = style.maxWidth = style.width = ret; 6648 ret = computed.width; 6649 6650 // Revert the changed values 6651 style.width = width; 6652 style.minWidth = minWidth; 6653 style.maxWidth = maxWidth; 6654 } 6655 } 6656 6657 return ret !== undefined ? 6658 6659 // Support: IE <=9 - 11 only 6660 // IE returns zIndex value as an integer. 6661 ret + "" : 6662 ret; 6663} 6664 6665 6666function addGetHookIf( conditionFn, hookFn ) { 6667 6668 // Define the hook, we'll check on the first run if it's really needed. 6669 return { 6670 get: function() { 6671 if ( conditionFn() ) { 6672 6673 // Hook not needed (or it's not possible to use it due 6674 // to missing dependency), remove it. 6675 delete this.get; 6676 return; 6677 } 6678 6679 // Hook needed; redefine it so that the support test is not executed again. 6680 return ( this.get = hookFn ).apply( this, arguments ); 6681 } 6682 }; 6683} 6684 6685 6686var cssPrefixes = [ "Webkit", "Moz", "ms" ], 6687 emptyStyle = document.createElement( "div" ).style, 6688 vendorProps = {}; 6689 6690// Return a vendor-prefixed property or undefined 6691function vendorPropName( name ) { 6692 6693 // Check for vendor prefixed names 6694 var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), 6695 i = cssPrefixes.length; 6696 6697 while ( i-- ) { 6698 name = cssPrefixes[ i ] + capName; 6699 if ( name in emptyStyle ) { 6700 return name; 6701 } 6702 } 6703} 6704 6705// Return a potentially-mapped jQuery.cssProps or vendor prefixed property 6706function finalPropName( name ) { 6707 var final = jQuery.cssProps[ name ] || vendorProps[ name ]; 6708 6709 if ( final ) { 6710 return final; 6711 } 6712 if ( name in emptyStyle ) { 6713 return name; 6714 } 6715 return vendorProps[ name ] = vendorPropName( name ) || name; 6716} 6717 6718 6719var 6720 6721 // Swappable if display is none or starts with table 6722 // except "table", "table-cell", or "table-caption" 6723 // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display 6724 rdisplayswap = /^(none|table(?!-c[ea]).+)/, 6725 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 6726 cssNormalTransform = { 6727 letterSpacing: "0", 6728 fontWeight: "400" 6729 }; 6730 6731function setPositiveNumber( _elem, value, subtract ) { 6732 6733 // Any relative (+/-) values have already been 6734 // normalized at this point 6735 var matches = rcssNum.exec( value ); 6736 return matches ? 6737 6738 // Guard against undefined "subtract", e.g., when used as in cssHooks 6739 Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : 6740 value; 6741} 6742 6743function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { 6744 var i = dimension === "width" ? 1 : 0, 6745 extra = 0, 6746 delta = 0; 6747 6748 // Adjustment may not be necessary 6749 if ( box === ( isBorderBox ? "border" : "content" ) ) { 6750 return 0; 6751 } 6752 6753 for ( ; i < 4; i += 2 ) { 6754 6755 // Both box models exclude margin 6756 if ( box === "margin" ) { 6757 delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); 6758 } 6759 6760 // If we get here with a content-box, we're seeking "padding" or "border" or "margin" 6761 if ( !isBorderBox ) { 6762 6763 // Add padding 6764 delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6765 6766 // For "border" or "margin", add border 6767 if ( box !== "padding" ) { 6768 delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6769 6770 // But still keep track of it otherwise 6771 } else { 6772 extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6773 } 6774 6775 // If we get here with a border-box (content + padding + border), we're seeking "content" or 6776 // "padding" or "margin" 6777 } else { 6778 6779 // For "content", subtract padding 6780 if ( box === "content" ) { 6781 delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6782 } 6783 6784 // For "content" or "padding", subtract border 6785 if ( box !== "margin" ) { 6786 delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6787 } 6788 } 6789 } 6790 6791 // Account for positive content-box scroll gutter when requested by providing computedVal 6792 if ( !isBorderBox && computedVal >= 0 ) { 6793 6794 // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border 6795 // Assuming integer scroll gutter, subtract the rest and round down 6796 delta += Math.max( 0, Math.ceil( 6797 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 6798 computedVal - 6799 delta - 6800 extra - 6801 0.5 6802 6803 // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter 6804 // Use an explicit zero to avoid NaN (gh-3964) 6805 ) ) || 0; 6806 } 6807 6808 return delta; 6809} 6810 6811function getWidthOrHeight( elem, dimension, extra ) { 6812 6813 // Start with computed style 6814 var styles = getStyles( elem ), 6815 6816 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). 6817 // Fake content-box until we know it's needed to know the true value. 6818 boxSizingNeeded = !support.boxSizingReliable() || extra, 6819 isBorderBox = boxSizingNeeded && 6820 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 6821 valueIsBorderBox = isBorderBox, 6822 6823 val = curCSS( elem, dimension, styles ), 6824 offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); 6825 6826 // Support: Firefox <=54 6827 // Return a confounding non-pixel value or feign ignorance, as appropriate. 6828 if ( rnumnonpx.test( val ) ) { 6829 if ( !extra ) { 6830 return val; 6831 } 6832 val = "auto"; 6833 } 6834 6835 6836 // Support: IE 9 - 11 only 6837 // Use offsetWidth/offsetHeight for when box sizing is unreliable. 6838 // In those cases, the computed value can be trusted to be border-box. 6839 if ( ( !support.boxSizingReliable() && isBorderBox || 6840 6841 // Support: IE 10 - 11+, Edge 15 - 18+ 6842 // IE/Edge misreport `getComputedStyle` of table rows with width/height 6843 // set in CSS while `offset*` properties report correct values. 6844 // Interestingly, in some cases IE 9 doesn't suffer from this issue. 6845 !support.reliableTrDimensions() && nodeName( elem, "tr" ) || 6846 6847 // Fall back to offsetWidth/offsetHeight when value is "auto" 6848 // This happens for inline elements with no explicit setting (gh-3571) 6849 val === "auto" || 6850 6851 // Support: Android <=4.1 - 4.3 only 6852 // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) 6853 !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && 6854 6855 // Make sure the element is visible & connected 6856 elem.getClientRects().length ) { 6857 6858 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; 6859 6860 // Where available, offsetWidth/offsetHeight approximate border box dimensions. 6861 // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the 6862 // retrieved value as a content box dimension. 6863 valueIsBorderBox = offsetProp in elem; 6864 if ( valueIsBorderBox ) { 6865 val = elem[ offsetProp ]; 6866 } 6867 } 6868 6869 // Normalize "" and auto 6870 val = parseFloat( val ) || 0; 6871 6872 // Adjust for the element's box model 6873 return ( val + 6874 boxModelAdjustment( 6875 elem, 6876 dimension, 6877 extra || ( isBorderBox ? "border" : "content" ), 6878 valueIsBorderBox, 6879 styles, 6880 6881 // Provide the current computed size to request scroll gutter calculation (gh-3589) 6882 val 6883 ) 6884 ) + "px"; 6885} 6886 6887jQuery.extend( { 6888 6889 // Add in style property hooks for overriding the default 6890 // behavior of getting and setting a style property 6891 cssHooks: { 6892 opacity: { 6893 get: function( elem, computed ) { 6894 if ( computed ) { 6895 6896 // We should always get a number back from opacity 6897 var ret = curCSS( elem, "opacity" ); 6898 return ret === "" ? "1" : ret; 6899 } 6900 } 6901 } 6902 }, 6903 6904 // Don't automatically add "px" to these possibly-unitless properties 6905 cssNumber: { 6906 "animationIterationCount": true, 6907 "columnCount": true, 6908 "fillOpacity": true, 6909 "flexGrow": true, 6910 "flexShrink": true, 6911 "fontWeight": true, 6912 "gridArea": true, 6913 "gridColumn": true, 6914 "gridColumnEnd": true, 6915 "gridColumnStart": true, 6916 "gridRow": true, 6917 "gridRowEnd": true, 6918 "gridRowStart": true, 6919 "lineHeight": true, 6920 "opacity": true, 6921 "order": true, 6922 "orphans": true, 6923 "widows": true, 6924 "zIndex": true, 6925 "zoom": true 6926 }, 6927 6928 // Add in properties whose names you wish to fix before 6929 // setting or getting the value 6930 cssProps: {}, 6931 6932 // Get and set the style property on a DOM Node 6933 style: function( elem, name, value, extra ) { 6934 6935 // Don't set styles on text and comment nodes 6936 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 6937 return; 6938 } 6939 6940 // Make sure that we're working with the right name 6941 var ret, type, hooks, 6942 origName = camelCase( name ), 6943 isCustomProp = rcustomProp.test( name ), 6944 style = elem.style; 6945 6946 // Make sure that we're working with the right name. We don't 6947 // want to query the value if it is a CSS custom property 6948 // since they are user-defined. 6949 if ( !isCustomProp ) { 6950 name = finalPropName( origName ); 6951 } 6952 6953 // Gets hook for the prefixed version, then unprefixed version 6954 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 6955 6956 // Check if we're setting a value 6957 if ( value !== undefined ) { 6958 type = typeof value; 6959 6960 // Convert "+=" or "-=" to relative numbers (trac-7345) 6961 if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { 6962 value = adjustCSS( elem, name, ret ); 6963 6964 // Fixes bug trac-9237 6965 type = "number"; 6966 } 6967 6968 // Make sure that null and NaN values aren't set (trac-7116) 6969 if ( value == null || value !== value ) { 6970 return; 6971 } 6972 6973 // If a number was passed in, add the unit (except for certain CSS properties) 6974 // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append 6975 // "px" to a few hardcoded values. 6976 if ( type === "number" && !isCustomProp ) { 6977 value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); 6978 } 6979 6980 // background-* props affect original clone's values 6981 if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { 6982 style[ name ] = "inherit"; 6983 } 6984 6985 // If a hook was provided, use that value, otherwise just set the specified value
vendor: 16,052 bytes, lines 6986-7590
6986 if ( !hooks || !( "set" in hooks ) || 6987 ( value = hooks.set( elem, value, extra ) ) !== undefined ) { 6988 6989 if ( isCustomProp ) { 6990 style.setProperty( name, value ); 6991 } else { 6992 style[ name ] = value; 6993 } 6994 } 6995 6996 } else { 6997 6998 // If a hook was provided get the non-computed value from there 6999 if ( hooks && "get" in hooks && 7000 ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { 7001 7002 return ret; 7003 } 7004 7005 // Otherwise just get the value from the style object 7006 return style[ name ]; 7007 } 7008 }, 7009 7010 css: function( elem, name, extra, styles ) { 7011 var val, num, hooks, 7012 origName = camelCase( name ), 7013 isCustomProp = rcustomProp.test( name ); 7014 7015 // Make sure that we're working with the right name. We don't 7016 // want to modify the value if it is a CSS custom property 7017 // since they are user-defined. 7018 if ( !isCustomProp ) { 7019 name = finalPropName( origName ); 7020 } 7021 7022 // Try prefixed name followed by the unprefixed name 7023 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 7024 7025 // If a hook was provided get the computed value from there 7026 if ( hooks && "get" in hooks ) { 7027 val = hooks.get( elem, true, extra ); 7028 } 7029 7030 // Otherwise, if a way to get the computed value exists, use that 7031 if ( val === undefined ) { 7032 val = curCSS( elem, name, styles ); 7033 } 7034 7035 // Convert "normal" to computed value 7036 if ( val === "normal" && name in cssNormalTransform ) { 7037 val = cssNormalTransform[ name ]; 7038 } 7039 7040 // Make numeric if forced or a qualifier was provided and val looks numeric 7041 if ( extra === "" || extra ) { 7042 num = parseFloat( val ); 7043 return extra === true || isFinite( num ) ? num || 0 : val; 7044 } 7045 7046 return val; 7047 } 7048} ); 7049 7050jQuery.each( [ "height", "width" ], function( _i, dimension ) { 7051 jQuery.cssHooks[ dimension ] = { 7052 get: function( elem, computed, extra ) { 7053 if ( computed ) { 7054 7055 // Certain elements can have dimension info if we invisibly show them 7056 // but it must have a current display style that would benefit 7057 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && 7058 7059 // Support: Safari 8+ 7060 // Table columns in Safari have non-zero offsetWidth & zero 7061 // getBoundingClientRect().width unless display is changed. 7062 // Support: IE <=11 only 7063 // Running getBoundingClientRect on a disconnected node 7064 // in IE throws an error. 7065 ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? 7066 swap( elem, cssShow, function() { 7067 return getWidthOrHeight( elem, dimension, extra ); 7068 } ) : 7069 getWidthOrHeight( elem, dimension, extra ); 7070 } 7071 }, 7072 7073 set: function( elem, value, extra ) { 7074 var matches, 7075 styles = getStyles( elem ), 7076 7077 // Only read styles.position if the test has a chance to fail 7078 // to avoid forcing a reflow. 7079 scrollboxSizeBuggy = !support.scrollboxSize() && 7080 styles.position === "absolute", 7081 7082 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) 7083 boxSizingNeeded = scrollboxSizeBuggy || extra, 7084 isBorderBox = boxSizingNeeded && 7085 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 7086 subtract = extra ? 7087 boxModelAdjustment( 7088 elem, 7089 dimension, 7090 extra, 7091 isBorderBox, 7092 styles 7093 ) : 7094 0; 7095 7096 // Account for unreliable border-box dimensions by comparing offset* to computed and 7097 // faking a content-box to get border and padding (gh-3699) 7098 if ( isBorderBox && scrollboxSizeBuggy ) { 7099 subtract -= Math.ceil( 7100 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 7101 parseFloat( styles[ dimension ] ) - 7102 boxModelAdjustment( elem, dimension, "border", false, styles ) - 7103 0.5 7104 ); 7105 } 7106 7107 // Convert to pixels if value adjustment is needed 7108 if ( subtract && ( matches = rcssNum.exec( value ) ) && 7109 ( matches[ 3 ] || "px" ) !== "px" ) { 7110 7111 elem.style[ dimension ] = value; 7112 value = jQuery.css( elem, dimension ); 7113 } 7114 7115 return setPositiveNumber( elem, value, subtract ); 7116 } 7117 }; 7118} ); 7119 7120jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, 7121 function( elem, computed ) { 7122 if ( computed ) { 7123 return ( parseFloat( curCSS( elem, "marginLeft" ) ) || 7124 elem.getBoundingClientRect().left - 7125 swap( elem, { marginLeft: 0 }, function() { 7126 return elem.getBoundingClientRect().left; 7127 } ) 7128 ) + "px"; 7129 } 7130 } 7131); 7132 7133// These hooks are used by animate to expand properties 7134jQuery.each( { 7135 margin: "", 7136 padding: "", 7137 border: "Width" 7138}, function( prefix, suffix ) { 7139 jQuery.cssHooks[ prefix + suffix ] = { 7140 expand: function( value ) { 7141 var i = 0, 7142 expanded = {}, 7143 7144 // Assumes a single number if not a string 7145 parts = typeof value === "string" ? value.split( " " ) : [ value ]; 7146 7147 for ( ; i < 4; i++ ) { 7148 expanded[ prefix + cssExpand[ i ] + suffix ] = 7149 parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; 7150 } 7151 7152 return expanded; 7153 } 7154 }; 7155 7156 if ( prefix !== "margin" ) { 7157 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; 7158 } 7159} ); 7160 7161jQuery.fn.extend( { 7162 css: function( name, value ) { 7163 return access( this, function( elem, name, value ) { 7164 var styles, len, 7165 map = {}, 7166 i = 0; 7167 7168 if ( Array.isArray( name ) ) { 7169 styles = getStyles( elem ); 7170 len = name.length; 7171 7172 for ( ; i < len; i++ ) { 7173 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); 7174 } 7175 7176 return map; 7177 } 7178 7179 return value !== undefined ? 7180 jQuery.style( elem, name, value ) : 7181 jQuery.css( elem, name ); 7182 }, name, value, arguments.length > 1 ); 7183 } 7184} ); 7185 7186 7187function Tween( elem, options, prop, end, easing ) { 7188 return new Tween.prototype.init( elem, options, prop, end, easing ); 7189} 7190jQuery.Tween = Tween; 7191 7192Tween.prototype = { 7193 constructor: Tween, 7194 init: function( elem, options, prop, end, easing, unit ) { 7195 this.elem = elem; 7196 this.prop = prop; 7197 this.easing = easing || jQuery.easing._default; 7198 this.options = options; 7199 this.start = this.now = this.cur(); 7200 this.end = end; 7201 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); 7202 }, 7203 cur: function() { 7204 var hooks = Tween.propHooks[ this.prop ]; 7205 7206 return hooks && hooks.get ? 7207 hooks.get( this ) : 7208 Tween.propHooks._default.get( this ); 7209 }, 7210 run: function( percent ) { 7211 var eased, 7212 hooks = Tween.propHooks[ this.prop ]; 7213 7214 if ( this.options.duration ) { 7215 this.pos = eased = jQuery.easing[ this.easing ]( 7216 percent, this.options.duration * percent, 0, 1, this.options.duration 7217 ); 7218 } else { 7219 this.pos = eased = percent; 7220 } 7221 this.now = ( this.end - this.start ) * eased + this.start; 7222 7223 if ( this.options.step ) { 7224 this.options.step.call( this.elem, this.now, this ); 7225 } 7226 7227 if ( hooks && hooks.set ) { 7228 hooks.set( this ); 7229 } else { 7230 Tween.propHooks._default.set( this ); 7231 } 7232 return this; 7233 } 7234}; 7235 7236Tween.prototype.init.prototype = Tween.prototype; 7237 7238Tween.propHooks = { 7239 _default: { 7240 get: function( tween ) { 7241 var result; 7242 7243 // Use a property on the element directly when it is not a DOM element, 7244 // or when there is no matching style property that exists. 7245 if ( tween.elem.nodeType !== 1 || 7246 tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { 7247 return tween.elem[ tween.prop ]; 7248 } 7249 7250 // Passing an empty string as a 3rd parameter to .css will automatically 7251 // attempt a parseFloat and fallback to a string if the parse fails. 7252 // Simple values such as "10px" are parsed to Float; 7253 // complex values such as "rotate(1rad)" are returned as-is. 7254 result = jQuery.css( tween.elem, tween.prop, "" ); 7255 7256 // Empty strings, null, undefined and "auto" are converted to 0. 7257 return !result || result === "auto" ? 0 : result; 7258 }, 7259 set: function( tween ) { 7260 7261 // Use step hook for back compat. 7262 // Use cssHook if its there. 7263 // Use .style if available and use plain properties where available. 7264 if ( jQuery.fx.step[ tween.prop ] ) { 7265 jQuery.fx.step[ tween.prop ]( tween ); 7266 } else if ( tween.elem.nodeType === 1 && ( 7267 jQuery.cssHooks[ tween.prop ] || 7268 tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { 7269 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); 7270 } else { 7271 tween.elem[ tween.prop ] = tween.now; 7272 } 7273 } 7274 } 7275}; 7276 7277// Support: IE <=9 only 7278// Panic based approach to setting things on disconnected nodes 7279Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { 7280 set: function( tween ) { 7281 if ( tween.elem.nodeType && tween.elem.parentNode ) { 7282 tween.elem[ tween.prop ] = tween.now; 7283 } 7284 } 7285}; 7286 7287jQuery.easing = { 7288 linear: function( p ) { 7289 return p; 7290 }, 7291 swing: function( p ) { 7292 return 0.5 - Math.cos( p * Math.PI ) / 2; 7293 }, 7294 _default: "swing" 7295}; 7296 7297jQuery.fx = Tween.prototype.init; 7298 7299// Back compat <1.8 extension point 7300jQuery.fx.step = {}; 7301 7302 7303 7304 7305var 7306 fxNow, inProgress, 7307 rfxtypes = /^(?:toggle|show|hide)$/, 7308 rrun = /queueHooks$/; 7309 7310function schedule() { 7311 if ( inProgress ) { 7312 if ( document.hidden === false && window.requestAnimationFrame ) { 7313 window.requestAnimationFrame( schedule ); 7314 } else { 7315 window.setTimeout( schedule, jQuery.fx.interval ); 7316 } 7317 7318 jQuery.fx.tick(); 7319 } 7320} 7321 7322// Animations created synchronously will run synchronously 7323function createFxNow() { 7324 window.setTimeout( function() { 7325 fxNow = undefined; 7326 } ); 7327 return ( fxNow = Date.now() ); 7328} 7329 7330// Generate parameters to create a standard animation 7331function genFx( type, includeWidth ) { 7332 var which, 7333 i = 0, 7334 attrs = { height: type }; 7335 7336 // If we include width, step value is 1 to do all cssExpand values, 7337 // otherwise step value is 2 to skip over Left and Right 7338 includeWidth = includeWidth ? 1 : 0; 7339 for ( ; i < 4; i += 2 - includeWidth ) { 7340 which = cssExpand[ i ]; 7341 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; 7342 } 7343 7344 if ( includeWidth ) { 7345 attrs.opacity = attrs.width = type; 7346 } 7347 7348 return attrs; 7349} 7350 7351function createTween( value, prop, animation ) { 7352 var tween, 7353 collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), 7354 index = 0, 7355 length = collection.length; 7356 for ( ; index < length; index++ ) { 7357 if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { 7358 7359 // We're done with this property 7360 return tween; 7361 } 7362 } 7363} 7364 7365function defaultPrefilter( elem, props, opts ) { 7366 var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, 7367 isBox = "width" in props || "height" in props, 7368 anim = this, 7369 orig = {}, 7370 style = elem.style, 7371 hidden = elem.nodeType && isHiddenWithinTree( elem ), 7372 dataShow = dataPriv.get( elem, "fxshow" ); 7373 7374 // Queue-skipping animations hijack the fx hooks 7375 if ( !opts.queue ) { 7376 hooks = jQuery._queueHooks( elem, "fx" ); 7377 if ( hooks.unqueued == null ) { 7378 hooks.unqueued = 0; 7379 oldfire = hooks.empty.fire; 7380 hooks.empty.fire = function() { 7381 if ( !hooks.unqueued ) { 7382 oldfire(); 7383 } 7384 }; 7385 } 7386 hooks.unqueued++; 7387 7388 anim.always( function() { 7389 7390 // Ensure the complete handler is called before this completes 7391 anim.always( function() { 7392 hooks.unqueued--; 7393 if ( !jQuery.queue( elem, "fx" ).length ) { 7394 hooks.empty.fire(); 7395 } 7396 } ); 7397 } ); 7398 } 7399 7400 // Detect show/hide animations 7401 for ( prop in props ) { 7402 value = props[ prop ]; 7403 if ( rfxtypes.test( value ) ) { 7404 delete props[ prop ]; 7405 toggle = toggle || value === "toggle"; 7406 if ( value === ( hidden ? "hide" : "show" ) ) { 7407 7408 // Pretend to be hidden if this is a "show" and 7409 // there is still data from a stopped show/hide 7410 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { 7411 hidden = true; 7412 7413 // Ignore all other no-op show/hide data 7414 } else { 7415 continue; 7416 } 7417 } 7418 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); 7419 } 7420 } 7421 7422 // Bail out if this is a no-op like .hide().hide() 7423 propTween = !jQuery.isEmptyObject( props ); 7424 if ( !propTween && jQuery.isEmptyObject( orig ) ) { 7425 return; 7426 } 7427 7428 // Restrict "overflow" and "display" styles during box animations 7429 if ( isBox && elem.nodeType === 1 ) { 7430 7431 // Support: IE <=9 - 11, Edge 12 - 15 7432 // Record all 3 overflow attributes because IE does not infer the shorthand 7433 // from identically-valued overflowX and overflowY and Edge just mirrors 7434 // the overflowX value there. 7435 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; 7436 7437 // Identify a display type, preferring old show/hide data over the CSS cascade 7438 restoreDisplay = dataShow && dataShow.display; 7439 if ( restoreDisplay == null ) { 7440 restoreDisplay = dataPriv.get( elem, "display" ); 7441 } 7442 display = jQuery.css( elem, "display" ); 7443 if ( display === "none" ) { 7444 if ( restoreDisplay ) { 7445 display = restoreDisplay; 7446 } else { 7447 7448 // Get nonempty value(s) by temporarily forcing visibility 7449 showHide( [ elem ], true ); 7450 restoreDisplay = elem.style.display || restoreDisplay; 7451 display = jQuery.css( elem, "display" ); 7452 showHide( [ elem ] ); 7453 } 7454 } 7455 7456 // Animate inline elements as inline-block 7457 if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { 7458 if ( jQuery.css( elem, "float" ) === "none" ) { 7459 7460 // Restore the original display value at the end of pure show/hide animations 7461 if ( !propTween ) { 7462 anim.done( function() { 7463 style.display = restoreDisplay; 7464 } ); 7465 if ( restoreDisplay == null ) { 7466 display = style.display; 7467 restoreDisplay = display === "none" ? "" : display; 7468 } 7469 } 7470 style.display = "inline-block"; 7471 } 7472 } 7473 } 7474 7475 if ( opts.overflow ) { 7476 style.overflow = "hidden"; 7477 anim.always( function() { 7478 style.overflow = opts.overflow[ 0 ]; 7479 style.overflowX = opts.overflow[ 1 ]; 7480 style.overflowY = opts.overflow[ 2 ]; 7481 } ); 7482 } 7483 7484 // Implement show/hide animations 7485 propTween = false; 7486 for ( prop in orig ) { 7487 7488 // General show/hide setup for this element animation 7489 if ( !propTween ) { 7490 if ( dataShow ) { 7491 if ( "hidden" in dataShow ) { 7492 hidden = dataShow.hidden; 7493 } 7494 } else { 7495 dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); 7496 } 7497 7498 // Store hidden/visible for toggle so `.stop().toggle()` "reverses" 7499 if ( toggle ) { 7500 dataShow.hidden = !hidden; 7501 } 7502 7503 // Show elements before animating them 7504 if ( hidden ) { 7505 showHide( [ elem ], true ); 7506 } 7507 7508 /* eslint-disable no-loop-func */ 7509 7510 anim.done( function() { 7511 7512 /* eslint-enable no-loop-func */ 7513 7514 // The final step of a "hide" animation is actually hiding the element 7515 if ( !hidden ) { 7516 showHide( [ elem ] ); 7517 } 7518 dataPriv.remove( elem, "fxshow" ); 7519 for ( prop in orig ) { 7520 jQuery.style( elem, prop, orig[ prop ] ); 7521 } 7522 } ); 7523 } 7524 7525 // Per-property setup 7526 propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); 7527 if ( !( prop in dataShow ) ) { 7528 dataShow[ prop ] = propTween.start; 7529 if ( hidden ) { 7530 propTween.end = propTween.start; 7531 propTween.start = 0; 7532 } 7533 } 7534 } 7535} 7536 7537function propFilter( props, specialEasing ) { 7538 var index, name, easing, value, hooks; 7539 7540 // camelCase, specialEasing and expand cssHook pass 7541 for ( index in props ) { 7542 name = camelCase( index ); 7543 easing = specialEasing[ name ]; 7544 value = props[ index ]; 7545 if ( Array.isArray( value ) ) { 7546 easing = value[ 1 ]; 7547 value = props[ index ] = value[ 0 ]; 7548 } 7549 7550 if ( index !== name ) { 7551 props[ name ] = value; 7552 delete props[ index ]; 7553 } 7554 7555 hooks = jQuery.cssHooks[ name ]; 7556 if ( hooks && "expand" in hooks ) { 7557 value = hooks.expand( value ); 7558 delete props[ name ]; 7559 7560 // Not quite $.extend, this won't overwrite existing keys. 7561 // Reusing 'index' because we have the correct "name" 7562 for ( index in value ) { 7563 if ( !( index in props ) ) { 7564 props[ index ] = value[ index ]; 7565 specialEasing[ index ] = easing; 7566 } 7567 } 7568 } else { 7569 specialEasing[ name ] = easing; 7570 } 7571 } 7572} 7573 7574function Animation( elem, properties, options ) { 7575 var result, 7576 stopped, 7577 index = 0, 7578 length = Animation.prefilters.length, 7579 deferred = jQuery.Deferred().always( function() { 7580 7581 // Don't match elem in the :animated selector 7582 delete tick.elem; 7583 } ), 7584 tick = function() { 7585 if ( stopped ) { 7586 return false; 7587 } 7588 var currentTime = fxNow || createFxNow(), 7589 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), 7590
vendor: 9,542 bytes, lines 7591-7981
7591 // Support: Android 2.3 only 7592 // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497) 7593 temp = remaining / animation.duration || 0, 7594 percent = 1 - temp, 7595 index = 0, 7596 length = animation.tweens.length; 7597 7598 for ( ; index < length; index++ ) { 7599 animation.tweens[ index ].run( percent ); 7600 } 7601 7602 deferred.notifyWith( elem, [ animation, percent, remaining ] ); 7603 7604 // If there's more to do, yield 7605 if ( percent < 1 && length ) { 7606 return remaining; 7607 } 7608 7609 // If this was an empty animation, synthesize a final progress notification 7610 if ( !length ) { 7611 deferred.notifyWith( elem, [ animation, 1, 0 ] ); 7612 } 7613 7614 // Resolve the animation and report its conclusion 7615 deferred.resolveWith( elem, [ animation ] ); 7616 return false; 7617 }, 7618 animation = deferred.promise( { 7619 elem: elem, 7620 props: jQuery.extend( {}, properties ), 7621 opts: jQuery.extend( true, { 7622 specialEasing: {}, 7623 easing: jQuery.easing._default 7624 }, options ), 7625 originalProperties: properties, 7626 originalOptions: options, 7627 startTime: fxNow || createFxNow(), 7628 duration: options.duration, 7629 tweens: [], 7630 createTween: function( prop, end ) { 7631 var tween = jQuery.Tween( elem, animation.opts, prop, end, 7632 animation.opts.specialEasing[ prop ] || animation.opts.easing ); 7633 animation.tweens.push( tween ); 7634 return tween; 7635 }, 7636 stop: function( gotoEnd ) { 7637 var index = 0, 7638 7639 // If we are going to the end, we want to run all the tweens 7640 // otherwise we skip this part 7641 length = gotoEnd ? animation.tweens.length : 0; 7642 if ( stopped ) { 7643 return this; 7644 } 7645 stopped = true; 7646 for ( ; index < length; index++ ) { 7647 animation.tweens[ index ].run( 1 ); 7648 } 7649 7650 // Resolve when we played the last frame; otherwise, reject 7651 if ( gotoEnd ) { 7652 deferred.notifyWith( elem, [ animation, 1, 0 ] ); 7653 deferred.resolveWith( elem, [ animation, gotoEnd ] ); 7654 } else { 7655 deferred.rejectWith( elem, [ animation, gotoEnd ] ); 7656 } 7657 return this; 7658 } 7659 } ), 7660 props = animation.props; 7661 7662 propFilter( props, animation.opts.specialEasing ); 7663 7664 for ( ; index < length; index++ ) { 7665 result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); 7666 if ( result ) { 7667 if ( isFunction( result.stop ) ) { 7668 jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = 7669 result.stop.bind( result ); 7670 } 7671 return result; 7672 } 7673 } 7674 7675 jQuery.map( props, createTween, animation ); 7676 7677 if ( isFunction( animation.opts.start ) ) { 7678 animation.opts.start.call( elem, animation ); 7679 } 7680 7681 // Attach callbacks from options 7682 animation 7683 .progress( animation.opts.progress ) 7684 .done( animation.opts.done, animation.opts.complete ) 7685 .fail( animation.opts.fail ) 7686 .always( animation.opts.always ); 7687 7688 jQuery.fx.timer( 7689 jQuery.extend( tick, { 7690 elem: elem, 7691 anim: animation, 7692 queue: animation.opts.queue 7693 } ) 7694 ); 7695 7696 return animation; 7697} 7698 7699jQuery.Animation = jQuery.extend( Animation, { 7700 7701 tweeners: { 7702 "*": [ function( prop, value ) { 7703 var tween = this.createTween( prop, value ); 7704 adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); 7705 return tween; 7706 } ] 7707 }, 7708 7709 tweener: function( props, callback ) { 7710 if ( isFunction( props ) ) { 7711 callback = props; 7712 props = [ "*" ]; 7713 } else { 7714 props = props.match( rnothtmlwhite ); 7715 } 7716 7717 var prop, 7718 index = 0, 7719 length = props.length; 7720 7721 for ( ; index < length; index++ ) { 7722 prop = props[ index ]; 7723 Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; 7724 Animation.tweeners[ prop ].unshift( callback ); 7725 } 7726 }, 7727 7728 prefilters: [ defaultPrefilter ], 7729 7730 prefilter: function( callback, prepend ) { 7731 if ( prepend ) { 7732 Animation.prefilters.unshift( callback ); 7733 } else { 7734 Animation.prefilters.push( callback ); 7735 } 7736 } 7737} ); 7738 7739jQuery.speed = function( speed, easing, fn ) { 7740 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { 7741 complete: fn || !fn && easing || 7742 isFunction( speed ) && speed, 7743 duration: speed, 7744 easing: fn && easing || easing && !isFunction( easing ) && easing 7745 }; 7746 7747 // Go to the end state if fx are off 7748 if ( jQuery.fx.off ) { 7749 opt.duration = 0; 7750 7751 } else { 7752 if ( typeof opt.duration !== "number" ) { 7753 if ( opt.duration in jQuery.fx.speeds ) { 7754 opt.duration = jQuery.fx.speeds[ opt.duration ]; 7755 7756 } else { 7757 opt.duration = jQuery.fx.speeds._default; 7758 } 7759 } 7760 } 7761 7762 // Normalize opt.queue - true/undefined/null -> "fx" 7763 if ( opt.queue == null || opt.queue === true ) { 7764 opt.queue = "fx"; 7765 } 7766 7767 // Queueing 7768 opt.old = opt.complete; 7769 7770 opt.complete = function() { 7771 if ( isFunction( opt.old ) ) { 7772 opt.old.call( this ); 7773 } 7774 7775 if ( opt.queue ) { 7776 jQuery.dequeue( this, opt.queue ); 7777 } 7778 }; 7779 7780 return opt; 7781}; 7782 7783jQuery.fn.extend( { 7784 fadeTo: function( speed, to, easing, callback ) { 7785 7786 // Show any hidden elements after setting opacity to 0 7787 return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() 7788 7789 // Animate to the value specified 7790 .end().animate( { opacity: to }, speed, easing, callback ); 7791 }, 7792 animate: function( prop, speed, easing, callback ) { 7793 var empty = jQuery.isEmptyObject( prop ), 7794 optall = jQuery.speed( speed, easing, callback ), 7795 doAnimation = function() { 7796 7797 // Operate on a copy of prop so per-property easing won't be lost 7798 var anim = Animation( this, jQuery.extend( {}, prop ), optall ); 7799 7800 // Empty animations, or finishing resolves immediately 7801 if ( empty || dataPriv.get( this, "finish" ) ) { 7802 anim.stop( true ); 7803 } 7804 }; 7805 7806 doAnimation.finish = doAnimation; 7807 7808 return empty || optall.queue === false ? 7809 this.each( doAnimation ) : 7810 this.queue( optall.queue, doAnimation ); 7811 }, 7812 stop: function( type, clearQueue, gotoEnd ) { 7813 var stopQueue = function( hooks ) { 7814 var stop = hooks.stop; 7815 delete hooks.stop; 7816 stop( gotoEnd ); 7817 }; 7818 7819 if ( typeof type !== "string" ) { 7820 gotoEnd = clearQueue; 7821 clearQueue = type; 7822 type = undefined; 7823 } 7824 if ( clearQueue ) { 7825 this.queue( type || "fx", [] ); 7826 } 7827 7828 return this.each( function() { 7829 var dequeue = true, 7830 index = type != null && type + "queueHooks", 7831 timers = jQuery.timers, 7832 data = dataPriv.get( this ); 7833 7834 if ( index ) { 7835 if ( data[ index ] && data[ index ].stop ) { 7836 stopQueue( data[ index ] ); 7837 } 7838 } else { 7839 for ( index in data ) { 7840 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { 7841 stopQueue( data[ index ] ); 7842 } 7843 } 7844 } 7845 7846 for ( index = timers.length; index--; ) { 7847 if ( timers[ index ].elem === this && 7848 ( type == null || timers[ index ].queue === type ) ) { 7849 7850 timers[ index ].anim.stop( gotoEnd ); 7851 dequeue = false; 7852 timers.splice( index, 1 ); 7853 } 7854 } 7855 7856 // Start the next in the queue if the last step wasn't forced. 7857 // Timers currently will call their complete callbacks, which 7858 // will dequeue but only if they were gotoEnd. 7859 if ( dequeue || !gotoEnd ) { 7860 jQuery.dequeue( this, type ); 7861 } 7862 } ); 7863 }, 7864 finish: function( type ) { 7865 if ( type !== false ) { 7866 type = type || "fx"; 7867 } 7868 return this.each( function() { 7869 var index, 7870 data = dataPriv.get( this ), 7871 queue = data[ type + "queue" ], 7872 hooks = data[ type + "queueHooks" ], 7873 timers = jQuery.timers, 7874 length = queue ? queue.length : 0; 7875 7876 // Enable finishing flag on private data 7877 data.finish = true; 7878 7879 // Empty the queue first 7880 jQuery.queue( this, type, [] ); 7881 7882 if ( hooks && hooks.stop ) { 7883 hooks.stop.call( this, true ); 7884 } 7885 7886 // Look for any active animations, and finish them 7887 for ( index = timers.length; index--; ) { 7888 if ( timers[ index ].elem === this && timers[ index ].queue === type ) { 7889 timers[ index ].anim.stop( true ); 7890 timers.splice( index, 1 ); 7891 } 7892 } 7893 7894 // Look for any animations in the old queue and finish them 7895 for ( index = 0; index < length; index++ ) { 7896 if ( queue[ index ] && queue[ index ].finish ) { 7897 queue[ index ].finish.call( this ); 7898 } 7899 } 7900 7901 // Turn off finishing flag 7902 delete data.finish; 7903 } ); 7904 } 7905} ); 7906 7907jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { 7908 var cssFn = jQuery.fn[ name ]; 7909 jQuery.fn[ name ] = function( speed, easing, callback ) { 7910 return speed == null || typeof speed === "boolean" ? 7911 cssFn.apply( this, arguments ) : 7912 this.animate( genFx( name, true ), speed, easing, callback ); 7913 }; 7914} ); 7915 7916// Generate shortcuts for custom animations 7917jQuery.each( { 7918 slideDown: genFx( "show" ), 7919 slideUp: genFx( "hide" ), 7920 slideToggle: genFx( "toggle" ), 7921 fadeIn: { opacity: "show" }, 7922 fadeOut: { opacity: "hide" }, 7923 fadeToggle: { opacity: "toggle" } 7924}, function( name, props ) { 7925 jQuery.fn[ name ] = function( speed, easing, callback ) { 7926 return this.animate( props, speed, easing, callback ); 7927 }; 7928} ); 7929 7930jQuery.timers = []; 7931jQuery.fx.tick = function() { 7932 var timer, 7933 i = 0, 7934 timers = jQuery.timers; 7935 7936 fxNow = Date.now(); 7937 7938 for ( ; i < timers.length; i++ ) { 7939 timer = timers[ i ]; 7940 7941 // Run the timer and safely remove it when done (allowing for external removal) 7942 if ( !timer() && timers[ i ] === timer ) { 7943 timers.splice( i--, 1 ); 7944 } 7945 } 7946 7947 if ( !timers.length ) { 7948 jQuery.fx.stop(); 7949 } 7950 fxNow = undefined; 7951}; 7952 7953jQuery.fx.timer = function( timer ) { 7954 jQuery.timers.push( timer ); 7955 jQuery.fx.start(); 7956}; 7957 7958jQuery.fx.interval = 13; 7959jQuery.fx.start = function() { 7960 if ( inProgress ) { 7961 return; 7962 } 7963 7964 inProgress = true; 7965 schedule(); 7966}; 7967 7968jQuery.fx.stop = function() { 7969 inProgress = null; 7970}; 7971 7972jQuery.fx.speeds = { 7973 slow: 600, 7974 fast: 200, 7975 7976 // Default speed 7977 _default: 400 7978}; 7979 7980 7981// Based off of the plugin by Clint Helfers, with permission.
vendor: 5,177 bytes, lines 7982-8202
7982jQuery.fn.delay = function( time, type ) { 7983 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 7984 type = type || "fx"; 7985 7986 return this.queue( type, function( next, hooks ) { 7987 var timeout = window.setTimeout( next, time ); 7988 hooks.stop = function() { 7989 window.clearTimeout( timeout ); 7990 }; 7991 } ); 7992}; 7993 7994 7995( function() { 7996 var input = document.createElement( "input" ), 7997 select = document.createElement( "select" ), 7998 opt = select.appendChild( document.createElement( "option" ) ); 7999 8000 input.type = "checkbox"; 8001 8002 // Support: Android <=4.3 only 8003 // Default value for a checkbox should be "on" 8004 support.checkOn = input.value !== ""; 8005 8006 // Support: IE <=11 only 8007 // Must access selectedIndex to make default options select 8008 support.optSelected = opt.selected; 8009 8010 // Support: IE <=11 only 8011 // An input loses its value after becoming a radio 8012 input = document.createElement( "input" ); 8013 input.value = "t"; 8014 input.type = "radio"; 8015 support.radioValue = input.value === "t"; 8016} )(); 8017 8018 8019var boolHook, 8020 attrHandle = jQuery.expr.attrHandle; 8021 8022jQuery.fn.extend( { 8023 attr: function( name, value ) { 8024 return access( this, jQuery.attr, name, value, arguments.length > 1 ); 8025 }, 8026 8027 removeAttr: function( name ) { 8028 return this.each( function() { 8029 jQuery.removeAttr( this, name ); 8030 } ); 8031 } 8032} ); 8033 8034jQuery.extend( { 8035 attr: function( elem, name, value ) { 8036 var ret, hooks, 8037 nType = elem.nodeType; 8038 8039 // Don't get/set attributes on text, comment and attribute nodes 8040 if ( nType === 3 || nType === 8 || nType === 2 ) { 8041 return; 8042 } 8043 8044 // Fallback to prop when attributes are not supported 8045 if ( typeof elem.getAttribute === "undefined" ) { 8046 return jQuery.prop( elem, name, value ); 8047 } 8048 8049 // Attribute hooks are determined by the lowercase version 8050 // Grab necessary hook if one is defined 8051 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 8052 hooks = jQuery.attrHooks[ name.toLowerCase() ] || 8053 ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); 8054 } 8055 8056 if ( value !== undefined ) { 8057 if ( value === null ) { 8058 jQuery.removeAttr( elem, name ); 8059 return; 8060 } 8061 8062 if ( hooks && "set" in hooks && 8063 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 8064 return ret; 8065 } 8066 8067 elem.setAttribute( name, value + "" ); 8068 return value; 8069 } 8070 8071 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 8072 return ret; 8073 } 8074 8075 ret = jQuery.find.attr( elem, name ); 8076 8077 // Non-existent attributes return null, we normalize to undefined 8078 return ret == null ? undefined : ret; 8079 }, 8080 8081 attrHooks: { 8082 type: { 8083 set: function( elem, value ) { 8084 if ( !support.radioValue && value === "radio" && 8085 nodeName( elem, "input" ) ) { 8086 var val = elem.value; 8087 elem.setAttribute( "type", value ); 8088 if ( val ) { 8089 elem.value = val; 8090 } 8091 return value; 8092 } 8093 } 8094 } 8095 }, 8096 8097 removeAttr: function( elem, value ) { 8098 var name, 8099 i = 0, 8100 8101 // Attribute names can contain non-HTML whitespace characters 8102 // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 8103 attrNames = value && value.match( rnothtmlwhite ); 8104 8105 if ( attrNames && elem.nodeType === 1 ) { 8106 while ( ( name = attrNames[ i++ ] ) ) { 8107 elem.removeAttribute( name ); 8108 } 8109 } 8110 } 8111} ); 8112 8113// Hooks for boolean attributes 8114boolHook = { 8115 set: function( elem, value, name ) { 8116 if ( value === false ) { 8117 8118 // Remove boolean attributes when set to false 8119 jQuery.removeAttr( elem, name ); 8120 } else { 8121 elem.setAttribute( name, name ); 8122 } 8123 return name; 8124 } 8125}; 8126 8127jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { 8128 var getter = attrHandle[ name ] || jQuery.find.attr; 8129 8130 attrHandle[ name ] = function( elem, name, isXML ) { 8131 var ret, handle, 8132 lowercaseName = name.toLowerCase(); 8133 8134 if ( !isXML ) { 8135 8136 // Avoid an infinite loop by temporarily removing this function from the getter 8137 handle = attrHandle[ lowercaseName ]; 8138 attrHandle[ lowercaseName ] = ret; 8139 ret = getter( elem, name, isXML ) != null ? 8140 lowercaseName : 8141 null; 8142 attrHandle[ lowercaseName ] = handle; 8143 } 8144 return ret; 8145 }; 8146} ); 8147 8148 8149 8150 8151var rfocusable = /^(?:input|select|textarea|button)$/i, 8152 rclickable = /^(?:a|area)$/i; 8153 8154jQuery.fn.extend( { 8155 prop: function( name, value ) { 8156 return access( this, jQuery.prop, name, value, arguments.length > 1 ); 8157 }, 8158 8159 removeProp: function( name ) { 8160 return this.each( function() { 8161 delete this[ jQuery.propFix[ name ] || name ]; 8162 } ); 8163 } 8164} ); 8165 8166jQuery.extend( { 8167 prop: function( elem, name, value ) { 8168 var ret, hooks, 8169 nType = elem.nodeType; 8170 8171 // Don't get/set properties on text, comment and attribute nodes 8172 if ( nType === 3 || nType === 8 || nType === 2 ) { 8173 return; 8174 } 8175 8176 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 8177 8178 // Fix name and attach hooks 8179 name = jQuery.propFix[ name ] || name; 8180 hooks = jQuery.propHooks[ name ]; 8181 } 8182 8183 if ( value !== undefined ) { 8184 if ( hooks && "set" in hooks && 8185 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 8186 return ret; 8187 } 8188 8189 return ( elem[ name ] = value ); 8190 } 8191 8192 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 8193 return ret; 8194 } 8195 8196 return elem[ name ]; 8197 }, 8198 8199 propHooks: { 8200 tabIndex: { 8201 get: function( elem ) { 8202
vendor: 6,126 bytes, lines 8203-8462
8203 // Support: IE <=9 - 11 only 8204 // elem.tabIndex doesn't always return the 8205 // correct value when it hasn't been explicitly set 8206 // Use proper attribute retrieval (trac-12072) 8207 var tabindex = jQuery.find.attr( elem, "tabindex" ); 8208 8209 if ( tabindex ) { 8210 return parseInt( tabindex, 10 ); 8211 } 8212 8213 if ( 8214 rfocusable.test( elem.nodeName ) || 8215 rclickable.test( elem.nodeName ) && 8216 elem.href 8217 ) { 8218 return 0; 8219 } 8220 8221 return -1; 8222 } 8223 } 8224 }, 8225 8226 propFix: { 8227 "for": "htmlFor", 8228 "class": "className" 8229 } 8230} ); 8231 8232// Support: IE <=11 only 8233// Accessing the selectedIndex property 8234// forces the browser to respect setting selected 8235// on the option 8236// The getter ensures a default option is selected 8237// when in an optgroup 8238// eslint rule "no-unused-expressions" is disabled for this code 8239// since it considers such accessions noop 8240if ( !support.optSelected ) { 8241 jQuery.propHooks.selected = { 8242 get: function( elem ) { 8243 8244 /* eslint no-unused-expressions: "off" */ 8245 8246 var parent = elem.parentNode; 8247 if ( parent && parent.parentNode ) { 8248 parent.parentNode.selectedIndex; 8249 } 8250 return null; 8251 }, 8252 set: function( elem ) { 8253 8254 /* eslint no-unused-expressions: "off" */ 8255 8256 var parent = elem.parentNode; 8257 if ( parent ) { 8258 parent.selectedIndex; 8259 8260 if ( parent.parentNode ) { 8261 parent.parentNode.selectedIndex; 8262 } 8263 } 8264 } 8265 }; 8266} 8267 8268jQuery.each( [ 8269 "tabIndex", 8270 "readOnly", 8271 "maxLength", 8272 "cellSpacing", 8273 "cellPadding", 8274 "rowSpan", 8275 "colSpan", 8276 "useMap", 8277 "frameBorder", 8278 "contentEditable" 8279], function() { 8280 jQuery.propFix[ this.toLowerCase() ] = this; 8281} ); 8282 8283 8284 8285 8286 // Strip and collapse whitespace according to HTML spec 8287 // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace 8288 function stripAndCollapse( value ) { 8289 var tokens = value.match( rnothtmlwhite ) || []; 8290 return tokens.join( " " ); 8291 } 8292 8293 8294function getClass( elem ) { 8295 return elem.getAttribute && elem.getAttribute( "class" ) || ""; 8296} 8297 8298function classesToArray( value ) { 8299 if ( Array.isArray( value ) ) { 8300 return value; 8301 } 8302 if ( typeof value === "string" ) { 8303 return value.match( rnothtmlwhite ) || []; 8304 } 8305 return []; 8306} 8307 8308jQuery.fn.extend( { 8309 addClass: function( value ) { 8310 var classNames, cur, curValue, className, i, finalValue; 8311 8312 if ( isFunction( value ) ) { 8313 return this.each( function( j ) { 8314 jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); 8315 } ); 8316 } 8317 8318 classNames = classesToArray( value ); 8319 8320 if ( classNames.length ) { 8321 return this.each( function() { 8322 curValue = getClass( this ); 8323 cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); 8324 8325 if ( cur ) { 8326 for ( i = 0; i < classNames.length; i++ ) { 8327 className = classNames[ i ]; 8328 if ( cur.indexOf( " " + className + " " ) < 0 ) { 8329 cur += className + " "; 8330 } 8331 } 8332 8333 // Only assign if different to avoid unneeded rendering. 8334 finalValue = stripAndCollapse( cur ); 8335 if ( curValue !== finalValue ) { 8336 this.setAttribute( "class", finalValue ); 8337 } 8338 } 8339 } ); 8340 } 8341 8342 return this; 8343 }, 8344 8345 removeClass: function( value ) { 8346 var classNames, cur, curValue, className, i, finalValue; 8347 8348 if ( isFunction( value ) ) { 8349 return this.each( function( j ) { 8350 jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); 8351 } ); 8352 } 8353 8354 if ( !arguments.length ) { 8355 return this.attr( "class", "" ); 8356 } 8357 8358 classNames = classesToArray( value ); 8359 8360 if ( classNames.length ) { 8361 return this.each( function() { 8362 curValue = getClass( this ); 8363 8364 // This expression is here for better compressibility (see addClass) 8365 cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); 8366 8367 if ( cur ) { 8368 for ( i = 0; i < classNames.length; i++ ) { 8369 className = classNames[ i ]; 8370 8371 // Remove *all* instances 8372 while ( cur.indexOf( " " + className + " " ) > -1 ) { 8373 cur = cur.replace( " " + className + " ", " " ); 8374 } 8375 } 8376 8377 // Only assign if different to avoid unneeded rendering. 8378 finalValue = stripAndCollapse( cur ); 8379 if ( curValue !== finalValue ) { 8380 this.setAttribute( "class", finalValue ); 8381 } 8382 } 8383 } ); 8384 } 8385 8386 return this; 8387 }, 8388 8389 toggleClass: function( value, stateVal ) { 8390 var classNames, className, i, self, 8391 type = typeof value, 8392 isValidValue = type === "string" || Array.isArray( value ); 8393 8394 if ( isFunction( value ) ) { 8395 return this.each( function( i ) { 8396 jQuery( this ).toggleClass( 8397 value.call( this, i, getClass( this ), stateVal ), 8398 stateVal 8399 ); 8400 } ); 8401 } 8402 8403 if ( typeof stateVal === "boolean" && isValidValue ) { 8404 return stateVal ? this.addClass( value ) : this.removeClass( value ); 8405 } 8406 8407 classNames = classesToArray( value ); 8408 8409 return this.each( function() { 8410 if ( isValidValue ) { 8411 8412 // Toggle individual class names 8413 self = jQuery( this ); 8414 8415 for ( i = 0; i < classNames.length; i++ ) { 8416 className = classNames[ i ]; 8417 8418 // Check each className given, space separated list 8419 if ( self.hasClass( className ) ) { 8420 self.removeClass( className ); 8421 } else { 8422 self.addClass( className ); 8423 } 8424 } 8425 8426 // Toggle whole class name 8427 } else if ( value === undefined || type === "boolean" ) { 8428 className = getClass( this ); 8429 if ( className ) { 8430 8431 // Store className if set 8432 dataPriv.set( this, "__className__", className ); 8433 } 8434 8435 // If the element has a class name or if we're passed `false`, 8436 // then remove the whole classname (if there was one, the above saved it). 8437 // Otherwise bring back whatever was previously saved (if anything), 8438 // falling back to the empty string if nothing was stored. 8439 if ( this.setAttribute ) { 8440 this.setAttribute( "class", 8441 className || value === false ? 8442 "" : 8443 dataPriv.get( this, "__className__" ) || "" 8444 ); 8445 } 8446 } 8447 } ); 8448 }, 8449 8450 hasClass: function( selector ) { 8451 var className, elem, 8452 i = 0; 8453 8454 className = " " + selector + " "; 8455 while ( ( elem = this[ i++ ] ) ) { 8456 if ( elem.nodeType === 1 && 8457 ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { 8458 return true; 8459 } 8460 } 8461 8462 return false;
vendor: 1,385 bytes, lines 8463-8532
8463 } 8464} ); 8465 8466 8467 8468 8469var rreturn = /\r/g; 8470 8471jQuery.fn.extend( { 8472 val: function( value ) { 8473 var hooks, ret, valueIsFunction, 8474 elem = this[ 0 ]; 8475 8476 if ( !arguments.length ) { 8477 if ( elem ) { 8478 hooks = jQuery.valHooks[ elem.type ] || 8479 jQuery.valHooks[ elem.nodeName.toLowerCase() ]; 8480 8481 if ( hooks && 8482 "get" in hooks && 8483 ( ret = hooks.get( elem, "value" ) ) !== undefined 8484 ) { 8485 return ret; 8486 } 8487 8488 ret = elem.value; 8489 8490 // Handle most common string cases 8491 if ( typeof ret === "string" ) { 8492 return ret.replace( rreturn, "" ); 8493 } 8494 8495 // Handle cases where value is null/undef or number 8496 return ret == null ? "" : ret; 8497 } 8498 8499 return; 8500 } 8501 8502 valueIsFunction = isFunction( value ); 8503 8504 return this.each( function( i ) { 8505 var val; 8506 8507 if ( this.nodeType !== 1 ) { 8508 return; 8509 } 8510 8511 if ( valueIsFunction ) { 8512 val = value.call( this, i, jQuery( this ).val() ); 8513 } else { 8514 val = value; 8515 } 8516 8517 // Treat null/undefined as ""; convert numbers to string 8518 if ( val == null ) { 8519 val = ""; 8520 8521 } else if ( typeof val === "number" ) { 8522 val += ""; 8523 8524 } else if ( Array.isArray( val ) ) { 8525 val = jQuery.map( val, function( value ) { 8526 return value == null ? "" : value + ""; 8527 } ); 8528 } 8529 8530 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; 8531 8532 // If set returns undefined, fall back to normal setting
vendor: 8,269 bytes, lines 8533-8847
8533 if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { 8534 this.value = val; 8535 } 8536 } ); 8537 } 8538} ); 8539 8540jQuery.extend( { 8541 valHooks: { 8542 option: { 8543 get: function( elem ) { 8544 8545 var val = jQuery.find.attr( elem, "value" ); 8546 return val != null ? 8547 val : 8548 8549 // Support: IE <=10 - 11 only 8550 // option.text throws exceptions (trac-14686, trac-14858) 8551 // Strip and collapse whitespace 8552 // https://html.spec.whatwg.org/#strip-and-collapse-whitespace 8553 stripAndCollapse( jQuery.text( elem ) ); 8554 } 8555 }, 8556 select: { 8557 get: function( elem ) { 8558 var value, option, i, 8559 options = elem.options, 8560 index = elem.selectedIndex, 8561 one = elem.type === "select-one", 8562 values = one ? null : [], 8563 max = one ? index + 1 : options.length; 8564 8565 if ( index < 0 ) { 8566 i = max; 8567 8568 } else { 8569 i = one ? index : 0; 8570 } 8571 8572 // Loop through all the selected options 8573 for ( ; i < max; i++ ) { 8574 option = options[ i ]; 8575 8576 // Support: IE <=9 only 8577 // IE8-9 doesn't update selected after form reset (trac-2551) 8578 if ( ( option.selected || i === index ) && 8579 8580 // Don't return options that are disabled or in a disabled optgroup 8581 !option.disabled && 8582 ( !option.parentNode.disabled || 8583 !nodeName( option.parentNode, "optgroup" ) ) ) { 8584 8585 // Get the specific value for the option 8586 value = jQuery( option ).val(); 8587 8588 // We don't need an array for one selects 8589 if ( one ) { 8590 return value; 8591 } 8592 8593 // Multi-Selects return an array 8594 values.push( value ); 8595 } 8596 } 8597 8598 return values; 8599 }, 8600 8601 set: function( elem, value ) { 8602 var optionSet, option, 8603 options = elem.options, 8604 values = jQuery.makeArray( value ), 8605 i = options.length; 8606 8607 while ( i-- ) { 8608 option = options[ i ]; 8609 8610 /* eslint-disable no-cond-assign */ 8611 8612 if ( option.selected = 8613 jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 8614 ) { 8615 optionSet = true; 8616 } 8617 8618 /* eslint-enable no-cond-assign */ 8619 } 8620 8621 // Force browsers to behave consistently when non-matching value is set 8622 if ( !optionSet ) { 8623 elem.selectedIndex = -1; 8624 } 8625 return values; 8626 } 8627 } 8628 } 8629} ); 8630 8631// Radios and checkboxes getter/setter 8632jQuery.each( [ "radio", "checkbox" ], function() { 8633 jQuery.valHooks[ this ] = { 8634 set: function( elem, value ) { 8635 if ( Array.isArray( value ) ) { 8636 return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); 8637 } 8638 } 8639 }; 8640 if ( !support.checkOn ) { 8641 jQuery.valHooks[ this ].get = function( elem ) { 8642 return elem.getAttribute( "value" ) === null ? "on" : elem.value; 8643 }; 8644 } 8645} ); 8646 8647 8648 8649 8650// Return jQuery for attributes-only inclusion 8651 8652 8653support.focusin = "onfocusin" in window; 8654 8655 8656var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, 8657 stopPropagationCallback = function( e ) { 8658 e.stopPropagation(); 8659 }; 8660 8661jQuery.extend( jQuery.event, { 8662 8663 trigger: function( event, data, elem, onlyHandlers ) { 8664 8665 var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, 8666 eventPath = [ elem || document ], 8667 type = hasOwn.call( event, "type" ) ? event.type : event, 8668 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; 8669 8670 cur = lastElement = tmp = elem = elem || document; 8671 8672 // Don't do events on text and comment nodes 8673 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 8674 return; 8675 } 8676 8677 // focus/blur morphs to focusin/out; ensure we're not firing them right now 8678 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { 8679 return; 8680 } 8681 8682 if ( type.indexOf( "." ) > -1 ) { 8683 8684 // Namespaced trigger; create a regexp to match event type in handle() 8685 namespaces = type.split( "." ); 8686 type = namespaces.shift(); 8687 namespaces.sort(); 8688 } 8689 ontype = type.indexOf( ":" ) < 0 && "on" + type; 8690 8691 // Caller can pass in a jQuery.Event object, Object, or just an event type string 8692 event = event[ jQuery.expando ] ? 8693 event : 8694 new jQuery.Event( type, typeof event === "object" && event ); 8695 8696 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) 8697 event.isTrigger = onlyHandlers ? 2 : 3; 8698 event.namespace = namespaces.join( "." ); 8699 event.rnamespace = event.namespace ? 8700 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : 8701 null; 8702 8703 // Clean up the event in case it is being reused 8704 event.result = undefined; 8705 if ( !event.target ) { 8706 event.target = elem; 8707 } 8708 8709 // Clone any incoming data and prepend the event, creating the handler arg list 8710 data = data == null ? 8711 [ event ] : 8712 jQuery.makeArray( data, [ event ] ); 8713 8714 // Allow special events to draw outside the lines 8715 special = jQuery.event.special[ type ] || {}; 8716 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { 8717 return; 8718 } 8719 8720 // Determine event propagation path in advance, per W3C events spec (trac-9951) 8721 // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) 8722 if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { 8723 8724 bubbleType = special.delegateType || type; 8725 if ( !rfocusMorph.test( bubbleType + type ) ) { 8726 cur = cur.parentNode; 8727 } 8728 for ( ; cur; cur = cur.parentNode ) { 8729 eventPath.push( cur ); 8730 tmp = cur; 8731 } 8732 8733 // Only add window if we got to document (e.g., not plain obj or detached DOM) 8734 if ( tmp === ( elem.ownerDocument || document ) ) { 8735 eventPath.push( tmp.defaultView || tmp.parentWindow || window ); 8736 } 8737 } 8738 8739 // Fire handlers on the event path 8740 i = 0; 8741 while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { 8742 lastElement = cur; 8743 event.type = i > 1 ? 8744 bubbleType : 8745 special.bindType || type; 8746 8747 // jQuery handler 8748 handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && 8749 dataPriv.get( cur, "handle" ); 8750 if ( handle ) { 8751 handle.apply( cur, data ); 8752 } 8753 8754 // Native handler 8755 handle = ontype && cur[ ontype ]; 8756 if ( handle && handle.apply && acceptData( cur ) ) { 8757 event.result = handle.apply( cur, data ); 8758 if ( event.result === false ) { 8759 event.preventDefault(); 8760 } 8761 } 8762 } 8763 event.type = type; 8764 8765 // If nobody prevented the default action, do it now 8766 if ( !onlyHandlers && !event.isDefaultPrevented() ) { 8767 8768 if ( ( !special._default || 8769 special._default.apply( eventPath.pop(), data ) === false ) && 8770 acceptData( elem ) ) { 8771 8772 // Call a native DOM method on the target with the same name as the event. 8773 // Don't do default actions on window, that's where global variables be (trac-6170) 8774 if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { 8775 8776 // Don't re-trigger an onFOO event when we call its FOO() method 8777 tmp = elem[ ontype ]; 8778 8779 if ( tmp ) { 8780 elem[ ontype ] = null; 8781 } 8782 8783 // Prevent re-triggering of the same event, since we already bubbled it above 8784 jQuery.event.triggered = type; 8785 8786 if ( event.isPropagationStopped() ) { 8787 lastElement.addEventListener( type, stopPropagationCallback ); 8788 } 8789 8790 elem[ type ](); 8791 8792 if ( event.isPropagationStopped() ) { 8793 lastElement.removeEventListener( type, stopPropagationCallback ); 8794 } 8795 8796 jQuery.event.triggered = undefined; 8797 8798 if ( tmp ) { 8799 elem[ ontype ] = tmp; 8800 } 8801 } 8802 } 8803 } 8804 8805 return event.result; 8806 }, 8807 8808 // Piggyback on a donor event to simulate a different one 8809 // Used only for `focus(in | out)` events 8810 simulate: function( type, elem, event ) { 8811 var e = jQuery.extend( 8812 new jQuery.Event(), 8813 event, 8814 { 8815 type: type, 8816 isSimulated: true 8817 } 8818 ); 8819 8820 jQuery.event.trigger( e, null, elem ); 8821 } 8822 8823} ); 8824 8825jQuery.fn.extend( { 8826 8827 trigger: function( type, data ) { 8828 return this.each( function() { 8829 jQuery.event.trigger( type, data, this ); 8830 } ); 8831 }, 8832 triggerHandler: function( type, data ) { 8833 var elem = this[ 0 ]; 8834 if ( elem ) { 8835 return jQuery.event.trigger( type, data, elem, true ); 8836 } 8837 } 8838} ); 8839 8840 8841// Support: Firefox <=44 8842// Firefox doesn't have focus(in | out) events 8843// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 8844// 8845// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 8846// focus(in | out) events fire after focus & blur events, 8847// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
vendor: 4,255 bytes, lines 8848-9017
8848// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 8849if ( !support.focusin ) { 8850 jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { 8851 8852 // Attach a single capturing handler on the document while someone wants focusin/focusout 8853 var handler = function( event ) { 8854 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); 8855 }; 8856 8857 jQuery.event.special[ fix ] = { 8858 setup: function() { 8859 8860 // Handle: regular nodes (via `this.ownerDocument`), window 8861 // (via `this.document`) & document (via `this`). 8862 var doc = this.ownerDocument || this.document || this, 8863 attaches = dataPriv.access( doc, fix ); 8864 8865 if ( !attaches ) { 8866 doc.addEventListener( orig, handler, true ); 8867 } 8868 dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); 8869 }, 8870 teardown: function() { 8871 var doc = this.ownerDocument || this.document || this, 8872 attaches = dataPriv.access( doc, fix ) - 1; 8873 8874 if ( !attaches ) { 8875 doc.removeEventListener( orig, handler, true ); 8876 dataPriv.remove( doc, fix ); 8877 8878 } else { 8879 dataPriv.access( doc, fix, attaches ); 8880 } 8881 } 8882 }; 8883 } ); 8884} 8885var location = window.location; 8886 8887var nonce = { guid: Date.now() }; 8888 8889var rquery = ( /\?/ ); 8890 8891 8892 8893// Cross-browser xml parsing 8894jQuery.parseXML = function( data ) { 8895 var xml, parserErrorElem; 8896 if ( !data || typeof data !== "string" ) { 8897 return null; 8898 } 8899 8900 // Support: IE 9 - 11 only 8901 // IE throws on parseFromString with invalid input. 8902 try { 8903 xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); 8904 } catch ( e ) {} 8905 8906 parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; 8907 if ( !xml || parserErrorElem ) { 8908 jQuery.error( "Invalid XML: " + ( 8909 parserErrorElem ? 8910 jQuery.map( parserErrorElem.childNodes, function( el ) { 8911 return el.textContent; 8912 } ).join( "\n" ) : 8913 data 8914 ) ); 8915 } 8916 return xml; 8917}; 8918 8919 8920var 8921 rbracket = /\[\]$/, 8922 rCRLF = /\r?\n/g, 8923 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 8924 rsubmittable = /^(?:input|select|textarea|keygen)/i; 8925 8926function buildParams( prefix, obj, traditional, add ) { 8927 var name; 8928 8929 if ( Array.isArray( obj ) ) { 8930 8931 // Serialize array item. 8932 jQuery.each( obj, function( i, v ) { 8933 if ( traditional || rbracket.test( prefix ) ) { 8934 8935 // Treat each array item as a scalar. 8936 add( prefix, v ); 8937 8938 } else { 8939 8940 // Item is non-scalar (array or object), encode its numeric index. 8941 buildParams( 8942 prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", 8943 v, 8944 traditional, 8945 add 8946 ); 8947 } 8948 } ); 8949 8950 } else if ( !traditional && toType( obj ) === "object" ) { 8951 8952 // Serialize object item. 8953 for ( name in obj ) { 8954 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 8955 } 8956 8957 } else { 8958 8959 // Serialize scalar item. 8960 add( prefix, obj ); 8961 } 8962} 8963 8964// Serialize an array of form elements or a set of 8965// key/values into a query string 8966jQuery.param = function( a, traditional ) { 8967 var prefix, 8968 s = [], 8969 add = function( key, valueOrFunction ) { 8970 8971 // If value is a function, invoke it and use its return value 8972 var value = isFunction( valueOrFunction ) ? 8973 valueOrFunction() : 8974 valueOrFunction; 8975 8976 s[ s.length ] = encodeURIComponent( key ) + "=" + 8977 encodeURIComponent( value == null ? "" : value ); 8978 }; 8979 8980 if ( a == null ) { 8981 return ""; 8982 } 8983 8984 // If an array was passed in, assume that it is an array of form elements. 8985 if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 8986 8987 // Serialize the form elements 8988 jQuery.each( a, function() { 8989 add( this.name, this.value ); 8990 } ); 8991 8992 } else { 8993 8994 // If traditional, encode the "old" way (the way 1.3.2 or older 8995 // did it), otherwise encode params recursively. 8996 for ( prefix in a ) { 8997 buildParams( prefix, a[ prefix ], traditional, add ); 8998 } 8999 } 9000 9001 // Return the resulting serialization 9002 return s.join( "&" ); 9003}; 9004 9005jQuery.fn.extend( { 9006 serialize: function() { 9007 return jQuery.param( this.serializeArray() ); 9008 }, 9009 serializeArray: function() { 9010 return this.map( function() { 9011 9012 // Can add propHook for "elements" to filter or add form elements 9013 var elements = jQuery.prop( this, "elements" ); 9014 return elements ? jQuery.makeArray( elements ) : this; 9015 } ).filter( function() { 9016 var type = this.type; 9017
vendor: 32,437 bytes, lines 9018-10271
9018 // Use .is( ":disabled" ) so that fieldset[disabled] works 9019 return this.name && !jQuery( this ).is( ":disabled" ) && 9020 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && 9021 ( this.checked || !rcheckableType.test( type ) ); 9022 } ).map( function( _i, elem ) { 9023 var val = jQuery( this ).val(); 9024 9025 if ( val == null ) { 9026 return null; 9027 } 9028 9029 if ( Array.isArray( val ) ) { 9030 return jQuery.map( val, function( val ) { 9031 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9032 } ); 9033 } 9034 9035 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9036 } ).get(); 9037 } 9038} ); 9039 9040 9041var 9042 r20 = /%20/g, 9043 rhash = /#.*$/, 9044 rantiCache = /([?&])_=[^&]*/, 9045 rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, 9046 9047 // trac-7653, trac-8125, trac-8152: local protocol detection 9048 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, 9049 rnoContent = /^(?:GET|HEAD)$/, 9050 rprotocol = /^\/\//, 9051 9052 /* Prefilters 9053 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) 9054 * 2) These are called: 9055 * - BEFORE asking for a transport 9056 * - AFTER param serialization (s.data is a string if s.processData is true) 9057 * 3) key is the dataType 9058 * 4) the catchall symbol "*" can be used 9059 * 5) execution will start with transport dataType and THEN continue down to "*" if needed 9060 */ 9061 prefilters = {}, 9062 9063 /* Transports bindings 9064 * 1) key is the dataType 9065 * 2) the catchall symbol "*" can be used 9066 * 3) selection will start with transport dataType and THEN go to "*" if needed 9067 */ 9068 transports = {}, 9069 9070 // Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression 9071 allTypes = "*/".concat( "*" ), 9072 9073 // Anchor tag for parsing the document origin 9074 originAnchor = document.createElement( "a" ); 9075 9076originAnchor.href = location.href; 9077 9078// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport 9079function addToPrefiltersOrTransports( structure ) { 9080 9081 // dataTypeExpression is optional and defaults to "*" 9082 return function( dataTypeExpression, func ) { 9083 9084 if ( typeof dataTypeExpression !== "string" ) { 9085 func = dataTypeExpression; 9086 dataTypeExpression = "*"; 9087 } 9088 9089 var dataType, 9090 i = 0, 9091 dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; 9092 9093 if ( isFunction( func ) ) { 9094 9095 // For each dataType in the dataTypeExpression 9096 while ( ( dataType = dataTypes[ i++ ] ) ) { 9097 9098 // Prepend if requested 9099 if ( dataType[ 0 ] === "+" ) { 9100 dataType = dataType.slice( 1 ) || "*"; 9101 ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); 9102 9103 // Otherwise append 9104 } else { 9105 ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); 9106 } 9107 } 9108 } 9109 }; 9110} 9111 9112// Base inspection function for prefilters and transports 9113function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { 9114 9115 var inspected = {}, 9116 seekingTransport = ( structure === transports ); 9117 9118 function inspect( dataType ) { 9119 var selected; 9120 inspected[ dataType ] = true; 9121 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { 9122 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); 9123 if ( typeof dataTypeOrTransport === "string" && 9124 !seekingTransport && !inspected[ dataTypeOrTransport ] ) { 9125 9126 options.dataTypes.unshift( dataTypeOrTransport ); 9127 inspect( dataTypeOrTransport ); 9128 return false; 9129 } else if ( seekingTransport ) { 9130 return !( selected = dataTypeOrTransport ); 9131 } 9132 } ); 9133 return selected; 9134 } 9135 9136 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); 9137} 9138 9139// A special extend for ajax options 9140// that takes "flat" options (not to be deep extended) 9141// Fixes trac-9887 9142function ajaxExtend( target, src ) { 9143 var key, deep, 9144 flatOptions = jQuery.ajaxSettings.flatOptions || {}; 9145 9146 for ( key in src ) { 9147 if ( src[ key ] !== undefined ) { 9148 ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; 9149 } 9150 } 9151 if ( deep ) { 9152 jQuery.extend( true, target, deep ); 9153 } 9154 9155 return target; 9156} 9157 9158/* Handles responses to an ajax request: 9159 * - finds the right dataType (mediates between content-type and expected dataType) 9160 * - returns the corresponding response 9161 */ 9162function ajaxHandleResponses( s, jqXHR, responses ) { 9163 9164 var ct, type, finalDataType, firstDataType, 9165 contents = s.contents, 9166 dataTypes = s.dataTypes; 9167 9168 // Remove auto dataType and get content-type in the process 9169 while ( dataTypes[ 0 ] === "*" ) { 9170 dataTypes.shift(); 9171 if ( ct === undefined ) { 9172 ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); 9173 } 9174 } 9175 9176 // Check if we're dealing with a known content-type 9177 if ( ct ) { 9178 for ( type in contents ) { 9179 if ( contents[ type ] && contents[ type ].test( ct ) ) { 9180 dataTypes.unshift( type ); 9181 break; 9182 } 9183 } 9184 } 9185 9186 // Check to see if we have a response for the expected dataType 9187 if ( dataTypes[ 0 ] in responses ) { 9188 finalDataType = dataTypes[ 0 ]; 9189 } else { 9190 9191 // Try convertible dataTypes 9192 for ( type in responses ) { 9193 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { 9194 finalDataType = type; 9195 break; 9196 } 9197 if ( !firstDataType ) { 9198 firstDataType = type; 9199 } 9200 } 9201 9202 // Or just use first one 9203 finalDataType = finalDataType || firstDataType; 9204 } 9205 9206 // If we found a dataType 9207 // We add the dataType to the list if needed 9208 // and return the corresponding response 9209 if ( finalDataType ) { 9210 if ( finalDataType !== dataTypes[ 0 ] ) { 9211 dataTypes.unshift( finalDataType ); 9212 } 9213 return responses[ finalDataType ]; 9214 } 9215} 9216 9217/* Chain conversions given the request and the original response 9218 * Also sets the responseXXX fields on the jqXHR instance 9219 */ 9220function ajaxConvert( s, response, jqXHR, isSuccess ) { 9221 var conv2, current, conv, tmp, prev, 9222 converters = {}, 9223 9224 // Work with a copy of dataTypes in case we need to modify it for conversion 9225 dataTypes = s.dataTypes.slice(); 9226 9227 // Create converters map with lowercased keys 9228 if ( dataTypes[ 1 ] ) { 9229 for ( conv in s.converters ) { 9230 converters[ conv.toLowerCase() ] = s.converters[ conv ]; 9231 } 9232 } 9233 9234 current = dataTypes.shift(); 9235 9236 // Convert to each sequential dataType 9237 while ( current ) { 9238 9239 if ( s.responseFields[ current ] ) { 9240 jqXHR[ s.responseFields[ current ] ] = response; 9241 } 9242 9243 // Apply the dataFilter if provided 9244 if ( !prev && isSuccess && s.dataFilter ) { 9245 response = s.dataFilter( response, s.dataType ); 9246 } 9247 9248 prev = current; 9249 current = dataTypes.shift(); 9250 9251 if ( current ) { 9252 9253 // There's only work to do if current dataType is non-auto 9254 if ( current === "*" ) { 9255 9256 current = prev; 9257 9258 // Convert response if prev dataType is non-auto and differs from current 9259 } else if ( prev !== "*" && prev !== current ) { 9260 9261 // Seek a direct converter 9262 conv = converters[ prev + " " + current ] || converters[ "* " + current ]; 9263 9264 // If none found, seek a pair 9265 if ( !conv ) { 9266 for ( conv2 in converters ) { 9267 9268 // If conv2 outputs current 9269 tmp = conv2.split( " " ); 9270 if ( tmp[ 1 ] === current ) { 9271 9272 // If prev can be converted to accepted input 9273 conv = converters[ prev + " " + tmp[ 0 ] ] || 9274 converters[ "* " + tmp[ 0 ] ]; 9275 if ( conv ) { 9276 9277 // Condense equivalence converters 9278 if ( conv === true ) { 9279 conv = converters[ conv2 ]; 9280 9281 // Otherwise, insert the intermediate dataType 9282 } else if ( converters[ conv2 ] !== true ) { 9283 current = tmp[ 0 ]; 9284 dataTypes.unshift( tmp[ 1 ] ); 9285 } 9286 break; 9287 } 9288 } 9289 } 9290 } 9291 9292 // Apply converter (if not an equivalence) 9293 if ( conv !== true ) { 9294 9295 // Unless errors are allowed to bubble, catch and return them 9296 if ( conv && s.throws ) { 9297 response = conv( response ); 9298 } else { 9299 try { 9300 response = conv( response ); 9301 } catch ( e ) { 9302 return { 9303 state: "parsererror", 9304 error: conv ? e : "No conversion from " + prev + " to " + current 9305 }; 9306 } 9307 } 9308 } 9309 } 9310 } 9311 } 9312 9313 return { state: "success", data: response }; 9314} 9315 9316jQuery.extend( { 9317 9318 // Counter for holding the number of active queries 9319 active: 0, 9320 9321 // Last-Modified header cache for next request 9322 lastModified: {}, 9323 etag: {}, 9324 9325 ajaxSettings: { 9326 url: location.href, 9327 type: "GET", 9328 isLocal: rlocalProtocol.test( location.protocol ), 9329 global: true, 9330 processData: true, 9331 async: true, 9332 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 9333 9334 /* 9335 timeout: 0, 9336 data: null, 9337 dataType: null, 9338 username: null, 9339 password: null, 9340 cache: null, 9341 throws: false, 9342 traditional: false, 9343 headers: {}, 9344 */ 9345 9346 accepts: { 9347 "*": allTypes, 9348 text: "text/plain", 9349 html: "text/html", 9350 xml: "application/xml, text/xml", 9351 json: "application/json, text/javascript" 9352 }, 9353 9354 contents: { 9355 xml: /\bxml\b/, 9356 html: /\bhtml/, 9357 json: /\bjson\b/ 9358 }, 9359 9360 responseFields: { 9361 xml: "responseXML", 9362 text: "responseText", 9363 json: "responseJSON" 9364 }, 9365 9366 // Data converters 9367 // Keys separate source (or catchall "*") and destination types with a single space 9368 converters: { 9369 9370 // Convert anything to text 9371 "* text": String, 9372 9373 // Text to html (true = no transformation) 9374 "text html": true, 9375 9376 // Evaluate text as a json expression 9377 "text json": JSON.parse, 9378 9379 // Parse text as xml 9380 "text xml": jQuery.parseXML 9381 }, 9382 9383 // For options that shouldn't be deep extended: 9384 // you can add your own custom options here if 9385 // and when you create one that shouldn't be 9386 // deep extended (see ajaxExtend) 9387 flatOptions: { 9388 url: true, 9389 context: true 9390 } 9391 }, 9392 9393 // Creates a full fledged settings object into target 9394 // with both ajaxSettings and settings fields. 9395 // If target is omitted, writes into ajaxSettings. 9396 ajaxSetup: function( target, settings ) { 9397 return settings ? 9398 9399 // Building a settings object 9400 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : 9401 9402 // Extending ajaxSettings 9403 ajaxExtend( jQuery.ajaxSettings, target ); 9404 }, 9405 9406 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), 9407 ajaxTransport: addToPrefiltersOrTransports( transports ), 9408 9409 // Main method 9410 ajax: function( url, options ) { 9411 9412 // If url is an object, simulate pre-1.5 signature 9413 if ( typeof url === "object" ) { 9414 options = url; 9415 url = undefined; 9416 } 9417 9418 // Force options to be an object 9419 options = options || {}; 9420 9421 var transport, 9422 9423 // URL without anti-cache param 9424 cacheURL, 9425 9426 // Response headers 9427 responseHeadersString, 9428 responseHeaders, 9429 9430 // timeout handle 9431 timeoutTimer, 9432 9433 // Url cleanup var 9434 urlAnchor, 9435 9436 // Request state (becomes false upon send and true upon completion) 9437 completed, 9438 9439 // To know if global events are to be dispatched 9440 fireGlobals, 9441 9442 // Loop variable 9443 i, 9444 9445 // uncached part of the url 9446 uncached, 9447 9448 // Create the final options object 9449 s = jQuery.ajaxSetup( {}, options ), 9450 9451 // Callbacks context 9452 callbackContext = s.context || s, 9453 9454 // Context for global events is callbackContext if it is a DOM node or jQuery collection 9455 globalEventContext = s.context && 9456 ( callbackContext.nodeType || callbackContext.jquery ) ? 9457 jQuery( callbackContext ) : 9458 jQuery.event, 9459 9460 // Deferreds 9461 deferred = jQuery.Deferred(), 9462 completeDeferred = jQuery.Callbacks( "once memory" ), 9463 9464 // Status-dependent callbacks 9465 statusCode = s.statusCode || {}, 9466 9467 // Headers (they are sent all at once) 9468 requestHeaders = {}, 9469 requestHeadersNames = {}, 9470 9471 // Default abort message 9472 strAbort = "canceled", 9473 9474 // Fake xhr 9475 jqXHR = { 9476 readyState: 0, 9477 9478 // Builds headers hashtable if needed 9479 getResponseHeader: function( key ) { 9480 var match; 9481 if ( completed ) { 9482 if ( !responseHeaders ) { 9483 responseHeaders = {}; 9484 while ( ( match = rheaders.exec( responseHeadersString ) ) ) { 9485 responseHeaders[ match[ 1 ].toLowerCase() + " " ] = 9486 ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) 9487 .concat( match[ 2 ] ); 9488 } 9489 } 9490 match = responseHeaders[ key.toLowerCase() + " " ]; 9491 } 9492 return match == null ? null : match.join( ", " ); 9493 }, 9494 9495 // Raw string 9496 getAllResponseHeaders: function() { 9497 return completed ? responseHeadersString : null; 9498 }, 9499 9500 // Caches the header 9501 setRequestHeader: function( name, value ) { 9502 if ( completed == null ) { 9503 name = requestHeadersNames[ name.toLowerCase() ] = 9504 requestHeadersNames[ name.toLowerCase() ] || name; 9505 requestHeaders[ name ] = value; 9506 } 9507 return this; 9508 }, 9509 9510 // Overrides response content-type header 9511 overrideMimeType: function( type ) { 9512 if ( completed == null ) { 9513 s.mimeType = type; 9514 } 9515 return this; 9516 }, 9517 9518 // Status-dependent callbacks 9519 statusCode: function( map ) { 9520 var code; 9521 if ( map ) { 9522 if ( completed ) { 9523 9524 // Execute the appropriate callbacks 9525 jqXHR.always( map[ jqXHR.status ] ); 9526 } else { 9527 9528 // Lazy-add the new callbacks in a way that preserves old ones 9529 for ( code in map ) { 9530 statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; 9531 } 9532 } 9533 } 9534 return this; 9535 }, 9536 9537 // Cancel the request 9538 abort: function( statusText ) { 9539 var finalText = statusText || strAbort; 9540 if ( transport ) { 9541 transport.abort( finalText ); 9542 } 9543 done( 0, finalText ); 9544 return this; 9545 } 9546 }; 9547 9548 // Attach deferreds 9549 deferred.promise( jqXHR ); 9550 9551 // Add protocol if not provided (prefilters might expect it) 9552 // Handle falsy url in the settings object (trac-10093: consistency with old signature) 9553 // We also use the url parameter if available 9554 s.url = ( ( url || s.url || location.href ) + "" ) 9555 .replace( rprotocol, location.protocol + "//" ); 9556 9557 // Alias method option to type as per ticket trac-12004 9558 s.type = options.method || options.type || s.method || s.type; 9559 9560 // Extract dataTypes list 9561 s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; 9562 9563 // A cross-domain request is in order when the origin doesn't match the current origin. 9564 if ( s.crossDomain == null ) { 9565 urlAnchor = document.createElement( "a" ); 9566 9567 // Support: IE <=8 - 11, Edge 12 - 15 9568 // IE throws exception on accessing the href property if url is malformed, 9569 // e.g. http://example.com:80x/ 9570 try { 9571 urlAnchor.href = s.url; 9572 9573 // Support: IE <=8 - 11 only 9574 // Anchor's host property isn't correctly set when s.url is relative 9575 urlAnchor.href = urlAnchor.href; 9576 s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== 9577 urlAnchor.protocol + "//" + urlAnchor.host; 9578 } catch ( e ) { 9579 9580 // If there is an error parsing the URL, assume it is crossDomain, 9581 // it can be rejected by the transport if it is invalid 9582 s.crossDomain = true; 9583 } 9584 } 9585 9586 // Convert data if not already a string 9587 if ( s.data && s.processData && typeof s.data !== "string" ) { 9588 s.data = jQuery.param( s.data, s.traditional ); 9589 } 9590 9591 // Apply prefilters 9592 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); 9593 9594 // If request was aborted inside a prefilter, stop there 9595 if ( completed ) { 9596 return jqXHR; 9597 } 9598 9599 // We can fire global events as of now if asked to 9600 // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118) 9601 fireGlobals = jQuery.event && s.global; 9602 9603 // Watch for a new set of requests 9604 if ( fireGlobals && jQuery.active++ === 0 ) { 9605 jQuery.event.trigger( "ajaxStart" ); 9606 } 9607 9608 // Uppercase the type 9609 s.type = s.type.toUpperCase(); 9610 9611 // Determine if request has content 9612 s.hasContent = !rnoContent.test( s.type ); 9613 9614 // Save the URL in case we're toying with the If-Modified-Since 9615 // and/or If-None-Match header later on 9616 // Remove hash to simplify url manipulation 9617 cacheURL = s.url.replace( rhash, "" ); 9618 9619 // More options handling for requests with no content 9620 if ( !s.hasContent ) { 9621 9622 // Remember the hash so we can put it back 9623 uncached = s.url.slice( cacheURL.length ); 9624 9625 // If data is available and should be processed, append data to url 9626 if ( s.data && ( s.processData || typeof s.data === "string" ) ) { 9627 cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; 9628 9629 // trac-9682: remove data so that it's not used in an eventual retry 9630 delete s.data; 9631 } 9632 9633 // Add or update anti-cache param if needed 9634 if ( s.cache === false ) { 9635 cacheURL = cacheURL.replace( rantiCache, "$1" ); 9636 uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + 9637 uncached; 9638 } 9639 9640 // Put hash and anti-cache on the URL that will be requested (gh-1732) 9641 s.url = cacheURL + uncached; 9642 9643 // Change '%20' to '+' if this is encoded form body content (gh-2658) 9644 } else if ( s.data && s.processData && 9645 ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { 9646 s.data = s.data.replace( r20, "+" ); 9647 } 9648 9649 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9650 if ( s.ifModified ) { 9651 if ( jQuery.lastModified[ cacheURL ] ) { 9652 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); 9653 } 9654 if ( jQuery.etag[ cacheURL ] ) { 9655 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); 9656 } 9657 } 9658 9659 // Set the correct header, if data is being sent 9660 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { 9661 jqXHR.setRequestHeader( "Content-Type", s.contentType ); 9662 } 9663 9664 // Set the Accepts header for the server, depending on the dataType 9665 jqXHR.setRequestHeader( 9666 "Accept", 9667 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? 9668 s.accepts[ s.dataTypes[ 0 ] ] + 9669 ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : 9670 s.accepts[ "*" ] 9671 ); 9672 9673 // Check for headers option 9674 for ( i in s.headers ) { 9675 jqXHR.setRequestHeader( i, s.headers[ i ] ); 9676 } 9677 9678 // Allow custom headers/mimetypes and early abort 9679 if ( s.beforeSend && 9680 ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { 9681 9682 // Abort if not done already and return 9683 return jqXHR.abort(); 9684 } 9685 9686 // Aborting is no longer a cancellation 9687 strAbort = "abort"; 9688 9689 // Install callbacks on deferreds 9690 completeDeferred.add( s.complete ); 9691 jqXHR.done( s.success ); 9692 jqXHR.fail( s.error ); 9693 9694 // Get transport 9695 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); 9696 9697 // If no transport, we auto-abort 9698 if ( !transport ) { 9699 done( -1, "No Transport" ); 9700 } else { 9701 jqXHR.readyState = 1; 9702 9703 // Send global event 9704 if ( fireGlobals ) { 9705 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); 9706 } 9707 9708 // If request was aborted inside ajaxSend, stop there 9709 if ( completed ) { 9710 return jqXHR; 9711 } 9712 9713 // Timeout 9714 if ( s.async && s.timeout > 0 ) { 9715 timeoutTimer = window.setTimeout( function() { 9716 jqXHR.abort( "timeout" ); 9717 }, s.timeout ); 9718 } 9719 9720 try { 9721 completed = false; 9722 transport.send( requestHeaders, done ); 9723 } catch ( e ) { 9724 9725 // Rethrow post-completion exceptions 9726 if ( completed ) { 9727 throw e; 9728 } 9729 9730 // Propagate others as results 9731 done( -1, e ); 9732 } 9733 } 9734 9735 // Callback for when everything is done 9736 function done( status, nativeStatusText, responses, headers ) { 9737 var isSuccess, success, error, response, modified, 9738 statusText = nativeStatusText; 9739 9740 // Ignore repeat invocations 9741 if ( completed ) { 9742 return; 9743 } 9744 9745 completed = true; 9746 9747 // Clear timeout if it exists 9748 if ( timeoutTimer ) { 9749 window.clearTimeout( timeoutTimer ); 9750 } 9751 9752 // Dereference transport for early garbage collection 9753 // (no matter how long the jqXHR object will be used) 9754 transport = undefined; 9755 9756 // Cache response headers 9757 responseHeadersString = headers || ""; 9758 9759 // Set readyState 9760 jqXHR.readyState = status > 0 ? 4 : 0; 9761 9762 // Determine if successful 9763 isSuccess = status >= 200 && status < 300 || status === 304; 9764 9765 // Get response data 9766 if ( responses ) { 9767 response = ajaxHandleResponses( s, jqXHR, responses ); 9768 } 9769 9770 // Use a noop converter for missing script but not if jsonp 9771 if ( !isSuccess && 9772 jQuery.inArray( "script", s.dataTypes ) > -1 && 9773 jQuery.inArray( "json", s.dataTypes ) < 0 ) { 9774 s.converters[ "text script" ] = function() {}; 9775 } 9776 9777 // Convert no matter what (that way responseXXX fields are always set) 9778 response = ajaxConvert( s, response, jqXHR, isSuccess ); 9779 9780 // If successful, handle type chaining 9781 if ( isSuccess ) { 9782 9783 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9784 if ( s.ifModified ) { 9785 modified = jqXHR.getResponseHeader( "Last-Modified" ); 9786 if ( modified ) { 9787 jQuery.lastModified[ cacheURL ] = modified; 9788 } 9789 modified = jqXHR.getResponseHeader( "etag" ); 9790 if ( modified ) { 9791 jQuery.etag[ cacheURL ] = modified; 9792 } 9793 } 9794 9795 // if no content 9796 if ( status === 204 || s.type === "HEAD" ) { 9797 statusText = "nocontent"; 9798 9799 // if not modified 9800 } else if ( status === 304 ) { 9801 statusText = "notmodified"; 9802 9803 // If we have data, let's convert it 9804 } else { 9805 statusText = response.state; 9806 success = response.data; 9807 error = response.error; 9808 isSuccess = !error; 9809 } 9810 } else { 9811 9812 // Extract error from statusText and normalize for non-aborts 9813 error = statusText; 9814 if ( status || !statusText ) { 9815 statusText = "error"; 9816 if ( status < 0 ) { 9817 status = 0; 9818 } 9819 } 9820 } 9821 9822 // Set data for the fake xhr object 9823 jqXHR.status = status; 9824 jqXHR.statusText = ( nativeStatusText || statusText ) + ""; 9825 9826 // Success/Error 9827 if ( isSuccess ) { 9828 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); 9829 } else { 9830 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); 9831 } 9832 9833 // Status-dependent callbacks 9834 jqXHR.statusCode( statusCode ); 9835 statusCode = undefined; 9836 9837 if ( fireGlobals ) { 9838 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", 9839 [ jqXHR, s, isSuccess ? success : error ] ); 9840 } 9841 9842 // Complete 9843 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); 9844 9845 if ( fireGlobals ) { 9846 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); 9847 9848 // Handle the global AJAX counter 9849 if ( !( --jQuery.active ) ) { 9850 jQuery.event.trigger( "ajaxStop" ); 9851 } 9852 } 9853 } 9854 9855 return jqXHR; 9856 }, 9857 9858 getJSON: function( url, data, callback ) { 9859 return jQuery.get( url, data, callback, "json" ); 9860 }, 9861 9862 getScript: function( url, callback ) { 9863 return jQuery.get( url, undefined, callback, "script" ); 9864 } 9865} ); 9866 9867jQuery.each( [ "get", "post" ], function( _i, method ) { 9868 jQuery[ method ] = function( url, data, callback, type ) { 9869 9870 // Shift arguments if data argument was omitted 9871 if ( isFunction( data ) ) { 9872 type = type || callback; 9873 callback = data; 9874 data = undefined; 9875 } 9876 9877 // The url can be an options object (which then must have .url) 9878 return jQuery.ajax( jQuery.extend( { 9879 url: url, 9880 type: method, 9881 dataType: type, 9882 data: data, 9883 success: callback 9884 }, jQuery.isPlainObject( url ) && url ) ); 9885 }; 9886} ); 9887 9888jQuery.ajaxPrefilter( function( s ) { 9889 var i; 9890 for ( i in s.headers ) { 9891 if ( i.toLowerCase() === "content-type" ) { 9892 s.contentType = s.headers[ i ] || ""; 9893 } 9894 } 9895} ); 9896 9897 9898jQuery._evalUrl = function( url, options, doc ) { 9899 return jQuery.ajax( { 9900 url: url, 9901 9902 // Make this explicit, since user can override this through ajaxSetup (trac-11264) 9903 type: "GET", 9904 dataType: "script", 9905 cache: true, 9906 async: false, 9907 global: false, 9908 9909 // Only evaluate the response if it is successful (gh-4126) 9910 // dataFilter is not invoked for failure responses, so using it instead 9911 // of the default converter is kludgy but it works. 9912 converters: { 9913 "text script": function() {} 9914 }, 9915 dataFilter: function( response ) { 9916 jQuery.globalEval( response, options, doc ); 9917 } 9918 } ); 9919}; 9920 9921 9922jQuery.fn.extend( { 9923 wrapAll: function( html ) { 9924 var wrap; 9925 9926 if ( this[ 0 ] ) { 9927 if ( isFunction( html ) ) { 9928 html = html.call( this[ 0 ] ); 9929 } 9930 9931 // The elements to wrap the target around 9932 wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); 9933 9934 if ( this[ 0 ].parentNode ) { 9935 wrap.insertBefore( this[ 0 ] ); 9936 } 9937 9938 wrap.map( function() { 9939 var elem = this; 9940 9941 while ( elem.firstElementChild ) { 9942 elem = elem.firstElementChild; 9943 } 9944 9945 return elem; 9946 } ).append( this ); 9947 } 9948 9949 return this; 9950 }, 9951 9952 wrapInner: function( html ) { 9953 if ( isFunction( html ) ) { 9954 return this.each( function( i ) { 9955 jQuery( this ).wrapInner( html.call( this, i ) ); 9956 } ); 9957 } 9958 9959 return this.each( function() { 9960 var self = jQuery( this ), 9961 contents = self.contents(); 9962 9963 if ( contents.length ) { 9964 contents.wrapAll( html ); 9965 9966 } else { 9967 self.append( html ); 9968 } 9969 } ); 9970 }, 9971 9972 wrap: function( html ) { 9973 var htmlIsFunction = isFunction( html ); 9974 9975 return this.each( function( i ) { 9976 jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); 9977 } ); 9978 }, 9979 9980 unwrap: function( selector ) { 9981 this.parent( selector ).not( "body" ).each( function() { 9982 jQuery( this ).replaceWith( this.childNodes ); 9983 } ); 9984 return this; 9985 } 9986} ); 9987 9988 9989jQuery.expr.pseudos.hidden = function( elem ) { 9990 return !jQuery.expr.pseudos.visible( elem ); 9991}; 9992jQuery.expr.pseudos.visible = function( elem ) { 9993 return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); 9994}; 9995 9996 9997 9998 9999jQuery.ajaxSettings.xhr = function() { 10000 try { 10001 return new window.XMLHttpRequest(); 10002 } catch ( e ) {} 10003}; 10004 10005var xhrSuccessStatus = { 10006 10007 // File protocol always yields status code 0, assume 200 10008 0: 200, 10009 10010 // Support: IE <=9 only 10011 // trac-1450: sometimes IE returns 1223 when it should be 204 10012 1223: 204 10013 }, 10014 xhrSupported = jQuery.ajaxSettings.xhr(); 10015 10016support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); 10017support.ajax = xhrSupported = !!xhrSupported; 10018 10019jQuery.ajaxTransport( function( options ) { 10020 var callback, errorCallback; 10021 10022 // Cross domain only allowed if supported through XMLHttpRequest 10023 if ( support.cors || xhrSupported && !options.crossDomain ) { 10024 return { 10025 send: function( headers, complete ) { 10026 var i, 10027 xhr = options.xhr(); 10028 10029 xhr.open( 10030 options.type, 10031 options.url, 10032 options.async, 10033 options.username, 10034 options.password 10035 ); 10036 10037 // Apply custom fields if provided 10038 if ( options.xhrFields ) { 10039 for ( i in options.xhrFields ) { 10040 xhr[ i ] = options.xhrFields[ i ]; 10041 } 10042 } 10043 10044 // Override mime type if needed 10045 if ( options.mimeType && xhr.overrideMimeType ) { 10046 xhr.overrideMimeType( options.mimeType ); 10047 } 10048 10049 // X-Requested-With header 10050 // For cross-domain requests, seeing as conditions for a preflight are 10051 // akin to a jigsaw puzzle, we simply never set it to be sure. 10052 // (it can always be set on a per-request basis or even using ajaxSetup) 10053 // For same-domain requests, won't change header if already provided. 10054 if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { 10055 headers[ "X-Requested-With" ] = "XMLHttpRequest"; 10056 } 10057 10058 // Set headers 10059 for ( i in headers ) { 10060 xhr.setRequestHeader( i, headers[ i ] ); 10061 } 10062 10063 // Callback 10064 callback = function( type ) { 10065 return function() { 10066 if ( callback ) { 10067 callback = errorCallback = xhr.onload = 10068 xhr.onerror = xhr.onabort = xhr.ontimeout = 10069 xhr.onreadystatechange = null; 10070 10071 if ( type === "abort" ) { 10072 xhr.abort(); 10073 } else if ( type === "error" ) { 10074 10075 // Support: IE <=9 only 10076 // On a manual native abort, IE9 throws 10077 // errors on any property access that is not readyState 10078 if ( typeof xhr.status !== "number" ) { 10079 complete( 0, "error" ); 10080 } else { 10081 complete( 10082 10083 // File: protocol always yields status 0; see trac-8605, trac-14207 10084 xhr.status, 10085 xhr.statusText 10086 ); 10087 } 10088 } else { 10089 complete( 10090 xhrSuccessStatus[ xhr.status ] || xhr.status, 10091 xhr.statusText, 10092 10093 // Support: IE <=9 only 10094 // IE9 has no XHR2 but throws on binary (trac-11426) 10095 // For XHR2 non-text, let the caller handle it (gh-2498) 10096 ( xhr.responseType || "text" ) !== "text" || 10097 typeof xhr.responseText !== "string" ? 10098 { binary: xhr.response } : 10099 { text: xhr.responseText }, 10100 xhr.getAllResponseHeaders() 10101 ); 10102 } 10103 } 10104 }; 10105 }; 10106 10107 // Listen to events 10108 xhr.onload = callback(); 10109 errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); 10110 10111 // Support: IE 9 only 10112 // Use onreadystatechange to replace onabort 10113 // to handle uncaught aborts 10114 if ( xhr.onabort !== undefined ) { 10115 xhr.onabort = errorCallback; 10116 } else { 10117 xhr.onreadystatechange = function() { 10118 10119 // Check readyState before timeout as it changes 10120 if ( xhr.readyState === 4 ) { 10121 10122 // Allow onerror to be called first, 10123 // but that will not handle a native abort 10124 // Also, save errorCallback to a variable 10125 // as xhr.onerror cannot be accessed 10126 window.setTimeout( function() { 10127 if ( callback ) { 10128 errorCallback(); 10129 } 10130 } ); 10131 } 10132 }; 10133 } 10134 10135 // Create the abort callback 10136 callback = callback( "abort" ); 10137 10138 try { 10139 10140 // Do send the request (this may raise an exception) 10141 xhr.send( options.hasContent && options.data || null ); 10142 } catch ( e ) { 10143 10144 // trac-14683: Only rethrow if this hasn't been notified as an error yet 10145 if ( callback ) { 10146 throw e; 10147 } 10148 } 10149 }, 10150 10151 abort: function() { 10152 if ( callback ) { 10153 callback(); 10154 } 10155 } 10156 }; 10157 } 10158} ); 10159 10160 10161 10162 10163// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) 10164jQuery.ajaxPrefilter( function( s ) { 10165 if ( s.crossDomain ) { 10166 s.contents.script = false; 10167 } 10168} ); 10169 10170// Install script dataType 10171jQuery.ajaxSetup( { 10172 accepts: { 10173 script: "text/javascript, application/javascript, " + 10174 "application/ecmascript, application/x-ecmascript" 10175 }, 10176 contents: { 10177 script: /\b(?:java|ecma)script\b/ 10178 }, 10179 converters: { 10180 "text script": function( text ) { 10181 jQuery.globalEval( text ); 10182 return text; 10183 } 10184 } 10185} ); 10186 10187// Handle cache's special case and crossDomain 10188jQuery.ajaxPrefilter( "script", function( s ) { 10189 if ( s.cache === undefined ) { 10190 s.cache = false; 10191 } 10192 if ( s.crossDomain ) { 10193 s.type = "GET"; 10194 } 10195} ); 10196 10197// Bind script tag hack transport 10198jQuery.ajaxTransport( "script", function( s ) { 10199 10200 // This transport only deals with cross domain or forced-by-attrs requests 10201 if ( s.crossDomain || s.scriptAttrs ) { 10202 var script, callback; 10203 return { 10204 send: function( _, complete ) { 10205 script = jQuery( "<script>" ) 10206 .attr( s.scriptAttrs || {} ) 10207 .prop( { charset: s.scriptCharset, src: s.url } ) 10208 .on( "load error", callback = function( evt ) { 10209 script.remove(); 10210 callback = null; 10211 if ( evt ) { 10212 complete( evt.type === "error" ? 404 : 200, evt.type ); 10213 } 10214 } ); 10215 10216 // Use native DOM manipulation to avoid our domManip AJAX trickery 10217 document.head.appendChild( script[ 0 ] ); 10218 }, 10219 abort: function() { 10220 if ( callback ) { 10221 callback(); 10222 } 10223 } 10224 }; 10225 } 10226} ); 10227 10228 10229 10230 10231var oldCallbacks = [], 10232 rjsonp = /(=)\?(?=&|$)|\?\?/; 10233 10234// Default jsonp settings 10235jQuery.ajaxSetup( { 10236 jsonp: "callback", 10237 jsonpCallback: function() { 10238 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) ); 10239 this[ callback ] = true; 10240 return callback; 10241 } 10242} ); 10243 10244// Detect, normalize options and install callbacks for jsonp requests 10245jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 10246 10247 var callbackName, overwritten, responseContainer, 10248 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 10249 "url" : 10250 typeof s.data === "string" && 10251 ( s.contentType || "" ) 10252 .indexOf( "application/x-www-form-urlencoded" ) === 0 && 10253 rjsonp.test( s.data ) && "data" 10254 ); 10255 10256 // Handle iff the expected data type is "jsonp" or we have a parameter to set 10257 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 10258 10259 // Get callback name, remembering preexisting value associated with it 10260 callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ? 10261 s.jsonpCallback() : 10262 s.jsonpCallback; 10263 10264 // Insert callback into url or form data 10265 if ( jsonProp ) { 10266 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 10267 } else if ( s.jsonp !== false ) { 10268 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 10269 } 10270 10271 // Use data converter to retrieve json after script execution
vendor: 8,362 bytes, lines 10272-10583
10272 s.converters[ "script json" ] = function() { 10273 if ( !responseContainer ) { 10274 jQuery.error( callbackName + " was not called" ); 10275 } 10276 return responseContainer[ 0 ]; 10277 }; 10278 10279 // Force json dataType 10280 s.dataTypes[ 0 ] = "json"; 10281 10282 // Install callback 10283 overwritten = window[ callbackName ]; 10284 window[ callbackName ] = function() { 10285 responseContainer = arguments; 10286 }; 10287 10288 // Clean-up function (fires after converters) 10289 jqXHR.always( function() { 10290 10291 // If previous value didn't exist - remove it 10292 if ( overwritten === undefined ) { 10293 jQuery( window ).removeProp( callbackName ); 10294 10295 // Otherwise restore preexisting value 10296 } else { 10297 window[ callbackName ] = overwritten; 10298 } 10299 10300 // Save back as free 10301 if ( s[ callbackName ] ) { 10302 10303 // Make sure that re-using the options doesn't screw things around 10304 s.jsonpCallback = originalSettings.jsonpCallback; 10305 10306 // Save the callback name for future use 10307 oldCallbacks.push( callbackName ); 10308 } 10309 10310 // Call if it was a function and we have a response 10311 if ( responseContainer && isFunction( overwritten ) ) { 10312 overwritten( responseContainer[ 0 ] ); 10313 } 10314 10315 responseContainer = overwritten = undefined; 10316 } ); 10317 10318 // Delegate to script 10319 return "script"; 10320 } 10321} ); 10322 10323 10324 10325 10326// Support: Safari 8 only 10327// In Safari 8 documents created via document.implementation.createHTMLDocument 10328// collapse sibling forms: the second one becomes a child of the first one. 10329// Because of that, this security measure has to be disabled in Safari 8. 10330// https://bugs.webkit.org/show_bug.cgi?id=137337 10331support.createHTMLDocument = ( function() { 10332 var body = document.implementation.createHTMLDocument( "" ).body; 10333 body.innerHTML = "<form></form><form></form>"; 10334 return body.childNodes.length === 2; 10335} )(); 10336 10337 10338// Argument "data" should be string of html 10339// context (optional): If specified, the fragment will be created in this context, 10340// defaults to document 10341// keepScripts (optional): If true, will include scripts passed in the html string 10342jQuery.parseHTML = function( data, context, keepScripts ) { 10343 if ( typeof data !== "string" ) { 10344 return []; 10345 } 10346 if ( typeof context === "boolean" ) { 10347 keepScripts = context; 10348 context = false; 10349 } 10350 10351 var base, parsed, scripts; 10352 10353 if ( !context ) { 10354 10355 // Stop scripts or inline event handlers from being executed immediately 10356 // by using document.implementation 10357 if ( support.createHTMLDocument ) { 10358 context = document.implementation.createHTMLDocument( "" ); 10359 10360 // Set the base href for the created document 10361 // so any parsed elements with URLs 10362 // are based on the document's URL (gh-2965) 10363 base = context.createElement( "base" ); 10364 base.href = document.location.href; 10365 context.head.appendChild( base ); 10366 } else { 10367 context = document; 10368 } 10369 } 10370 10371 parsed = rsingleTag.exec( data ); 10372 scripts = !keepScripts && []; 10373 10374 // Single tag 10375 if ( parsed ) { 10376 return [ context.createElement( parsed[ 1 ] ) ]; 10377 } 10378 10379 parsed = buildFragment( [ data ], context, scripts ); 10380 10381 if ( scripts && scripts.length ) { 10382 jQuery( scripts ).remove(); 10383 } 10384 10385 return jQuery.merge( [], parsed.childNodes ); 10386}; 10387 10388 10389/** 10390 * Load a url into a page 10391 */ 10392jQuery.fn.load = function( url, params, callback ) { 10393 var selector, type, response, 10394 self = this, 10395 off = url.indexOf( " " ); 10396 10397 if ( off > -1 ) { 10398 selector = stripAndCollapse( url.slice( off ) ); 10399 url = url.slice( 0, off ); 10400 } 10401 10402 // If it's a function 10403 if ( isFunction( params ) ) { 10404 10405 // We assume that it's the callback 10406 callback = params; 10407 params = undefined; 10408 10409 // Otherwise, build a param string 10410 } else if ( params && typeof params === "object" ) { 10411 type = "POST"; 10412 } 10413 10414 // If we have elements to modify, make the request 10415 if ( self.length > 0 ) { 10416 jQuery.ajax( { 10417 url: url, 10418 10419 // If "type" variable is undefined, then "GET" method will be used. 10420 // Make value of this field explicit since 10421 // user can override it through ajaxSetup method 10422 type: type || "GET", 10423 dataType: "html", 10424 data: params 10425 } ).done( function( responseText ) { 10426 10427 // Save response for use in complete callback 10428 response = arguments; 10429 10430 self.html( selector ? 10431 10432 // If a selector was specified, locate the right elements in a dummy div 10433 // Exclude scripts to avoid IE 'Permission Denied' errors 10434 jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : 10435 10436 // Otherwise use the full result 10437 responseText ); 10438 10439 // If the request succeeds, this function gets "data", "status", "jqXHR" 10440 // but they are ignored because response was set above. 10441 // If it fails, this function gets "jqXHR", "status", "error" 10442 } ).always( callback && function( jqXHR, status ) { 10443 self.each( function() { 10444 callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); 10445 } ); 10446 } ); 10447 } 10448 10449 return this; 10450}; 10451 10452 10453 10454 10455jQuery.expr.pseudos.animated = function( elem ) { 10456 return jQuery.grep( jQuery.timers, function( fn ) { 10457 return elem === fn.elem; 10458 } ).length; 10459}; 10460 10461 10462 10463 10464jQuery.offset = { 10465 setOffset: function( elem, options, i ) { 10466 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, 10467 position = jQuery.css( elem, "position" ), 10468 curElem = jQuery( elem ), 10469 props = {}; 10470 10471 // Set position first, in-case top/left are set even on static elem 10472 if ( position === "static" ) { 10473 elem.style.position = "relative"; 10474 } 10475 10476 curOffset = curElem.offset(); 10477 curCSSTop = jQuery.css( elem, "top" ); 10478 curCSSLeft = jQuery.css( elem, "left" ); 10479 calculatePosition = ( position === "absolute" || position === "fixed" ) && 10480 ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1; 10481 10482 // Need to be able to calculate position if either 10483 // top or left is auto and position is either absolute or fixed 10484 if ( calculatePosition ) { 10485 curPosition = curElem.position(); 10486 curTop = curPosition.top; 10487 curLeft = curPosition.left; 10488 10489 } else { 10490 curTop = parseFloat( curCSSTop ) || 0; 10491 curLeft = parseFloat( curCSSLeft ) || 0; 10492 } 10493 10494 if ( isFunction( options ) ) { 10495 10496 // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) 10497 options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); 10498 } 10499 10500 if ( options.top != null ) { 10501 props.top = ( options.top - curOffset.top ) + curTop; 10502 } 10503 if ( options.left != null ) { 10504 props.left = ( options.left - curOffset.left ) + curLeft; 10505 } 10506 10507 if ( "using" in options ) { 10508 options.using.call( elem, props ); 10509 10510 } else { 10511 curElem.css( props ); 10512 } 10513 } 10514}; 10515 10516jQuery.fn.extend( { 10517 10518 // offset() relates an element's border box to the document origin 10519 offset: function( options ) { 10520 10521 // Preserve chaining for setter 10522 if ( arguments.length ) { 10523 return options === undefined ? 10524 this : 10525 this.each( function( i ) { 10526 jQuery.offset.setOffset( this, options, i ); 10527 } ); 10528 } 10529 10530 var rect, win, 10531 elem = this[ 0 ]; 10532 10533 if ( !elem ) { 10534 return; 10535 } 10536 10537 // Return zeros for disconnected and hidden (display: none) elements (gh-2310) 10538 // Support: IE <=11 only 10539 // Running getBoundingClientRect on a 10540 // disconnected node in IE throws an error 10541 if ( !elem.getClientRects().length ) { 10542 return { top: 0, left: 0 }; 10543 } 10544 10545 // Get document-relative position by adding viewport scroll to viewport-relative gBCR 10546 rect = elem.getBoundingClientRect(); 10547 win = elem.ownerDocument.defaultView; 10548 return { 10549 top: rect.top + win.pageYOffset, 10550 left: rect.left + win.pageXOffset 10551 }; 10552 }, 10553 10554 // position() relates an element's margin box to its offset parent's padding box 10555 // This corresponds to the behavior of CSS absolute positioning 10556 position: function() { 10557 if ( !this[ 0 ] ) { 10558 return; 10559 } 10560 10561 var offsetParent, offset, doc, 10562 elem = this[ 0 ], 10563 parentOffset = { top: 0, left: 0 }; 10564 10565 // position:fixed elements are offset from the viewport, which itself always has zero offset 10566 if ( jQuery.css( elem, "position" ) === "fixed" ) { 10567 10568 // Assume position:fixed implies availability of getBoundingClientRect 10569 offset = elem.getBoundingClientRect(); 10570 10571 } else { 10572 offset = this.offset(); 10573 10574 // Account for the *real* offset parent, which can be the document or its root element 10575 // when a statically positioned element is identified 10576 doc = elem.ownerDocument; 10577 offsetParent = elem.offsetParent || doc.documentElement; 10578 while ( offsetParent && 10579 ( offsetParent === doc.body || offsetParent === doc.documentElement ) && 10580 jQuery.css( offsetParent, "position" ) === "static" ) { 10581 10582 offsetParent = offsetParent.parentNode; 10583 }
vendor: 8,798 bytes, lines 10584-10875
10584 if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) { 10585 10586 // Incorporate borders into its offset, since they are outside its content origin 10587 parentOffset = jQuery( offsetParent ).offset(); 10588 parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true ); 10589 parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true ); 10590 } 10591 } 10592 10593 // Subtract parent offsets and element margins 10594 return { 10595 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), 10596 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) 10597 }; 10598 }, 10599 10600 // This method will return documentElement in the following cases: 10601 // 1) For the element inside the iframe without offsetParent, this method will return 10602 // documentElement of the parent window 10603 // 2) For the hidden or detached element 10604 // 3) For body or html element, i.e. in case of the html node - it will return itself 10605 // 10606 // but those exceptions were never presented as a real life use-cases 10607 // and might be considered as more preferable results. 10608 // 10609 // This logic, however, is not guaranteed and can change at any point in the future 10610 offsetParent: function() { 10611 return this.map( function() { 10612 var offsetParent = this.offsetParent; 10613 10614 while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) { 10615 offsetParent = offsetParent.offsetParent; 10616 } 10617 10618 return offsetParent || documentElement; 10619 } ); 10620 } 10621} ); 10622 10623// Create scrollLeft and scrollTop methods 10624jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { 10625 var top = "pageYOffset" === prop; 10626 10627 jQuery.fn[ method ] = function( val ) { 10628 return access( this, function( elem, method, val ) { 10629 10630 // Coalesce documents and windows 10631 var win; 10632 if ( isWindow( elem ) ) { 10633 win = elem; 10634 } else if ( elem.nodeType === 9 ) { 10635 win = elem.defaultView; 10636 } 10637 10638 if ( val === undefined ) { 10639 return win ? win[ prop ] : elem[ method ]; 10640 } 10641 10642 if ( win ) { 10643 win.scrollTo( 10644 !top ? val : win.pageXOffset, 10645 top ? val : win.pageYOffset 10646 ); 10647 10648 } else { 10649 elem[ method ] = val; 10650 } 10651 }, method, val, arguments.length ); 10652 }; 10653} ); 10654 10655// Support: Safari <=7 - 9.1, Chrome <=37 - 49 10656// Add the top/left cssHooks using jQuery.fn.position 10657// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 10658// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347 10659// getComputedStyle returns percent when specified for top/left/bottom/right; 10660// rather than make the css module depend on the offset module, just check for it here 10661jQuery.each( [ "top", "left" ], function( _i, prop ) { 10662 jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, 10663 function( elem, computed ) { 10664 if ( computed ) { 10665 computed = curCSS( elem, prop ); 10666 10667 // If curCSS returns percentage, fallback to offset 10668 return rnumnonpx.test( computed ) ? 10669 jQuery( elem ).position()[ prop ] + "px" : 10670 computed; 10671 } 10672 } 10673 ); 10674} ); 10675 10676 10677// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods 10678jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { 10679 jQuery.each( { 10680 padding: "inner" + name, 10681 content: type, 10682 "": "outer" + name 10683 }, function( defaultExtra, funcName ) { 10684 10685 // Margin is only for outerHeight, outerWidth 10686 jQuery.fn[ funcName ] = function( margin, value ) { 10687 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), 10688 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); 10689 10690 return access( this, function( elem, type, value ) { 10691 var doc; 10692 10693 if ( isWindow( elem ) ) { 10694 10695 // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) 10696 return funcName.indexOf( "outer" ) === 0 ? 10697 elem[ "inner" + name ] : 10698 elem.document.documentElement[ "client" + name ]; 10699 } 10700 10701 // Get document width or height 10702 if ( elem.nodeType === 9 ) { 10703 doc = elem.documentElement; 10704 10705 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], 10706 // whichever is greatest 10707 return Math.max( 10708 elem.body[ "scroll" + name ], doc[ "scroll" + name ], 10709 elem.body[ "offset" + name ], doc[ "offset" + name ], 10710 doc[ "client" + name ] 10711 ); 10712 } 10713 10714 return value === undefined ? 10715 10716 // Get width or height on the element, requesting but not forcing parseFloat 10717 jQuery.css( elem, type, extra ) : 10718 10719 // Set width or height on the element 10720 jQuery.style( elem, type, value, extra ); 10721 }, type, chainable ? margin : undefined, chainable ); 10722 }; 10723 } ); 10724} ); 10725 10726 10727jQuery.each( [ 10728 "ajaxStart", 10729 "ajaxStop", 10730 "ajaxComplete", 10731 "ajaxError", 10732 "ajaxSuccess", 10733 "ajaxSend" 10734], function( _i, type ) { 10735 jQuery.fn[ type ] = function( fn ) { 10736 return this.on( type, fn ); 10737 }; 10738} ); 10739 10740 10741 10742 10743jQuery.fn.extend( { 10744 10745 bind: function( types, data, fn ) { 10746 return this.on( types, null, data, fn ); 10747 }, 10748 unbind: function( types, fn ) { 10749 return this.off( types, null, fn ); 10750 }, 10751 10752 delegate: function( selector, types, data, fn ) { 10753 return this.on( types, selector, data, fn ); 10754 }, 10755 undelegate: function( selector, types, fn ) { 10756 10757 // ( namespace ) or ( selector, types [, fn] ) 10758 return arguments.length === 1 ? 10759 this.off( selector, "**" ) : 10760 this.off( types, selector || "**", fn ); 10761 }, 10762 10763 hover: function( fnOver, fnOut ) { 10764 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 10765 } 10766} ); 10767 10768jQuery.each( 10769 ( "blur focus focusin focusout resize scroll click dblclick " + 10770 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 10771 "change select submit keydown keypress keyup contextmenu" ).split( " " ), 10772 function( _i, name ) { 10773 10774 // Handle event binding 10775 jQuery.fn[ name ] = function( data, fn ) { 10776 return arguments.length > 0 ? 10777 this.on( name, null, data, fn ) : 10778 this.trigger( name ); 10779 }; 10780 } 10781); 10782 10783 10784 10785 10786// Support: Android <=4.0 only 10787// Make sure we trim BOM and NBSP 10788// Require that the "whitespace run" starts from a non-whitespace 10789// to avoid O(N^2) behavior when the engine would try matching "\s+$" at each space position. 10790var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g; 10791 10792// Bind a function to a context, optionally partially applying any 10793// arguments. 10794// jQuery.proxy is deprecated to promote standards (specifically Function#bind) 10795// However, it is not slated for removal any time soon 10796jQuery.proxy = function( fn, context ) { 10797 var tmp, args, proxy; 10798 10799 if ( typeof context === "string" ) { 10800 tmp = fn[ context ]; 10801 context = fn; 10802 fn = tmp; 10803 } 10804 10805 // Quick check to determine if target is callable, in the spec 10806 // this throws a TypeError, but we will just return undefined. 10807 if ( !isFunction( fn ) ) { 10808 return undefined; 10809 } 10810 10811 // Simulated bind 10812 args = slice.call( arguments, 2 ); 10813 proxy = function() { 10814 return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); 10815 }; 10816 10817 // Set the guid of unique handler to the same of original handler, so it can be removed 10818 proxy.guid = fn.guid = fn.guid || jQuery.guid++; 10819 10820 return proxy; 10821}; 10822 10823jQuery.holdReady = function( hold ) { 10824 if ( hold ) { 10825 jQuery.readyWait++; 10826 } else { 10827 jQuery.ready( true ); 10828 } 10829}; 10830jQuery.isArray = Array.isArray; 10831jQuery.parseJSON = JSON.parse; 10832jQuery.nodeName = nodeName; 10833jQuery.isFunction = isFunction; 10834jQuery.isWindow = isWindow; 10835jQuery.camelCase = camelCase; 10836jQuery.type = toType; 10837 10838jQuery.now = Date.now; 10839 10840jQuery.isNumeric = function( obj ) { 10841 10842 // As of jQuery 3.0, isNumeric is limited to 10843 // strings and numbers (primitives or objects) 10844 // that can be coerced to finite numbers (gh-2662) 10845 var type = jQuery.type( obj ); 10846 return ( type === "number" || type === "string" ) && 10847 10848 // parseFloat NaNs numeric-cast false positives ("") 10849 // ...but misinterprets leading-number strings, particularly hex literals ("0x...") 10850 // subtraction forces infinities to NaN 10851 !isNaN( obj - parseFloat( obj ) ); 10852}; 10853 10854jQuery.trim = function( text ) { 10855 return text == null ? 10856 "" : 10857 ( text + "" ).replace( rtrim, "$1" ); 10858}; 10859 10860 10861 10862// Register as a named AMD module, since jQuery can be concatenated with other 10863// files that may use define, but not via a proper concatenation script that 10864// understands anonymous AMD modules. A named AMD is safest and most robust 10865// way to register. Lowercase jquery is used because AMD module names are 10866// derived from file names, and jQuery is normally delivered in a lowercase 10867// file name. Do this after creating the global so that if an AMD module wants 10868// to call noConflict to hide this version of jQuery, it will work. 10869 10870// Note that for maximum portability, libraries that are not jQuery should 10871// declare themselves as anonymous modules, and avoid setting a global if an 10872// AMD loader is present. jQuery is a special case. For more information, see 10873// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon 10874 10875if ( t
vendor: 6,946 bytes, lines 10875-10924
10875rue ) { 10876 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function() { 10877 return jQuery; 10878 }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 10879 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 10880} 10881 10882 10883 10884 10885var 10886 10887 // Map over jQuery in case of overwrite 10888 _jQuery = window.jQuery, 10889 10890 // Map over the $ in case of overwrite 10891 _$ = window.$; 10892 10893jQuery.noConflict = function( deep ) { 10894 if ( window.$ === jQuery ) { 10895 window.$ = _$; 10896 } 10897 10898 if ( deep && window.jQuery === jQuery ) { 10899 window.jQuery = _jQuery; 10900 } 10901 10902 return jQuery; 10903}; 10904 10905// Expose jQuery and $ identifiers, even in AMD 10906// (trac-7102#comment:10, https://github.com/jquery/jquery/pull/557) 10907// and CommonJS for browser emulators (trac-13566) 10908if ( typeof noGlobal === "undefined" ) { 10909 window.jQuery = window.$ = jQuery; 10910} 10911 10912 10913 10914 10915return jQuery; 10916} ); 10917 10918 10919/***/ }), 10920 10921/***/ 582: 10922/***/ (function(module) { 10923 10924!function(t,i){ true?module.exports=i():0}(this,function(){"use strict";function t(t,r,e,a,h){!function t(n,r,e,a,h){for(;a>e;){if(a-e>600){var o=a-e+1,s=r-e+1,l=Math.log(o),f=.5*Math.exp(2*l/3),u=.5*Math.sqrt(l*f*(o-f)/o)*(s-o/2<0?-1:1),m=Math.max(e,Math.floor(r-s*f/o+u)),c=Math.min(a,Math.floor(r+(o-s)*f/o+u));t(n,r,m,c,h)}var p=n[r],d=e,x=a;for(i(n,e,r),h(n[a],p)>0&&i(n,e,a);d<x;){for(i(n,d,x),d++,x--;h(n[d],p)<0;)d++;for(;h(n[x],p)>0;)x--}0===h(n[e],p)?i(n,e,x):i(n,++x,a),x<=r&&(e=x+1),r<=x&&(a=x-1)}}(t,r,e||0,a||t.length-1,h||n)}function i(t,i,n){var r=t[i];t[i]=t[n],t[n]=r}function n(t,i){return t<i?-1:t>i?1:0}var r=function(t){void 0===t&&(t=9),this._maxEntries=Math.max(4,t),this._minEntries=Math.max(2,Math.ceil(.4*this._maxEntries)),this.clear()};function e(t,i,n){if(!n)return i.indexOf(t);for(var r=0;r<i.length;r++)if(n(t,i[r]))return r;return-1}function a(t,i){h(t,0,t.children.length,i,t)}function h(t,i,n,r,e){e||(e=p(null)),e.minX=1/0,e.minY=1/0,e.maxX=-1/0,e.maxY=-1/0;for(var a=i;a<n;a++){var h=t.children[a];o(e,t.leaf?r(h):h)}return e}function o(t,i){return t.minX=Math.min(t.minX,i.minX),t.minY=Math.min(t.minY,i.minY),t.maxX=Math.max(t.maxX,i.maxX),t.maxY=Math.max(t.maxY,i.maxY),t}function s(t,i){return t.minX-i.minX}function l(t,i){return t.minY-i.minY}function f(t){return(t.maxX-t.minX)*(t.maxY-t.minY)}function u(t){return t.maxX-t.minX+(t.maxY-t.minY)}function m(t,i){return t.minX<=i.minX&&t.minY<=i.minY&&i.maxX<=t.maxX&&i.maxY<=t.maxY}function c(t,i){return i.minX<=t.maxX&&i.minY<=t.maxY&&i.maxX>=t.minX&&i.maxY>=t.minY}function p(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function d(i,n,r,e,a){for(var h=[n,r];h.length;)if(!((r=h.pop())-(n=h.pop())<=e)){var o=n+Math.ceil((r-n)/e/2)*e;t(i,o,n,r,a),h.push(n,o,o,r)}}return r.prototype.all=function(){return this._all(this.data,[])},r.prototype.search=function(t){var i=this.data,n=[];if(!c(t,i))return n;for(var r=this.toBBox,e=[];i;){for(var a=0;a<i.children.length;a++){var h=i.children[a],o=i.leaf?r(h):h;c(t,o)&&(i.leaf?n.push(h):m(t,o)?this._all(h,n):e.push(h))}i=e.pop()}return n},r.prototype.collides=function(t){var i=this.data;if(!c(t,i))return!1;for(var n=[];i;){for(var r=0;r<i.children.length;r++){var e=i.children[r],a=i.leaf?this.toBBox(e):e;if(c(t,a)){if(i.leaf||m(t,a))return!0;n.push(e)}}i=n.pop()}return!1},r.prototype.load=function(t){if(!t||!t.length)return this;if(t.length<this._minEntries){for(var i=0;i<t.length;i++)this.insert(t[i]);return this}var n=this._build(t.slice(),0,t.length-1,0);if(this.data.children.length)if(this.data.height===n.height)this._splitRoot(this.data,n);else{if(this.data.height<n.height){var r=this.data;this.data=n,n=r}this._insert(n,this.data.height-n.height-1,!0)}else this.data=n;return this},r.prototype.insert=function(t){return t&&this._insert(t,this.data.height-1),this},r.prototype.clear=function(){return this.data=p([]),this},r.prototype.remove=function(t,i){if(!t)return this;for(var n,r,a,h=this.data,o=this.toBBox(t),s=[],l=[];h||s.length;){if(h||(h=s.pop(),r=s[s.length-1],n=l.pop(),a=!0),h.leaf){var f=e(t,h.children,i);if(-1!==f)return h.children.splice(f,1),s.push(h),this._condense(s),this}a||h.leaf||!m(h,o)?r?(n++,h=r.children[n],a=!1):h=null:(s.push(h),l.push(n),n=0,r=h,h=h.children[0])}return this},r.prototype.toBBox=function(t){return t},r.prototype.compareMinX=function(t,i){return t.minX-i.minX},r.prototype.compareMinY=function(t,i){return t.minY-i.minY},r.prototype.toJSON=function(){return this.data},r.prototype.fromJSON=function(t){return this.data=t,this},r.prototype._all=function(t,i){for(var n=[];t;)t.leaf?i.push.apply(i,t.children):n.push.apply(n,t.children),t=n.pop();return i},r.prototype._build=function(t,i,n,r){var e,h=n-i+1,o=this._maxEntries;if(h<=o)return a(e=p(t.slice(i,n+1)),this.toBBox),e;r||(r=Math.ceil(Math.log(h)/Math.log(o)),o=Math.ceil(h/Math.pow(o,r-1))),(e=p([])).leaf=!1,e.height=r;var s=Math.ceil(h/o),l=s*Math.ceil(Math.sqrt(o));d(t,i,n,l,this.compareMinX);for(var f=i;f<=n;f+=l){var u=Math.min(f+l-1,n);d(t,f,u,s,this.compareMinY);for(var m=f;m<=u;m+=s){var c=Math.min(m+s-1,u);e.children.push(this._build(t,m,c,r-1))}}return a(e,this.toBBox),e},r.prototype._chooseSubtree=function(t,i,n,r){for(;r.push(i),!i.leaf&&r.length-1!==n;){for(var e=1/0,a=1/0,h=void 0,o=0;o<i.children.length;o++){var s=i.children[o],l=f(s),u=(m=t,c=s,(Math.max(c.maxX,m.maxX)-Math.min(c.minX,m.minX))*(Math.max(c.maxY,m.maxY)-Math.min(c.minY,m.minY))-l);u<a?(a=u,e=l<e?l:e,h=s):u===a&&l<e&&(e=l,h=s)}i=h||i.children[0]}var m,c;return i},r.prototype._insert=function(t,i,n){var r=n?t:this.toBBox(t),e=[],a=this._chooseSubtree(r,this.data,i,e);for(a.children.push(t),o(a,r);i>=0&&e[i].children.length>this._maxEntries;)this._split(e,i),i--;this._adjustParentBBoxes(r,e,i)},r.prototype._split=function(t,i){var n=t[i],r=n.children.length,e=this._minEntries;this._chooseSplitAxis(n,e,r);var h=this._chooseSplitIndex(n,e,r),o=p(n.children.splice(h,n.children.length-h));o.height=n.height,o.leaf=n.leaf,a(n,this.toBBox),a(o,this.toBBox),i?t[i-1].children.push(o):this._splitRoot(n,o)},r.prototype._splitRoot=function(t,i){this.data=p([t,i]),this.data.height=t.height+1,this.data.leaf=!1,a(this.data,this.toBBox)},r.prototype._chooseSplitIndex=function(t,i,n){for(var r,e,a,o,s,l,u,m=1/0,c=1/0,p=i;p<=n-i;p++){var d=h(t,0,p,this.toBBox),x=h(t,p,n,this.toBBox),v=(e=d,a=x,o=void 0,s=void 0,l=void 0,u=void 0,o=Math.max(e.minX,a.minX),s=Math.max(e.minY,a.minY),l=Math.min(e.maxX,a.maxX),u=Math.min(e.maxY,a.maxY),Math.max(0,l-o)*Math.max(0,u-s)),M=f(d)+f(x);v<m?(m=v,r=p,c=M<c?M:c):v===m&&M<c&&(c=M,r=p)}return r||n-i},r.prototype._chooseSplitAxis=function(t,i,n){var r=t.leaf?this.compareMinX:s,e=t.leaf?this.compareMinY:l;this._allDistMargin(t,i,n,r)<this._allDistMargin(t,i,n,e)&&t.children.sort(r)},r.prototype._allDistMargin=function(t,i,n,r){t.children.sort(r);for(var e=this.toBBox,a=h(t,0,i,e),s=h(t,n-i,n,e),l=u(a)+u(s),f=i;f<n-i;f++){var m=t.children[f];o(a,t.leaf?e(m):m),l+=u(a)}for(var c=n-i-1;c>=i;c--){var p=t.children[c];
10924o(s,t.leaf?e(p):p),l+=u(s)}return l},r.prototype._adjustParentBBoxes=function(t,i,n){for(var r=n;r>=0;r--)o(i[r],t)},r.prototype._condense=function(t){for(var i=t.length-1,n=void 0;i>=0;i--)0===t[i].children.length?i>0?(n=t[i-1].children).splice(n.indexOf(t[i]),1):this.clear():a(t[i],this.toBBox)},r}); 10925 10926 10927/***/ }) 10928 10929/******/ }); 10930/************************************************************************/ 10931/******/ // The module cache 10932/******/ var __webpack_module_cache__ = {}; 10933/******/ 10934/******/ // The require function 10935/******/ function __webpack_require__(moduleId) { 10936/******/ // Check if module is in cache 10937/******/ var cachedModule = __webpack_module_cache__[moduleId]; 10938/******/ if (cachedModule !== undefined) { 10939/******/ return cachedModule.exports; 10940/******/ } 10941/******/ // Create a new module (and put it into the cache) 10942/******/ var module = __webpack_module_cache__[moduleId] = { 10943/******/ // no module.id needed 10944/******/ // no module.loaded needed 10945/******/ exports: {} 10946/******/ }; 10947/******/ 10948/******/ // Execute the module function 10949/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); 10950/******/ 10951/******/ // Return the exports of the module 10952/******/ return module.exports; 10953/******/ } 10954/******/ 10955/************************************************************************/ 10956/******/ /* webpack/runtime/global */ 10957/******/ (() => { 10958/******/ __webpack_require__.g = (function() { 10959/******/ if (typeof globalThis === 'object') return globalThis; 10960/******/ try { 10961/******/ return this || new Function('return this')(); 10962/******/ } catch (e) { 10963/******/ if (typeof window === 'object') return window; 10964/******/ } 10965/******/ })(); 10966/******/ })(); 10967/******/ 10968/************************************************************************/ 10969var __webpack_exports__ = {}; 10970// This entry need to be wrapped in an IIFE because it need to be in strict mode. 10971(() => { 10972"use strict"; 10973 10974;// CONCATENATED MODULE: ./node_modules/ol/events/Event.js 10975/** 10976 * @module ol/events/Event 10977 */ 10978 10979/** 10980 * @classdesc 10981 * Stripped down implementation of the W3C DOM Level 2 Event interface. 10982 * See https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface. 10983 * 10984 * This implementation only provides `type` and `target` properties, and 10985 * `stopPropagation` and `preventDefault` methods. It is meant as base class 10986 * for higher level events defined in the library, and works with 10987 * {@link module:ol/events/Target~Target}. 10988 */ 10989class BaseEvent { 10990 /** 10991 * @param {string} type Type. 10992 */ 10993 constructor(type) { 10994 /** 10995 * @type {boolean} 10996 */ 10997 this.propagationStopped; 10998 10999 /** 11000 * @type {boolean} 11001 */ 11002 this.defaultPrevented; 11003 11004 /** 11005 * The event type. 11006 * @type {string} 11007 * @api 11008 */ 11009 this.type = type; 11010 11011 /** 11012 * The event target. 11013 * @type {Object} 11014 * @api 11015 */ 11016 this.target = null; 11017 } 11018 11019 /** 11020 * Prevent default. This means that no emulated `click`, `singleclick` or `doubleclick` events 11021 * will be fired. 11022 * @api 11023 */ 11024 preventDefault() { 11025 this.defaultPrevented = true; 11026 } 11027 11028 /** 11029 * Stop event propagation. 11030 * @api 11031 */ 11032 stopPropagation() { 11033 this.propagationStopped = true; 11034 } 11035} 11036 11037/** 11038 * @param {Event|import("./Event.js").default} evt Event 11039 */ 11040function stopPropagation(evt) { 11041 evt.stopPropagation(); 11042} 11043 11044/** 11045 * @param {Event|import("./Event.js").default} evt Event 11046 */ 11047function preventDefault(evt) { 11048 evt.preventDefault(); 11049} 11050 11051/* harmony default export */ const Event = (BaseEvent); 11052 11053;// CONCATENATED MODULE: ./node_modules/ol/ObjectEventType.js 11054/** 11055 * @module ol/ObjectEventType 11056 */ 11057 11058/** 11059 * @enum {string} 11060 */ 11061/* harmony default export */ const ObjectEventType = ({ 11062 /** 11063 * Triggered when a property is changed. 11064 * @event module:ol/Object.ObjectEvent#propertychange 11065 * @api 11066 */ 11067 PROPERTYCHANGE: 'propertychange', 11068}); 11069 11070/** 11071 * @typedef {'propertychange'} Types 11072 */ 11073 11074;// CONCATENATED MODULE: ./node_modules/ol/Disposable.js 11075/** 11076 * @module ol/Disposable 11077 */ 11078 11079/** 11080 * @classdesc 11081 * Objects that need to clean up after themselves. 11082 */ 11083class Disposable { 11084 constructor() { 11085 /** 11086 * The object has already been disposed. 11087 * @type {boolean} 11088 * @protected 11089 */ 11090 this.disposed = false;
11091 } 11092 11093 /** 11094 * Clean up. 11095 */ 11096 dispose() { 11097 if (!this.disposed) { 11098 this.disposed = true; 11099 this.disposeInternal(); 11100 } 11101 } 11102 11103 /** 11104 * Extension point for disposable objects. 11105 * @protected 11106 */ 11107 disposeInternal() {} 11108} 11109 11110/* harmony default export */ const ol_Disposable = (Disposable); 11111 11112;// CONCATENATED MODULE: ./node_modules/ol/array.js 11113/** 11114 * @module ol/array 11115 */ 11116 11117/** 11118 * Performs a binary search on the provided sorted list and returns the index of the item if found. If it can't be found it'll return -1. 11119 * https://github.com/darkskyapp/binary-search 11120 * 11121 * @param {Array<*>} haystack Items to search through. 11122 * @param {*} needle The item to look for. 11123 * @param {Function} [comparator] Comparator function. 11124 * @return {number} The index of the item if found, -1 if not. 11125 */ 11126function binarySearch(haystack, needle, comparator) { 11127 let mid, cmp; 11128 comparator = comparator || numberSafeCompareFunction; 11129 let low = 0; 11130 let high = haystack.length; 11131 let found = false; 11132 11133 while (low < high) { 11134 /* Note that "(low + high) >>> 1" may overflow, and results in a typecast 11135 * to double (which gives the wrong results). */ 11136 mid = low + ((high - low) >> 1); 11137 cmp = +comparator(haystack[mid], needle); 11138 11139 if (cmp < 0.0) { 11140 /* Too low. */ 11141 low = mid + 1; 11142 } else { 11143 /* Key found or too high */ 11144 high = mid; 11145 found = !cmp; 11146 } 11147 } 11148 11149 /* Key not found. */ 11150 return found ? low : ~low; 11151} 11152 11153/** 11154 * Compare function for array sort that is safe for numbers. 11155 * @param {*} a The first object to be compared. 11156 * @param {*} b The second object to be compared. 11157 * @return {number} A negative number, zero, or a positive number as the first 11158 * argument is less than, equal to, or greater than the second. 11159 */ 11160function numberSafeCompareFunction(a, b) { 11161 return a > b ? 1 : a < b ? -1 : 0; 11162} 11163 11164/** 11165 * {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution} can use a function 11166 * of this type to determine which nearest resolution to use. 11167 * 11168 * This function takes a `{number}` representing a value between two array entries, 11169 * a `{number}` representing the value of the nearest higher entry and 11170 * a `{number}` representing the value of the nearest lower entry 11171 * as arguments and returns a `{number}`. If a negative number or zero is returned 11172 * the lower value will be used, if a positive number is returned the higher value 11173 * will be used. 11174 * @typedef {function(number, number, number): number} NearestDirectionFunction 11175 * @api 11176 */ 11177 11178/** 11179 * @param {Array<number>} arr Array in descending order. 11180 * @param {number} target Target. 11181 * @param {number|NearestDirectionFunction} direction 11182 * 0 means return the nearest, 11183 * > 0 means return the largest nearest, 11184 * < 0 means return the smallest nearest. 11185 * @return {number} Index. 11186 */ 11187function linearFindNearest(arr, target, direction) { 11188 const n = arr.length; 11189 if (arr[0] <= target) { 11190 return 0; 11191 } else if (target <= arr[n - 1]) { 11192 return n - 1; 11193 } else { 11194 let i; 11195 if (direction > 0) { 11196 for (i = 1; i < n; ++i) { 11197 if (arr[i] < target) { 11198 return i - 1; 11199 } 11200 } 11201 } else if (direction < 0) { 11202 for (i = 1; i < n; ++i) { 11203 if (arr[i] <= target) { 11204 return i; 11205 } 11206 } 11207 } else { 11208 for (i = 1; i < n; ++i) { 11209 if (arr[i] == target) { 11210 return i; 11211 } else if (arr[i] < target) { 11212 if (typeof direction === 'function') { 11213 if (direction(target, arr[i - 1], arr[i]) > 0) { 11214 return i - 1; 11215 } else { 11216 return i; 11217 } 11218 } else if (arr[i - 1] - target < target - arr[i]) { 11219 return i - 1; 11220 } else { 11221 return i; 11222 } 11223 } 11224 } 11225 } 11226 return n - 1; 11227 } 11228} 11229 11230/** 11231 * @param {Array<*>} arr Array. 11232 * @param {number} begin Begin index. 11233 * @param {number} end End index. 11234 */ 11235function reverseSubArray(arr, begin, end) { 11236 while (begin < end) { 11237 const tmp = arr[begin]; 11238 arr[begin] = arr[end]; 11239 arr[end] = tmp; 11240 ++begin; 11241 --end; 11242 } 11243} 11244 11245/** 11246 * @param {Array<VALUE>} arr The array to modify. 11247 * @param {!Array<VALUE>|VALUE} data The elements or arrays of elements to add to arr. 11248 * @template VALUE 11249 */ 11250function array_extend(arr, data) { 11251 const extension = Array.isArray(data) ? data : [data]; 11252 const length = extension.length; 11253 for (let i = 0; i < length; i++) { 11254 arr[arr.length] = extension[i]; 11255 } 11256} 11257 11258/** 11259 * @param {Array<VALUE>} arr The array to modify. 11260 * @param {VALUE} obj The element to remove. 11261 * @template VALUE 11262 * @return {boolean} If the element was removed. 11263 */ 11264function remove(arr, obj) { 11265 const i = arr.indexOf(obj); 11266 const found = i > -1; 11267 if (found) { 11268 arr.splice(i, 1); 11269 } 11270 return found; 11271} 11272 11273/** 11274 * @param {Array|Uint8ClampedArray} arr1 The first array to compare. 11275 * @param {Array|Uint8ClampedArray} arr2 The second array to compare. 11276 * @return {boolean} Whether the two arrays are equal. 11277 */ 11278function equals(arr1, arr2) { 11279 const len1 = arr1.length; 11280 if (len1 !== arr2.length) { 11281 return false;
11282 } 11283 for (let i = 0; i < len1; i++) { 11284 if (arr1[i] !== arr2[i]) { 11285 return false; 11286 } 11287 } 11288 return true; 11289} 11290 11291/** 11292 * Sort the passed array such that the relative order of equal elements is preserved. 11293 * See https://en.wikipedia.org/wiki/Sorting_algorithm#Stability for details. 11294 * @param {Array<*>} arr The array to sort (modifies original). 11295 * @param {!function(*, *): number} compareFnc Comparison function. 11296 * @api 11297 */ 11298function stableSort(arr, compareFnc) { 11299 const length = arr.length; 11300 const tmp = Array(arr.length); 11301 let i; 11302 for (i = 0; i < length; i++) { 11303 tmp[i] = {index: i, value: arr[i]}; 11304 } 11305 tmp.sort(function (a, b) { 11306 return compareFnc(a.value, b.value) || a.index - b.index; 11307 }); 11308 for (i = 0; i < arr.length; i++) { 11309 arr[i] = tmp[i].value; 11310 } 11311} 11312 11313/** 11314 * @param {Array<*>} arr The array to test. 11315 * @param {Function} [func] Comparison function. 11316 * @param {boolean} [strict] Strictly sorted (default false). 11317 * @return {boolean} Return index. 11318 */ 11319function isSorted(arr, func, strict) { 11320 const compare = func || numberSafeCompareFunction; 11321 return arr.every(function (currentVal, index) { 11322 if (index === 0) { 11323 return true; 11324 } 11325 const res = compare(arr[index - 1], currentVal); 11326 return !(res > 0 || (strict && res === 0)); 11327 }); 11328} 11329 11330;// CONCATENATED MODULE: ./node_modules/ol/functions.js 11331/** 11332 * @module ol/functions 11333 */ 11334 11335 11336 11337/** 11338 * Always returns true. 11339 * @return {boolean} true. 11340 */ 11341function TRUE() { 11342 return true; 11343} 11344 11345/** 11346 * Always returns false. 11347 * @return {boolean} false. 11348 */ 11349function functions_FALSE() { 11350 return false; 11351} 11352 11353/** 11354 * A reusable function, used e.g. as a default for callbacks. 11355 * 11356 * @return {void} Nothing. 11357 */ 11358function VOID() {} 11359 11360/** 11361 * Wrap a function in another function that remembers the last return. If the 11362 * returned function is called twice in a row with the same arguments and the same 11363 * this object, it will return the value from the first call in the second call. 11364 * 11365 * @param {function(...any): ReturnType} fn The function to memoize. 11366 * @return {function(...any): ReturnType} The memoized function. 11367 * @template ReturnType 11368 */ 11369function memoizeOne(fn) { 11370 let called = false; 11371 11372 /** @type {ReturnType} */ 11373 let lastResult; 11374 11375 /** @type {Array<any>} */ 11376 let lastArgs; 11377 11378 let lastThis; 11379 11380 return function () { 11381 const nextArgs = Array.prototype.slice.call(arguments); 11382 if (!called || this !== lastThis || !equals(nextArgs, lastArgs)) { 11383 called = true; 11384 lastThis = this; 11385 lastArgs = nextArgs; 11386 lastResult = fn.apply(this, arguments); 11387 } 11388 return lastResult; 11389 }; 11390} 11391 11392/** 11393 * @template T 11394 * @param {function(): (T | Promise<T>)} getter A function that returns a value or a promise for a value. 11395 * @return {Promise<T>} A promise for the value. 11396 */ 11397function toPromise(getter) { 11398 function promiseGetter() { 11399 let value; 11400 try { 11401 value = getter(); 11402 } catch (err) { 11403 return Promise.reject(err); 11404 } 11405 if (value instanceof Promise) { 11406 return value; 11407 } 11408 return Promise.resolve(value); 11409 } 11410 return promiseGetter(); 11411} 11412 11413;// CONCATENATED MODULE: ./node_modules/ol/obj.js 11414/** 11415 * @module ol/obj 11416 */ 11417 11418/** 11419 * Removes all properties from an object. 11420 * @param {Object} object The object to clear. 11421 */ 11422function clear(object) { 11423 for (const property in object) { 11424 delete object[property]; 11425 } 11426} 11427 11428/** 11429 * Determine if an object has any properties. 11430 * @param {Object} object The object to check. 11431 * @return {boolean} The object is empty. 11432 */ 11433function obj_isEmpty(object) { 11434 let property; 11435 for (property in object) { 11436 return false; 11437 } 11438 return !property; 11439} 11440 11441;// CONCATENATED MODULE: ./node_modules/ol/events/Target.js 11442/** 11443 * @module ol/events/Target 11444 */ 11445 11446 11447 11448 11449 11450/** 11451 * @typedef {EventTarget|Target} EventTargetLike 11452 */ 11453 11454/** 11455 * @classdesc 11456 * A simplified implementation of the W3C DOM Level 2 EventTarget interface. 11457 * See https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget. 11458 * 11459 * There are two important simplifications compared to the specification: 11460 * 11461 * 1. The handling of `useCapture` in `addEventListener` and 11462 * `removeEventListener`. There is no real capture model. 11463 * 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`. 11464 * There is no event target hierarchy. When a listener calls 11465 * `stopPropagation` or `preventDefault` on an event object, it means that no 11466 * more listeners after this one will be called. Same as when the listener 11467 * returns false. 11468 */ 11469class Target extends ol_Disposable { 11470 /** 11471 * @param {*} [target] Default event target for dispatched events. 11472 */ 11473 constructor(target) { 11474 super(); 11475 11476 /** 11477 * @private 11478 * @type {*} 11479 */ 11480 this.eventTarget_ = target; 11481 11482 /** 11483 * @private 11484 * @type {Object<string, number>} 11485 */ 11486 this.pendingRemovals_ = null; 11487 11488 /** 11489 * @private 11490 * @type {Object<string, number>} 11491 */ 11492 this.dispatching_ = null; 11493 11494 /** 11495 * @private 11496 * @type {Object<string, Array<import("../events.js").Listener>>} 11497 */ 11498 this.listeners_ = null; 11499 } 11500 11501 /** 11502 * @param {string} type Type. 11503 * @param {import("../events.js").Listener} listener Listener. 11504 */ 11505 addEventListener(type, listener) { 11506 if (!type || !listener) { 11507 return; 11508 } 11509 const listeners = this.listeners_ || (this.listeners_ = {}); 11510 const listenersForType = listeners[type] || (listeners[type] = []); 11511 if (!listenersForType.includes(listener)) { 11512 listenersForType.push(listener); 11513 } 11514 } 11515 11516 /** 11517 * Dispatches an event and calls all listeners listening for events 11518 * of this type. The event parameter can either be a string or an 11519 * Object with a `type` property. 11520 * 11521 * @param {import("./Event.js").default|string} event Event object. 11522 * @return {boolean|undefined} `false` if anyone called preventDefault on the 11523 * event object or if any of the listeners returned false. 11524 * @api 11525 */ 11526 dispatchEvent(event) { 11527 const isString = typeof event === 'string'; 11528 const type = isString ? event : event.type; 11529 const listeners = this.listeners_ && this.listeners_[type]; 11530 if (!listeners) { 11531 return; 11532 } 11533 11534 const evt = isString ? new Event(event) : /** @type {Event} */ (event); 11535 if (!evt.target) { 11536 evt.target = this.eventTarget_ || this; 11537 } 11538 const dispatching = this.dispatching_ || (this.dispatching_ = {}); 11539 const pendingRemovals = 11540 this.pendingRemovals_ || (this.pendingRemovals_ = {}); 11541 if (!(type in dispatching)) { 11542 dispatching[type] = 0; 11543 pendingRemovals[type] = 0; 11544 } 11545 ++dispatching[type]; 11546 let propagate; 11547 for (let i = 0, ii = listeners.length; i < ii; ++i) { 11548 if ('handleEvent' in listeners[i]) { 11549 propagate = /** @type {import("../events.js").ListenerObject} */ ( 11550 listeners[i] 11551 ).handleEvent(evt); 11552 } else { 11553 propagate = /** @type {import("../events.js").ListenerFunction} */ ( 11554 listeners[i] 11555 ).call(this, evt); 11556 } 11557 if (propagate === false || evt.propagationStopped) { 11558 propagate = false;
11559 break; 11560 } 11561 } 11562 if (--dispatching[type] === 0) { 11563 let pr = pendingRemovals[type]; 11564 delete pendingRemovals[type]; 11565 while (pr--) { 11566 this.removeEventListener(type, VOID); 11567 } 11568 delete dispatching[type]; 11569 } 11570 return propagate; 11571 } 11572 11573 /** 11574 * Clean up. 11575 */ 11576 disposeInternal() { 11577 this.listeners_ && clear(this.listeners_); 11578 } 11579 11580 /** 11581 * Get the listeners for a specified event type. Listeners are returned in the 11582 * order that they will be called in. 11583 * 11584 * @param {string} type Type. 11585 * @return {Array<import("../events.js").Listener>|undefined} Listeners. 11586 */ 11587 getListeners(type) { 11588 return (this.listeners_ && this.listeners_[type]) || undefined; 11589 } 11590 11591 /** 11592 * @param {string} [type] Type. If not provided, 11593 * `true` will be returned if this event target has any listeners. 11594 * @return {boolean} Has listeners. 11595 */ 11596 hasListener(type) { 11597 if (!this.listeners_) { 11598 return false; 11599 } 11600 return type 11601 ? type in this.listeners_ 11602 : Object.keys(this.listeners_).length > 0; 11603 } 11604 11605 /** 11606 * @param {string} type Type. 11607 * @param {import("../events.js").Listener} listener Listener. 11608 */ 11609 removeEventListener(type, listener) { 11610 const listeners = this.listeners_ && this.listeners_[type]; 11611 if (listeners) { 11612 const index = listeners.indexOf(listener); 11613 if (index !== -1) { 11614 if (this.pendingRemovals_ && type in this.pendingRemovals_) { 11615 // make listener a no-op, and remove later in #dispatchEvent() 11616 listeners[index] = VOID; 11617 ++this.pendingRemovals_[type]; 11618 } else { 11619 listeners.splice(index, 1); 11620 if (listeners.length === 0) { 11621 delete this.listeners_[type]; 11622 } 11623 } 11624 } 11625 } 11626 } 11627} 11628 11629/* harmony default export */ const events_Target = (Target); 11630 11631;// CONCATENATED MODULE: ./node_modules/ol/events/EventType.js 11632/** 11633 * @module ol/events/EventType 11634 */ 11635 11636/** 11637 * @enum {string} 11638 * @const 11639 */ 11640/* harmony default export */ const EventType = ({ 11641 /** 11642 * Generic change event. Triggered when the revision counter is increased. 11643 * @event module:ol/events/Event~BaseEvent#change 11644 * @api 11645 */ 11646 CHANGE: 'change', 11647 11648 /** 11649 * Generic error event. Triggered when an error occurs. 11650 * @event module:ol/events/Event~BaseEvent#error 11651 * @api 11652 */ 11653 ERROR: 'error', 11654 11655 BLUR: 'blur', 11656 CLEAR: 'clear', 11657 CONTEXTMENU: 'contextmenu', 11658 CLICK: 'click', 11659 DBLCLICK: 'dblclick', 11660 DRAGENTER: 'dragenter', 11661 DRAGOVER: 'dragover', 11662 DROP: 'drop', 11663 FOCUS: 'focus', 11664 KEYDOWN: 'keydown', 11665 KEYPRESS: 'keypress', 11666 LOAD: 'load', 11667 RESIZE: 'resize', 11668 TOUCHMOVE: 'touchmove', 11669 WHEEL: 'wheel', 11670}); 11671 11672;// CONCATENATED MODULE: ./node_modules/ol/events.js 11673/** 11674 * @module ol/events 11675 */ 11676 11677 11678/** 11679 * Key to use with {@link module:ol/Observable.unByKey}. 11680 * @typedef {Object} EventsKey 11681 * @property {ListenerFunction} listener Listener. 11682 * @property {import("./events/Target.js").EventTargetLike} target Target. 11683 * @property {string} type Type. 11684 * @api 11685 */ 11686 11687/** 11688 * Listener function. This function is called with an event object as argument. 11689 * When the function returns `false`, event propagation will stop. 11690 * 11691 * @typedef {function((Event|import("./events/Event.js").default)): (void|boolean)} ListenerFunction 11692 * @api 11693 */ 11694 11695/** 11696 * @typedef {Object} ListenerObject 11697 * @property {ListenerFunction} handleEvent HandleEvent listener function. 11698 */ 11699 11700/** 11701 * @typedef {ListenerFunction|ListenerObject} Listener 11702 */ 11703 11704/** 11705 * Registers an event listener on an event target. Inspired by 11706 * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html 11707 * 11708 * This function efficiently binds a `listener` to a `this` object, and returns 11709 * a key for use with {@link module:ol/events.unlistenByKey}. 11710 * 11711 * @param {import("./events/Target.js").EventTargetLike} target Event target. 11712 * @param {string} type Event type. 11713 * @param {ListenerFunction} listener Listener. 11714 * @param {Object} [thisArg] Object referenced by the `this` keyword in the 11715 * listener. Default is the `target`. 11716 * @param {boolean} [once] If true, add the listener as one-off listener. 11717 * @return {EventsKey} Unique key for the listener. 11718 */ 11719function listen(target, type, listener, thisArg, once) { 11720 if (thisArg && thisArg !== target) { 11721 listener = listener.bind(thisArg); 11722 } 11723 if (once) { 11724 const originalListener = listener; 11725 listener = function () { 11726 target.removeEventListener(type, listener); 11727 originalListener.apply(this, arguments); 11728 }; 11729 } 11730 const eventsKey = { 11731 target: target, 11732 type: type, 11733 listener: listener, 11734 }; 11735 target.addEventListener(type, listener); 11736 return eventsKey; 11737} 11738 11739/** 11740 * Registers a one-off event listener on an event target. Inspired by 11741 * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html 11742 *
11743 * This function efficiently binds a `listener` as self-unregistering listener 11744 * to a `this` object, and returns a key for use with 11745 * {@link module:ol/events.unlistenByKey} in case the listener needs to be 11746 * unregistered before it is called. 11747 * 11748 * When {@link module:ol/events.listen} is called with the same arguments after this 11749 * function, the self-unregistering listener will be turned into a permanent 11750 * listener. 11751 * 11752 * @param {import("./events/Target.js").EventTargetLike} target Event target. 11753 * @param {string} type Event type. 11754 * @param {ListenerFunction} listener Listener. 11755 * @param {Object} [thisArg] Object referenced by the `this` keyword in the 11756 * listener. Default is the `target`. 11757 * @return {EventsKey} Key for unlistenByKey. 11758 */ 11759function listenOnce(target, type, listener, thisArg) { 11760 return listen(target, type, listener, thisArg, true); 11761} 11762 11763/** 11764 * Unregisters event listeners on an event target. Inspired by 11765 * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html 11766 * 11767 * The argument passed to this function is the key returned from 11768 * {@link module:ol/events.listen} or {@link module:ol/events.listenOnce}. 11769 * 11770 * @param {EventsKey} key The key. 11771 */ 11772function unlistenByKey(key) { 11773 if (key && key.target) { 11774 key.target.removeEventListener(key.type, key.listener); 11775 clear(key); 11776 } 11777} 11778 11779;// CONCATENATED MODULE: ./node_modules/ol/Observable.js 11780/** 11781 * @module ol/Observable 11782 */ 11783 11784 11785 11786 11787/*** 11788 * @template {string} Type 11789 * @template {Event|import("./events/Event.js").default} EventClass 11790 * @template Return 11791 * @typedef {(type: Type, listener: (event: EventClass) => ?) => Return} OnSignature 11792 */ 11793 11794/*** 11795 * @template {string} Type 11796 * @template Return 11797 * @typedef {(type: Type[], listener: (event: Event|import("./events/Event").default) => ?) => Return extends void ? void : Return[]} CombinedOnSignature 11798 */ 11799 11800/** 11801 * @typedef {'change'|'error'} EventTypes 11802 */ 11803 11804/*** 11805 * @template Return 11806 * @typedef {OnSignature<EventTypes, import("./events/Event.js").default, Return> & CombinedOnSignature<EventTypes, Return>} ObservableOnSignature 11807 */ 11808 11809/** 11810 * @classdesc 11811 * Abstract base class; normally only used for creating subclasses and not 11812 * instantiated in apps. 11813 * An event target providing convenient methods for listener registration 11814 * and unregistration. A generic `change` event is always available through 11815 * {@link module:ol/Observable~Observable#changed}. 11816 * 11817 * @fires import("./events/Event.js").default 11818 * @api 11819 */ 11820class Observable extends events_Target { 11821 constructor() { 11822 super(); 11823 11824 this.on = 11825 /** @type {ObservableOnSignature<import("./events").EventsKey>} */ ( 11826 this.onInternal 11827 ); 11828 11829 this.once = 11830 /** @type {ObservableOnSignature<import("./events").EventsKey>} */ ( 11831 this.onceInternal 11832 ); 11833 11834 this.un = /** @type {ObservableOnSignature<void>} */ (this.unInternal); 11835 11836 /** 11837 * @private 11838 * @type {number} 11839 */ 11840 this.revision_ = 0; 11841 } 11842 11843 /** 11844 * Increases the revision counter and dispatches a 'change' event. 11845 * @api 11846 */ 11847 changed() { 11848 ++this.revision_; 11849 this.dispatchEvent(EventType.CHANGE); 11850 } 11851 11852 /** 11853 * Get the version number for this object. Each time the object is modified, 11854 * its version number will be incremented. 11855 * @return {number} Revision. 11856 * @api 11857 */ 11858 getRevision() { 11859 return this.revision_; 11860 } 11861 11862 /** 11863 * @param {string|Array<string>} type Type. 11864 * @param {function((Event|import("./events/Event").default)): ?} listener Listener. 11865 * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key. 11866 * @protected 11867 */ 11868 onInternal(type, listener) { 11869 if (Array.isArray(type)) { 11870 const len = type.length; 11871 const keys = new Array(len); 11872 for (let i = 0; i < len; ++i) { 11873 keys[i] = listen(this, type[i], listener); 11874 } 11875 return keys; 11876 } else { 11877 return listen(this, /** @type {string} */ (type), listener); 11878 } 11879 } 11880 11881 /** 11882 * @param {string|Array<string>} type Type. 11883 * @param {function((Event|import("./events/Event").default)): ?} listener Listener. 11884 * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key. 11885 * @protected 11886 */ 11887 onceInternal(type, listener) { 11888 let key; 11889 if (Array.isArray(type)) { 11890 const len = type.length; 11891 key = new Array(len); 11892 for (let i = 0; i < len; ++i) { 11893 key[i] = listenOnce(this, type[i], listener); 11894 } 11895 } else { 11896 key = listenOnce(this, /** @type {string} */ (type), listener); 11897 } 11898 /** @type {Object} */ (listener).ol_key = key; 11899 return key; 11900 } 11901 11902 /** 11903 * Unlisten for a certain type of event. 11904 * @param {string|Array<string>} type Type. 11905 * @param {function((Event|import("./events/Event").default)): ?} listener Listener. 11906 * @protected 11907 */ 11908 unInternal(type, listener) {
11909 const key = /** @type {Object} */ (listener).ol_key; 11910 if (key) { 11911 unByKey(key); 11912 } else if (Array.isArray(type)) { 11913 for (let i = 0, ii = type.length; i < ii; ++i) { 11914 this.removeEventListener(type[i], listener); 11915 } 11916 } else { 11917 this.removeEventListener(type, listener); 11918 } 11919 } 11920} 11921 11922/** 11923 * Listen for a certain type of event. 11924 * @function 11925 * @param {string|Array<string>} type The event type or array of event types. 11926 * @param {function((Event|import("./events/Event").default)): ?} listener The listener function. 11927 * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Unique key for the listener. If 11928 * called with an array of event types as the first argument, the return 11929 * will be an array of keys. 11930 * @api 11931 */ 11932Observable.prototype.on; 11933 11934/** 11935 * Listen once for a certain type of event. 11936 * @function 11937 * @param {string|Array<string>} type The event type or array of event types. 11938 * @param {function((Event|import("./events/Event").default)): ?} listener The listener function. 11939 * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Unique key for the listener. If 11940 * called with an array of event types as the first argument, the return 11941 * will be an array of keys. 11942 * @api 11943 */ 11944Observable.prototype.once; 11945 11946/** 11947 * Unlisten for a certain type of event. 11948 * @function 11949 * @param {string|Array<string>} type The event type or array of event types. 11950 * @param {function((Event|import("./events/Event").default)): ?} listener The listener function. 11951 * @api 11952 */ 11953Observable.prototype.un; 11954 11955/** 11956 * Removes an event listener using the key returned by `on()` or `once()`. 11957 * @param {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} key The key returned by `on()` 11958 * or `once()` (or an array of keys). 11959 * @api 11960 */ 11961function unByKey(key) { 11962 if (Array.isArray(key)) { 11963 for (let i = 0, ii = key.length; i < ii; ++i) { 11964 unlistenByKey(key[i]); 11965 } 11966 } else { 11967 unlistenByKey(/** @type {import("./events.js").EventsKey} */ (key)); 11968 } 11969} 11970 11971/* harmony default export */ const ol_Observable = (Observable); 11972 11973;// CONCATENATED MODULE: ./node_modules/ol/util.js 11974/** 11975 * @module ol/util 11976 */ 11977 11978/** 11979 * @return {never} Any return. 11980 */ 11981function util_abstract() { 11982 throw new Error('Unimplemented abstract method.'); 11983} 11984 11985/** 11986 * Counter for getUid. 11987 * @type {number} 11988 * @private 11989 */ 11990let uidCounter_ = 0; 11991 11992/** 11993 * Gets a unique ID for an object. This mutates the object so that further calls 11994 * with the same object as a parameter returns the same value. Unique IDs are generated 11995 * as a strictly increasing sequence. Adapted from goog.getUid. 11996 * 11997 * @param {Object} obj The object to get the unique ID for. 11998 * @return {string} The unique ID for the object. 11999 * @api 12000 */ 12001function getUid(obj) { 12002 return obj.ol_uid || (obj.ol_uid = String(++uidCounter_)); 12003} 12004 12005/** 12006 * OpenLayers version. 12007 * @type {string} 12008 */ 12009const VERSION = '7.0.0'; 12010 12011;// CONCATENATED MODULE: ./node_modules/ol/Object.js 12012/** 12013 * @module ol/Object 12014 */ 12015 12016 12017 12018 12019 12020 12021/** 12022 * @classdesc 12023 * Events emitted by {@link module:ol/Object~BaseObject} instances are instances of this type. 12024 */ 12025class ObjectEvent extends Event { 12026 /** 12027 * @param {string} type The event type. 12028 * @param {string} key The property name. 12029 * @param {*} oldValue The old value for `key`. 12030 */ 12031 constructor(type, key, oldValue) { 12032 super(type); 12033 12034 /** 12035 * The name of the property whose value is changing. 12036 * @type {string} 12037 * @api 12038 */ 12039 this.key = key; 12040 12041 /** 12042 * The old value. To get the new value use `e.target.get(e.key)` where 12043 * `e` is the event object. 12044 * @type {*} 12045 * @api 12046 */ 12047 this.oldValue = oldValue; 12048 } 12049} 12050 12051/*** 12052 * @template Return 12053 * @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> & 12054 * import("./Observable").OnSignature<import("./ObjectEventType").Types, ObjectEvent, Return> & 12055 * import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|import("./ObjectEventType").Types, Return>} ObjectOnSignature 12056 */ 12057 12058/** 12059 * @classdesc 12060 * Abstract base class; normally only used for creating subclasses and not 12061 * instantiated in apps. 12062 * Most non-trivial classes inherit from this. 12063 * 12064 * This extends {@link module:ol/Observable~Observable} with observable 12065 * properties, where each property is observable as well as the object as a 12066 * whole. 12067 * 12068 * Classes that inherit from this have pre-defined properties, to which you can 12069 * add your owns. The pre-defined properties are listed in this documentation as 12070 * 'Observable Properties', and have their own accessors; for example, 12071 * {@link module:ol/Map~Map} has a `target` property, accessed with 12072 * `getTarget()` and changed with `setTarget()`. Not all properties are however 12073 * settable. There are also general-purpose accessors `get()` and `set()`. For 12074 * example, `get('target')` is equivalent to `getTarget()`. 12075 * 12076 * The `set` accessors trigger a change event, and you can monitor this by 12077 * registering a listener. For example, {@link module:ol/View~View} has a 12078 * `center` property, so `view.on('change:center', function(evt) {...});` would 12079 * call the function whenever the value of the center property changes. Within 12080 * the function, `evt.target` would be the view, so `evt.target.getCenter()` 12081 * would return the new center. 12082 * 12083 * You can add your own observable properties with 12084 * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`. 12085 * You can listen for changes on that property value with 12086 * `object.on('change:prop', listener)`. You can get a list of all 12087 * properties with {@link module:ol/Object~BaseObject#getProperties}. 12088 *
12089 * Note that the observable properties are separate from standard JS properties. 12090 * You can, for example, give your map object a title with 12091 * `map.title='New title'` and with `map.set('title', 'Another title')`. The 12092 * first will be a `hasOwnProperty`; the second will appear in 12093 * `getProperties()`. Only the second is observable. 12094 * 12095 * Properties can be deleted by using the unset method. E.g. 12096 * object.unset('foo'). 12097 * 12098 * @fires ObjectEvent 12099 * @api 12100 */ 12101class BaseObject extends ol_Observable { 12102 /** 12103 * @param {Object<string, *>} [values] An object with key-value pairs. 12104 */ 12105 constructor(values) { 12106 super(); 12107 12108 /*** 12109 * @type {ObjectOnSignature<import("./events").EventsKey>} 12110 */ 12111 this.on; 12112 12113 /*** 12114 * @type {ObjectOnSignature<import("./events").EventsKey>} 12115 */ 12116 this.once; 12117 12118 /*** 12119 * @type {ObjectOnSignature<void>} 12120 */ 12121 this.un; 12122 12123 // Call {@link module:ol/util.getUid} to ensure that the order of objects' ids is 12124 // the same as the order in which they were created. This also helps to 12125 // ensure that object properties are always added in the same order, which 12126 // helps many JavaScript engines generate faster code. 12127 getUid(this); 12128 12129 /** 12130 * @private 12131 * @type {Object<string, *>} 12132 */ 12133 this.values_ = null; 12134 12135 if (values !== undefined) { 12136 this.setProperties(values); 12137 } 12138 } 12139 12140 /** 12141 * Gets a value. 12142 * @param {string} key Key name. 12143 * @return {*} Value. 12144 * @api 12145 */ 12146 get(key) { 12147 let value; 12148 if (this.values_ && this.values_.hasOwnProperty(key)) { 12149 value = this.values_[key]; 12150 } 12151 return value; 12152 } 12153 12154 /** 12155 * Get a list of object property names. 12156 * @return {Array<string>} List of property names. 12157 * @api 12158 */ 12159 getKeys() { 12160 return (this.values_ && Object.keys(this.values_)) || []; 12161 } 12162 12163 /** 12164 * Get an object of all property names and values. 12165 * @return {Object<string, *>} Object. 12166 * @api 12167 */ 12168 getProperties() { 12169 return (this.values_ && Object.assign({}, this.values_)) || {}; 12170 } 12171 12172 /** 12173 * @return {boolean} The object has properties. 12174 */ 12175 hasProperties() { 12176 return !!this.values_; 12177 } 12178 12179 /** 12180 * @param {string} key Key name. 12181 * @param {*} oldValue Old value. 12182 */ 12183 notify(key, oldValue) { 12184 let eventType; 12185 eventType = `change:${key}`; 12186 if (this.hasListener(eventType)) { 12187 this.dispatchEvent(new ObjectEvent(eventType, key, oldValue)); 12188 } 12189 eventType = ObjectEventType.PROPERTYCHANGE; 12190 if (this.hasListener(eventType)) { 12191 this.dispatchEvent(new ObjectEvent(eventType, key, oldValue)); 12192 } 12193 } 12194 12195 /** 12196 * @param {string} key Key name. 12197 * @param {import("./events.js").Listener} listener Listener. 12198 */ 12199 addChangeListener(key, listener) { 12200 this.addEventListener(`change:${key}`, listener); 12201 } 12202 12203 /** 12204 * @param {string} key Key name. 12205 * @param {import("./events.js").Listener} listener Listener. 12206 */ 12207 removeChangeListener(key, listener) { 12208 this.removeEventListener(`change:${key}`, listener); 12209 } 12210 12211 /** 12212 * Sets a value. 12213 * @param {string} key Key name. 12214 * @param {*} value Value. 12215 * @param {boolean} [silent] Update without triggering an event. 12216 * @api 12217 */ 12218 set(key, value, silent) { 12219 const values = this.values_ || (this.values_ = {}); 12220 if (silent) { 12221 values[key] = value; 12222 } else { 12223 const oldValue = values[key]; 12224 values[key] = value; 12225 if (oldValue !== value) { 12226 this.notify(key, oldValue); 12227 } 12228 } 12229 } 12230 12231 /** 12232 * Sets a collection of key-value pairs. Note that this changes any existing 12233 * properties and adds new ones (it does not remove any existing properties). 12234 * @param {Object<string, *>} values Values. 12235 * @param {boolean} [silent] Update without triggering an event. 12236 * @api 12237 */ 12238 setProperties(values, silent) { 12239 for (const key in values) { 12240 this.set(key, values[key], silent); 12241 } 12242 } 12243 12244 /** 12245 * Apply any properties from another object without triggering events. 12246 * @param {BaseObject} source The source object. 12247 * @protected 12248 */ 12249 applyProperties(source) { 12250 if (!source.values_) { 12251 return; 12252 } 12253 Object.assign(this.values_ || (this.values_ = {}), source.values_); 12254 } 12255 12256 /** 12257 * Unsets a property. 12258 * @param {string} key Key name. 12259 * @param {boolean} [silent] Unset without triggering an event. 12260 * @api 12261 */ 12262 unset(key, silent) { 12263 if (this.values_ && key in this.values_) { 12264 const oldValue = this.values_[key]; 12265 delete this.values_[key]; 12266 if (obj_isEmpty(this.values_)) { 12267 this.values_ = null; 12268 } 12269 if (!silent) { 12270 this.notify(key, oldValue); 12271 } 12272 } 12273 } 12274} 12275 12276/* harmony default export */ const ol_Object = (BaseObject); 12277 12278;// CONCATENATED MODULE: ./node_modules/ol/AssertionError.js 12279/** 12280 * @module ol/AssertionError 12281 */ 12282 12283 12284/** 12285 * Error object thrown when an assertion failed. This is an ECMA-262 Error, 12286 * extended with a `code` property. 12287 * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error. 12288 */
12289class AssertionError extends Error { 12290 /** 12291 * @param {number} code Error code. 12292 */ 12293 constructor(code) { 12294 const path = VERSION === 'latest' ? VERSION : 'v' + VERSION.split('-')[0]; 12295 const message = 12296 'Assertion failed. See https://openlayers.org/en/' + 12297 path + 12298 '/doc/errors/#' + 12299 code + 12300 ' for details.'; 12301 12302 super(message); 12303 12304 /** 12305 * Error code. The meaning of the code can be found on 12306 * https://openlayers.org/en/latest/doc/errors/ (replace `latest` with 12307 * the version found in the OpenLayers script's header comment if a version 12308 * other than the latest is used). 12309 * @type {number} 12310 * @api 12311 */ 12312 this.code = code; 12313 12314 /** 12315 * @type {string} 12316 */ 12317 this.name = 'AssertionError'; 12318 12319 // Re-assign message, see https://github.com/Rich-Harris/buble/issues/40 12320 this.message = message; 12321 } 12322} 12323 12324/* harmony default export */ const ol_AssertionError = (AssertionError); 12325 12326;// CONCATENATED MODULE: ./node_modules/ol/asserts.js 12327/** 12328 * @module ol/asserts 12329 */ 12330 12331 12332/** 12333 * @param {*} assertion Assertion we expected to be truthy. 12334 * @param {number} errorCode Error code. 12335 */ 12336function asserts_assert(assertion, errorCode) { 12337 if (!assertion) { 12338 throw new ol_AssertionError(errorCode); 12339 } 12340} 12341 12342;// CONCATENATED MODULE: ./node_modules/ol/Feature.js 12343/** 12344 * @module ol/Feature 12345 */ 12346 12347 12348 12349 12350 12351/** 12352 * @typedef {typeof Feature|typeof import("./render/Feature.js").default} FeatureClass 12353 */ 12354 12355/** 12356 * @typedef {Feature|import("./render/Feature.js").default} FeatureLike 12357 */ 12358 12359/*** 12360 * @template Return 12361 * @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> & 12362 * import("./Observable").OnSignature<import("./ObjectEventType").Types|'change:geometry', import("./Object").ObjectEvent, Return> & 12363 * import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|import("./ObjectEventType").Types 12364 * |'change:geometry', Return>} FeatureOnSignature 12365 */ 12366 12367/*** 12368 * @template Geometry 12369 * @typedef {Object<string, *> & { geometry?: Geometry }} ObjectWithGeometry 12370 */ 12371 12372/** 12373 * @classdesc 12374 * A vector object for geographic features with a geometry and other 12375 * attribute properties, similar to the features in vector file formats like 12376 * GeoJSON. 12377 * 12378 * Features can be styled individually with `setStyle`; otherwise they use the 12379 * style of their vector layer. 12380 * 12381 * Note that attribute properties are set as {@link module:ol/Object~BaseObject} properties on 12382 * the feature object, so they are observable, and have get/set accessors. 12383 * 12384 * Typically, a feature has a single geometry property. You can set the 12385 * geometry using the `setGeometry` method and get it with `getGeometry`. 12386 * It is possible to store more than one geometry on a feature using attribute 12387 * properties. By default, the geometry used for rendering is identified by 12388 * the property name `geometry`. If you want to use another geometry property 12389 * for rendering, use the `setGeometryName` method to change the attribute 12390 * property associated with the geometry for the feature. For example: 12391 * 12392 * ```js 12393 * 12394 * import Feature from 'ol/Feature'; 12395 * import Polygon from 'ol/geom/Polygon'; 12396 * import Point from 'ol/geom/Point'; 12397 * 12398 * const feature = new Feature({ 12399 * geometry: new Polygon(polyCoords), 12400 * labelPoint: new Point(labelCoords), 12401 * name: 'My Polygon', 12402 * }); 12403 * 12404 * // get the polygon geometry 12405 * const poly = feature.getGeometry(); 12406 * 12407 * // Render the feature as a point using the coordinates from labelPoint 12408 * feature.setGeometryName('labelPoint'); 12409 * 12410 * // get the point geometry 12411 * const point = feature.getGeometry(); 12412 * ``` 12413 * 12414 * @api 12415 * @template {import("./geom/Geometry.js").default} [Geometry=import("./geom/Geometry.js").default] 12416 */ 12417class Feature extends ol_Object { 12418 /** 12419 * @param {Geometry|ObjectWithGeometry<Geometry>} [geometryOrProperties] 12420 * You may pass a Geometry object directly, or an object literal containing 12421 * properties. If you pass an object literal, you may include a Geometry 12422 * associated with a `geometry` key. 12423 */ 12424 constructor(geometryOrProperties) { 12425 super(); 12426 12427 /*** 12428 * @type {FeatureOnSignature<import("./events").EventsKey>} 12429 */ 12430 this.on; 12431 12432 /*** 12433 * @type {FeatureOnSignature<import("./events").EventsKey>} 12434 */ 12435 this.once; 12436 12437 /*** 12438 * @type {FeatureOnSignature<void>} 12439 */ 12440 this.un; 12441 12442 /** 12443 * @private 12444 * @type {number|string|undefined} 12445 */ 12446 this.id_ = undefined; 12447 12448 /** 12449 * @type {string} 12450 * @private 12451 */ 12452 this.geometryName_ = 'geometry'; 12453 12454 /** 12455 * User provided style. 12456 * @private 12457 * @type {import("./style/Style.js").StyleLike} 12458 */ 12459 this.style_ = null; 12460 12461 /** 12462 * @private 12463 * @type {import("./style/Style.js").StyleFunction|undefined} 12464 */ 12465 this.styleFunction_ = undefined; 12466 12467 /** 12468 * @private 12469 * @type {?import("./events.js").EventsKey} 12470 */ 12471 this.geometryChangeKey_ = null; 12472 12473 this.addChangeListener(this.geometryName_, this.handleGeometryChanged_); 12474 12475 if (geometryOrProperties) { 12476 if ( 12477 typeof ( 12478 /** @type {?} */ (geometryOrProperties).getSimplifiedGeometry 12479 ) === 'function' 12480 ) { 12481 const geometry = /** @type {Geometry} */ (geometryOrProperties); 12482 this.setGeometry(geometry); 12483 } else { 12484 /** @type {Object<string, *>} */ 12485 const properties = geometryOrProperties; 12486 this.setProperties(properties); 12487 } 12488 } 12489 } 12490 12491 /** 12492 * Clone this feature. If the original feature has a geometry it 12493 * is also cloned. The feature id is not set in the clone. 12494 * @return {Feature<Geometry>} The clone. 12495 * @api 12496 */ 12497 clone() { 12498 const clone = /** @type {Feature<Geometry>} */ ( 12499 new Feature(this.hasProperties() ? this.getProperties() : null) 12500 ); 12501 clone.setGeometryName(this.getGeometryName()); 12502 const geometry = this.getGeometry(); 12503 if (geometry) { 12504 clone.setGeometry(/** @type {Geometry} */ (geometry.clone())); 12505 }
12506 const style = this.getStyle(); 12507 if (style) { 12508 clone.setStyle(style); 12509 } 12510 return clone; 12511 } 12512 12513 /** 12514 * Get the feature's default geometry. A feature may have any number of named 12515 * geometries. The "default" geometry (the one that is rendered by default) is 12516 * set when calling {@link module:ol/Feature~Feature#setGeometry}. 12517 * @return {Geometry|undefined} The default geometry for the feature. 12518 * @api 12519 * @observable 12520 */ 12521 getGeometry() { 12522 return /** @type {Geometry|undefined} */ (this.get(this.geometryName_)); 12523 } 12524 12525 /** 12526 * Get the feature identifier. This is a stable identifier for the feature and 12527 * is either set when reading data from a remote source or set explicitly by 12528 * calling {@link module:ol/Feature~Feature#setId}. 12529 * @return {number|string|undefined} Id. 12530 * @api 12531 */ 12532 getId() { 12533 return this.id_; 12534 } 12535 12536 /** 12537 * Get the name of the feature's default geometry. By default, the default 12538 * geometry is named `geometry`. 12539 * @return {string} Get the property name associated with the default geometry 12540 * for this feature. 12541 * @api 12542 */ 12543 getGeometryName() { 12544 return this.geometryName_; 12545 } 12546 12547 /** 12548 * Get the feature's style. Will return what was provided to the 12549 * {@link module:ol/Feature~Feature#setStyle} method. 12550 * @return {import("./style/Style.js").StyleLike|undefined} The feature style. 12551 * @api 12552 */ 12553 getStyle() { 12554 return this.style_; 12555 } 12556 12557 /** 12558 * Get the feature's style function. 12559 * @return {import("./style/Style.js").StyleFunction|undefined} Return a function 12560 * representing the current style of this feature. 12561 * @api 12562 */ 12563 getStyleFunction() { 12564 return this.styleFunction_; 12565 } 12566 12567 /** 12568 * @private 12569 */ 12570 handleGeometryChange_() { 12571 this.changed(); 12572 } 12573 12574 /** 12575 * @private 12576 */ 12577 handleGeometryChanged_() { 12578 if (this.geometryChangeKey_) { 12579 unlistenByKey(this.geometryChangeKey_); 12580 this.geometryChangeKey_ = null; 12581 } 12582 const geometry = this.getGeometry(); 12583 if (geometry) { 12584 this.geometryChangeKey_ = listen( 12585 geometry, 12586 EventType.CHANGE, 12587 this.handleGeometryChange_, 12588 this 12589 ); 12590 } 12591 this.changed(); 12592 } 12593 12594 /** 12595 * Set the default geometry for the feature. This will update the property 12596 * with the name returned by {@link module:ol/Feature~Feature#getGeometryName}. 12597 * @param {Geometry|undefined} geometry The new geometry. 12598 * @api 12599 * @observable 12600 */ 12601 setGeometry(geometry) { 12602 this.set(this.geometryName_, geometry); 12603 } 12604 12605 /** 12606 * Set the style for the feature to override the layer style. This can be a 12607 * single style object, an array of styles, or a function that takes a 12608 * resolution and returns an array of styles. To unset the feature style, call 12609 * `setStyle()` without arguments or a falsey value. 12610 * @param {import("./style/Style.js").StyleLike} [style] Style for this feature. 12611 * @api 12612 * @fires module:ol/events/Event~BaseEvent#event:change 12613 */ 12614 setStyle(style) { 12615 this.style_ = style; 12616 this.styleFunction_ = !style ? undefined : createStyleFunction(style); 12617 this.changed(); 12618 } 12619 12620 /** 12621 * Set the feature id. The feature id is considered stable and may be used when 12622 * requesting features or comparing identifiers returned from a remote source. 12623 * The feature id can be used with the 12624 * {@link module:ol/source/Vector~VectorSource#getFeatureById} method. 12625 * @param {number|string|undefined} id The feature id. 12626 * @api 12627 * @fires module:ol/events/Event~BaseEvent#event:change 12628 */ 12629 setId(id) { 12630 this.id_ = id; 12631 this.changed(); 12632 } 12633 12634 /** 12635 * Set the property name to be used when getting the feature's default geometry. 12636 * When calling {@link module:ol/Feature~Feature#getGeometry}, the value of the property with 12637 * this name will be returned. 12638 * @param {string} name The property name of the default geometry. 12639 * @api 12640 */ 12641 setGeometryName(name) { 12642 this.removeChangeListener(this.geometryName_, this.handleGeometryChanged_); 12643 this.geometryName_ = name; 12644 this.addChangeListener(this.geometryName_, this.handleGeometryChanged_); 12645 this.handleGeometryChanged_(); 12646 } 12647} 12648 12649/** 12650 * Convert the provided object into a feature style function. Functions passed 12651 * through unchanged. Arrays of Style or single style objects wrapped 12652 * in a new feature style function. 12653 * @param {!import("./style/Style.js").StyleFunction|!Array<import("./style/Style.js").default>|!import("./style/Style.js").default} obj 12654 * A feature style function, a single style, or an array of styles. 12655 * @return {import("./style/Style.js").StyleFunction} A style function. 12656 */ 12657function createStyleFunction(obj) { 12658 if (typeof obj === 'function') { 12659 return obj; 12660 } else { 12661 /** 12662 * @type {Array<import("./style/Style.js").default>} 12663 */ 12664 let styles; 12665 if (Array.isArray(obj)) { 12666 styles = obj; 12667 } else { 12668 asserts_assert(typeof (/** @type {?} */ (obj).getZIndex) === 'function', 41); // Expected an `import("./style/Style.js").Style` or an array of `import("./style/Style.js").Style` 12669 const style = /** @type {import("./style/Style.js").default} */ (obj); 12670 styles = [style]; 12671 } 12672 return function () { 12673 return styles; 12674 }; 12675 } 12676} 12677/* harmony default export */ const ol_Feature = (Feature); 12678 12679;// CONCATENATED MODULE: ./node_modules/ol/ViewHint.js 12680/** 12681 * @module ol/ViewHint 12682 */ 12683 12684/** 12685 * @enum {number} 12686 */ 12687/* harmony default export */ const ViewHint = ({ 12688 ANIMATING: 0, 12689 INTERACTING: 1, 12690}); 12691 12692;// CONCATENATED MODULE: ./node_modules/ol/ViewProperty.js 12693/** 12694 * @module ol/ViewProperty 12695 */ 12696
12697/** 12698 * @enum {string} 12699 */ 12700/* harmony default export */ const ViewProperty = ({ 12701 CENTER: 'center', 12702 RESOLUTION: 'resolution', 12703 ROTATION: 'rotation', 12704}); 12705 12706;// CONCATENATED MODULE: ./node_modules/ol/tilegrid/common.js 12707/** 12708 * @module ol/tilegrid/common 12709 */ 12710 12711/** 12712 * Default maximum zoom for default tile grids. 12713 * @type {number} 12714 */ 12715const DEFAULT_MAX_ZOOM = 42; 12716 12717/** 12718 * Default tile size. 12719 * @type {number} 12720 */ 12721const DEFAULT_TILE_SIZE = 256; 12722 12723;// CONCATENATED MODULE: ./node_modules/ol/proj/Units.js 12724/** 12725 * @module ol/proj/Units 12726 */ 12727 12728/** 12729 * @typedef {'radians' | 'degrees' | 'ft' | 'm' | 'pixels' | 'tile-pixels' | 'us-ft'} Units 12730 * Projection units. 12731 */ 12732 12733/** 12734 * See http://duff.ess.washington.edu/data/raster/drg/docs/geotiff.txt 12735 * @type {Object<number, Units>} 12736 */ 12737const unitByCode = { 12738 '9001': 'm', 12739 '9002': 'ft', 12740 '9003': 'us-ft', 12741 '9101': 'radians', 12742 '9102': 'degrees', 12743}; 12744 12745/** 12746 * @param {number} code Unit code. 12747 * @return {Units} Units. 12748 */ 12749function fromCode(code) { 12750 return unitByCode[code]; 12751} 12752 12753/** 12754 * @typedef {Object} MetersPerUnitLookup 12755 * @property {number} radians Radians 12756 * @property {number} degrees Degrees 12757 * @property {number} ft Feet 12758 * @property {number} m Meters 12759 * @property {number} us-ft US feet 12760 */ 12761 12762/** 12763 * Meters per unit lookup table. 12764 * @const 12765 * @type {MetersPerUnitLookup} 12766 * @api 12767 */ 12768const Units_METERS_PER_UNIT = { 12769 // use the radius of the Normal sphere 12770 'radians': 6370997 / (2 * Math.PI), 12771 'degrees': (2 * Math.PI * 6370997) / 360, 12772 'ft': 0.3048, 12773 'm': 1, 12774 'us-ft': 1200 / 3937, 12775}; 12776 12777;// CONCATENATED MODULE: ./node_modules/ol/proj/Projection.js 12778/** 12779 * @module ol/proj/Projection 12780 */ 12781 12782 12783/** 12784 * @typedef {Object} Options 12785 * @property {string} code The SRS identifier code, e.g. `EPSG:4326`. 12786 * @property {import("./Units.js").Units} [units] Units. Required unless a 12787 * proj4 projection is defined for `code`. 12788 * @property {import("../extent.js").Extent} [extent] The validity extent for the SRS. 12789 * @property {string} [axisOrientation='enu'] The axis orientation as specified in Proj4. 12790 * @property {boolean} [global=false] Whether the projection is valid for the whole globe. 12791 * @property {number} [metersPerUnit] The meters per unit for the SRS. 12792 * If not provided, the `units` are used to get the meters per unit from the {@link METERS_PER_UNIT} 12793 * lookup table. 12794 * @property {import("../extent.js").Extent} [worldExtent] The world extent for the SRS. 12795 * @property {function(number, import("../coordinate.js").Coordinate):number} [getPointResolution] 12796 * Function to determine resolution at a point. The function is called with a 12797 * `number` view resolution and a {@link module:ol/coordinate~Coordinate} as arguments, and returns 12798 * the `number` resolution in projection units at the passed coordinate. If this is `undefined`, 12799 * the default {@link module:ol/proj.getPointResolution} function will be used. 12800 */ 12801 12802/** 12803 * @classdesc 12804 * Projection definition class. One of these is created for each projection 12805 * supported in the application and stored in the {@link module:ol/proj} namespace. 12806 * You can use these in applications, but this is not required, as API params 12807 * and options use {@link module:ol/proj~ProjectionLike} which means the simple string 12808 * code will suffice. 12809 * 12810 * You can use {@link module:ol/proj.get} to retrieve the object for a particular 12811 * projection. 12812 * 12813 * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together 12814 * with the following aliases: 12815 * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, 12816 * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84, 12817 * http://www.opengis.net/gml/srs/epsg.xml#4326, 12818 * urn:x-ogc:def:crs:EPSG:4326 12819 * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913, 12820 * urn:ogc:def:crs:EPSG:6.18:3:3857, 12821 * http://www.opengis.net/gml/srs/epsg.xml#3857 12822 * 12823 * If you use [proj4js](https://github.com/proj4js/proj4js), aliases can 12824 * be added using `proj4.defs()`. After all required projection definitions are 12825 * added, call the {@link module:ol/proj/proj4.register} function. 12826 * 12827 * @api 12828 */ 12829class Projection { 12830 /** 12831 * @param {Options} options Projection options. 12832 */ 12833 constructor(options) { 12834 /** 12835 * @private 12836 * @type {string} 12837 */ 12838 this.code_ = options.code; 12839 12840 /** 12841 * Units of projected coordinates. When set to `TILE_PIXELS`, a 12842 * `this.extent_` and `this.worldExtent_` must be configured properly for each 12843 * tile. 12844 * @private 12845 * @type {import("./Units.js").Units} 12846 */ 12847 this.units_ = /** @type {import("./Units.js").Units} */ (options.units); 12848 12849 /** 12850 * Validity extent of the projection in projected coordinates. For projections 12851 * with `TILE_PIXELS` units, this is the extent of the tile in 12852 * tile pixel space. 12853 * @private 12854 * @type {import("../extent.js").Extent} 12855 */ 12856 this.extent_ = options.extent !== undefined ? options.extent : null; 12857 12858 /** 12859 * Extent of the world in EPSG:4326. For projections with 12860 * `TILE_PIXELS` units, this is the extent of the tile in 12861 * projected coordinate space. 12862 * @private 12863 * @type {import("../extent.js").Extent} 12864 */ 12865 this.worldExtent_ = 12866 options.worldExtent !== undefined ? options.worldExtent : null; 12867 12868 /** 12869 * @private 12870 * @type {string} 12871 */ 12872 this.axisOrientation_ = 12873 options.axisOrientation !== undefined ? options.axisOrientation : 'enu'; 12874 12875 /** 12876 * @private 12877 * @type {boolean} 12878 */ 12879 this.global_ = options.global !== undefined ? options.global : false;
12880 12881 /** 12882 * @private 12883 * @type {boolean} 12884 */ 12885 this.canWrapX_ = !!(this.global_ && this.extent_); 12886 12887 /** 12888 * @private 12889 * @type {function(number, import("../coordinate.js").Coordinate):number|undefined} 12890 */ 12891 this.getPointResolutionFunc_ = options.getPointResolution; 12892 12893 /** 12894 * @private 12895 * @type {import("../tilegrid/TileGrid.js").default} 12896 */ 12897 this.defaultTileGrid_ = null; 12898 12899 /** 12900 * @private 12901 * @type {number|undefined} 12902 */ 12903 this.metersPerUnit_ = options.metersPerUnit; 12904 } 12905 12906 /** 12907 * @return {boolean} The projection is suitable for wrapping the x-axis 12908 */ 12909 canWrapX() { 12910 return this.canWrapX_; 12911 } 12912 12913 /** 12914 * Get the code for this projection, e.g. 'EPSG:4326'. 12915 * @return {string} Code. 12916 * @api 12917 */ 12918 getCode() { 12919 return this.code_; 12920 } 12921 12922 /** 12923 * Get the validity extent for this projection. 12924 * @return {import("../extent.js").Extent} Extent. 12925 * @api 12926 */ 12927 getExtent() { 12928 return this.extent_; 12929 } 12930 12931 /** 12932 * Get the units of this projection. 12933 * @return {import("./Units.js").Units} Units. 12934 * @api 12935 */ 12936 getUnits() { 12937 return this.units_; 12938 } 12939 12940 /** 12941 * Get the amount of meters per unit of this projection. If the projection is 12942 * not configured with `metersPerUnit` or a units identifier, the return is 12943 * `undefined`. 12944 * @return {number|undefined} Meters. 12945 * @api 12946 */ 12947 getMetersPerUnit() { 12948 return this.metersPerUnit_ || Units_METERS_PER_UNIT[this.units_]; 12949 } 12950 12951 /** 12952 * Get the world extent for this projection. 12953 * @return {import("../extent.js").Extent} Extent. 12954 * @api 12955 */ 12956 getWorldExtent() { 12957 return this.worldExtent_; 12958 } 12959 12960 /** 12961 * Get the axis orientation of this projection. 12962 * Example values are: 12963 * enu - the default easting, northing, elevation. 12964 * neu - northing, easting, up - useful for "lat/long" geographic coordinates, 12965 * or south orientated transverse mercator. 12966 * wnu - westing, northing, up - some planetary coordinate systems have 12967 * "west positive" coordinate systems 12968 * @return {string} Axis orientation. 12969 * @api 12970 */ 12971 getAxisOrientation() { 12972 return this.axisOrientation_; 12973 } 12974 12975 /** 12976 * Is this projection a global projection which spans the whole world? 12977 * @return {boolean} Whether the projection is global. 12978 * @api 12979 */ 12980 isGlobal() { 12981 return this.global_; 12982 } 12983 12984 /** 12985 * Set if the projection is a global projection which spans the whole world 12986 * @param {boolean} global Whether the projection is global. 12987 * @api 12988 */ 12989 setGlobal(global) { 12990 this.global_ = global; 12991 this.canWrapX_ = !!(global && this.extent_); 12992 } 12993 12994 /** 12995 * @return {import("../tilegrid/TileGrid.js").default} The default tile grid. 12996 */ 12997 getDefaultTileGrid() { 12998 return this.defaultTileGrid_; 12999 } 13000 13001 /** 13002 * @param {import("../tilegrid/TileGrid.js").default} tileGrid The default tile grid. 13003 */ 13004 setDefaultTileGrid(tileGrid) { 13005 this.defaultTileGrid_ = tileGrid; 13006 } 13007 13008 /** 13009 * Set the validity extent for this projection. 13010 * @param {import("../extent.js").Extent} extent Extent. 13011 * @api 13012 */ 13013 setExtent(extent) { 13014 this.extent_ = extent; 13015 this.canWrapX_ = !!(this.global_ && extent); 13016 } 13017 13018 /** 13019 * Set the world extent for this projection. 13020 * @param {import("../extent.js").Extent} worldExtent World extent 13021 * [minlon, minlat, maxlon, maxlat]. 13022 * @api 13023 */ 13024 setWorldExtent(worldExtent) { 13025 this.worldExtent_ = worldExtent; 13026 } 13027 13028 /** 13029 * Set the getPointResolution function (see {@link module:ol/proj.getPointResolution} 13030 * for this projection. 13031 * @param {function(number, import("../coordinate.js").Coordinate):number} func Function 13032 * @api 13033 */ 13034 setGetPointResolution(func) { 13035 this.getPointResolutionFunc_ = func; 13036 } 13037 13038 /** 13039 * Get the custom point resolution function for this projection (if set). 13040 * @return {function(number, import("../coordinate.js").Coordinate):number|undefined} The custom point 13041 * resolution function (if set). 13042 */ 13043 getPointResolutionFunc() { 13044 return this.getPointResolutionFunc_; 13045 } 13046} 13047 13048/* harmony default export */ const proj_Projection = (Projection); 13049 13050;// CONCATENATED MODULE: ./node_modules/ol/proj/epsg3857.js 13051/** 13052 * @module ol/proj/epsg3857 13053 */ 13054 13055 13056/** 13057 * Radius of WGS84 sphere 13058 * 13059 * @const 13060 * @type {number} 13061 */ 13062const RADIUS = 6378137; 13063 13064/** 13065 * @const 13066 * @type {number} 13067 */ 13068const HALF_SIZE = Math.PI * RADIUS; 13069 13070/** 13071 * @const 13072 * @type {import("../extent.js").Extent} 13073 */ 13074const EXTENT = [-HALF_SIZE, -HALF_SIZE, HALF_SIZE, HALF_SIZE]; 13075 13076/** 13077 * @const 13078 * @type {import("../extent.js").Extent} 13079 */ 13080const WORLD_EXTENT = [-180, -85, 180, 85]; 13081 13082/** 13083 * Maximum safe value in y direction 13084 * @const 13085 * @type {number} 13086 */ 13087const MAX_SAFE_Y = RADIUS * Math.log(Math.tan(Math.PI / 2)); 13088 13089/** 13090 * @classdesc 13091 * Projection object for web/spherical Mercator (EPSG:3857). 13092 */ 13093class EPSG3857Projection extends proj_Projection { 13094 /** 13095 * @param {string} code Code. 13096 */ 13097 constructor(code) { 13098 super({ 13099 code: code, 13100 units: 'm', 13101 extent: EXTENT, 13102 global: true, 13103 worldExtent: WORLD_EXTENT, 13104 getPointResolution: function (resolution, point) { 13105 return resolution / Math.cosh(point[1] / RADIUS); 13106 }, 13107 }); 13108 } 13109} 13110 13111/** 13112 * Projections equal to EPSG:3857. 13113 * 13114 * @const 13115 * @type {Array<import("./Projection.js").default>} 13116 */ 13117const PROJECTIONS = [ 13118 new EPSG3857Projection('EPSG:3857'), 13119 new EPSG3857Projection('EPSG:102100'), 13120 new EPSG3857Projection('EPSG:102113'), 13121 new EPSG3857Projection('EPSG:900913'), 13122 new EPSG3857Projection('http://www.opengis.net/def/crs/EPSG/0/3857'), 13123 new EPSG3857Projection('http://www.opengis.net/gml/srs/epsg.xml#3857'), 13124]; 13125 13126/** 13127 * Transformation from EPSG:4326 to EPSG:3857. 13128 * 13129 * @param {Array<number>} input Input array of coordinate values. 13130 * @param {Array<number>} [output] Output array of coordinate values. 13131 * @param {number} [dimension] Dimension (default is `2`). 13132 * @return {Array<number>} Output array of coordinate values. 13133 */
13134function fromEPSG4326(input, output, dimension) { 13135 const length = input.length; 13136 dimension = dimension > 1 ? dimension : 2; 13137 if (output === undefined) { 13138 if (dimension > 2) { 13139 // preserve values beyond second dimension 13140 output = input.slice(); 13141 } else { 13142 output = new Array(length); 13143 } 13144 } 13145 for (let i = 0; i < length; i += dimension) { 13146 output[i] = (HALF_SIZE * input[i]) / 180; 13147 let y = RADIUS * Math.log(Math.tan((Math.PI * (+input[i + 1] + 90)) / 360)); 13148 if (y > MAX_SAFE_Y) { 13149 y = MAX_SAFE_Y; 13150 } else if (y < -MAX_SAFE_Y) { 13151 y = -MAX_SAFE_Y; 13152 } 13153 output[i + 1] = y; 13154 } 13155 return output; 13156} 13157 13158/** 13159 * Transformation from EPSG:3857 to EPSG:4326. 13160 * 13161 * @param {Array<number>} input Input array of coordinate values. 13162 * @param {Array<number>} [output] Output array of coordinate values. 13163 * @param {number} [dimension] Dimension (default is `2`). 13164 * @return {Array<number>} Output array of coordinate values. 13165 */ 13166function toEPSG4326(input, output, dimension) { 13167 const length = input.length; 13168 dimension = dimension > 1 ? dimension : 2; 13169 if (output === undefined) { 13170 if (dimension > 2) { 13171 // preserve values beyond second dimension 13172 output = input.slice(); 13173 } else { 13174 output = new Array(length); 13175 } 13176 } 13177 for (let i = 0; i < length; i += dimension) { 13178 output[i] = (180 * input[i]) / HALF_SIZE; 13179 output[i + 1] = 13180 (360 * Math.atan(Math.exp(input[i + 1] / RADIUS))) / Math.PI - 90; 13181 } 13182 return output; 13183} 13184 13185;// CONCATENATED MODULE: ./node_modules/ol/proj/epsg4326.js 13186/** 13187 * @module ol/proj/epsg4326 13188 */ 13189 13190 13191/** 13192 * Semi-major radius of the WGS84 ellipsoid. 13193 * 13194 * @const 13195 * @type {number} 13196 */ 13197const epsg4326_RADIUS = 6378137; 13198 13199/** 13200 * Extent of the EPSG:4326 projection which is the whole world. 13201 * 13202 * @const 13203 * @type {import("../extent.js").Extent} 13204 */ 13205const epsg4326_EXTENT = [-180, -90, 180, 90]; 13206 13207/** 13208 * @const 13209 * @type {number} 13210 */ 13211const epsg4326_METERS_PER_UNIT = (Math.PI * epsg4326_RADIUS) / 180; 13212 13213/** 13214 * @classdesc 13215 * Projection object for WGS84 geographic coordinates (EPSG:4326). 13216 * 13217 * Note that OpenLayers does not strictly comply with the EPSG definition. 13218 * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x). 13219 * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates. 13220 */ 13221class EPSG4326Projection extends proj_Projection { 13222 /** 13223 * @param {string} code Code. 13224 * @param {string} [axisOrientation] Axis orientation. 13225 */ 13226 constructor(code, axisOrientation) { 13227 super({ 13228 code: code, 13229 units: 'degrees', 13230 extent: epsg4326_EXTENT, 13231 axisOrientation: axisOrientation, 13232 global: true, 13233 metersPerUnit: epsg4326_METERS_PER_UNIT, 13234 worldExtent: epsg4326_EXTENT, 13235 }); 13236 } 13237} 13238 13239/** 13240 * Projections equal to EPSG:4326. 13241 * 13242 * @const 13243 * @type {Array<import("./Projection.js").default>} 13244 */ 13245const epsg4326_PROJECTIONS = [ 13246 new EPSG4326Projection('CRS:84'), 13247 new EPSG4326Projection('EPSG:4326', 'neu'), 13248 new EPSG4326Projection('urn:ogc:def:crs:OGC:1.3:CRS84'), 13249 new EPSG4326Projection('urn:ogc:def:crs:OGC:2:84'), 13250 new EPSG4326Projection('http://www.opengis.net/def/crs/OGC/1.3/CRS84'), 13251 new EPSG4326Projection('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'), 13252 new EPSG4326Projection('http://www.opengis.net/def/crs/EPSG/0/4326', 'neu'), 13253]; 13254 13255;// CONCATENATED MODULE: ./node_modules/ol/proj/projections.js 13256/** 13257 * @module ol/proj/projections 13258 */ 13259 13260/** 13261 * @type {Object<string, import("./Projection.js").default>} 13262 */ 13263let cache = {}; 13264 13265/** 13266 * Clear the projections cache. 13267 */ 13268function projections_clear() { 13269 cache = {}; 13270} 13271 13272/** 13273 * Get a cached projection by code. 13274 * @param {string} code The code for the projection. 13275 * @return {import("./Projection.js").default} The projection (if cached). 13276 */ 13277function get(code) { 13278 return ( 13279 cache[code] || 13280 cache[code.replace(/urn:(x-)?ogc:def:crs:EPSG:(.*:)?(\w+)$/, 'EPSG:$3')] || 13281 null 13282 ); 13283} 13284 13285/** 13286 * Add a projection to the cache. 13287 * @param {string} code The projection code. 13288 * @param {import("./Projection.js").default} projection The projection to cache. 13289 */ 13290function add(code, projection) { 13291 cache[code] = projection; 13292} 13293 13294;// CONCATENATED MODULE: ./node_modules/ol/proj/transforms.js 13295/** 13296 * @module ol/proj/transforms 13297 */ 13298 13299 13300/** 13301 * @private
13302 * @type {!Object<string, Object<string, import("../proj.js").TransformFunction>>} 13303 */ 13304let transforms = {}; 13305 13306/** 13307 * Clear the transform cache. 13308 */ 13309function transforms_clear() { 13310 transforms = {}; 13311} 13312 13313/** 13314 * Registers a conversion function to convert coordinates from the source 13315 * projection to the destination projection. 13316 * 13317 * @param {import("./Projection.js").default} source Source. 13318 * @param {import("./Projection.js").default} destination Destination. 13319 * @param {import("../proj.js").TransformFunction} transformFn Transform. 13320 */ 13321function transforms_add(source, destination, transformFn) { 13322 const sourceCode = source.getCode(); 13323 const destinationCode = destination.getCode(); 13324 if (!(sourceCode in transforms)) { 13325 transforms[sourceCode] = {}; 13326 } 13327 transforms[sourceCode][destinationCode] = transformFn; 13328} 13329 13330/** 13331 * Unregisters the conversion function to convert coordinates from the source 13332 * projection to the destination projection. This method is used to clean up 13333 * cached transforms during testing. 13334 * 13335 * @param {import("./Projection.js").default} source Source projection. 13336 * @param {import("./Projection.js").default} destination Destination projection. 13337 * @return {import("../proj.js").TransformFunction} transformFn The unregistered transform. 13338 */ 13339function transforms_remove(source, destination) { 13340 const sourceCode = source.getCode(); 13341 const destinationCode = destination.getCode(); 13342 const transform = transforms[sourceCode][destinationCode]; 13343 delete transforms[sourceCode][destinationCode]; 13344 if (isEmpty(transforms[sourceCode])) { 13345 delete transforms[sourceCode]; 13346 } 13347 return transform; 13348} 13349 13350/** 13351 * Get a transform given a source code and a destination code. 13352 * @param {string} sourceCode The code for the source projection. 13353 * @param {string} destinationCode The code for the destination projection. 13354 * @return {import("../proj.js").TransformFunction|undefined} The transform function (if found). 13355 */ 13356function transforms_get(sourceCode, destinationCode) { 13357 let transform; 13358 if (sourceCode in transforms && destinationCode in transforms[sourceCode]) { 13359 transform = transforms[sourceCode][destinationCode]; 13360 } 13361 return transform; 13362} 13363 13364;// CONCATENATED MODULE: ./node_modules/ol/extent/Relationship.js 13365/** 13366 * @module ol/extent/Relationship 13367 */ 13368 13369/** 13370 * Relationship to an extent. 13371 * @enum {number} 13372 */ 13373/* harmony default export */ const Relationship = ({ 13374 UNKNOWN: 0, 13375 INTERSECTING: 1, 13376 ABOVE: 2, 13377 RIGHT: 4, 13378 BELOW: 8, 13379 LEFT: 16, 13380}); 13381 13382;// CONCATENATED MODULE: ./node_modules/ol/extent.js 13383/** 13384 * @module ol/extent 13385 */ 13386 13387 13388 13389/** 13390 * An array of numbers representing an extent: `[minx, miny, maxx, maxy]`. 13391 * @typedef {Array<number>} Extent 13392 * @api 13393 */ 13394 13395/** 13396 * Extent corner. 13397 * @typedef {'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'} Corner 13398 */ 13399 13400/** 13401 * Build an extent that includes all given coordinates. 13402 * 13403 * @param {Array<import("./coordinate.js").Coordinate>} coordinates Coordinates. 13404 * @return {Extent} Bounding extent. 13405 * @api 13406 */ 13407function boundingExtent(coordinates) { 13408 const extent = createEmpty(); 13409 for (let i = 0, ii = coordinates.length; i < ii; ++i) { 13410 extendCoordinate(extent, coordinates[i]); 13411 } 13412 return extent; 13413} 13414 13415/** 13416 * @param {Array<number>} xs Xs. 13417 * @param {Array<number>} ys Ys. 13418 * @param {Extent} [dest] Destination extent. 13419 * @private 13420 * @return {Extent} Extent. 13421 */ 13422function _boundingExtentXYs(xs, ys, dest) { 13423 const minX = Math.min.apply(null, xs); 13424 const minY = Math.min.apply(null, ys); 13425 const maxX = Math.max.apply(null, xs); 13426 const maxY = Math.max.apply(null, ys); 13427 return createOrUpdate(minX, minY, maxX, maxY, dest); 13428} 13429 13430/** 13431 * Return extent increased by the provided value. 13432 * @param {Extent} extent Extent. 13433 * @param {number} value The amount by which the extent should be buffered. 13434 * @param {Extent} [dest] Extent. 13435 * @return {Extent} Extent. 13436 * @api 13437 */ 13438function buffer(extent, value, dest) { 13439 if (dest) { 13440 dest[0] = extent[0] - value; 13441 dest[1] = extent[1] - value; 13442 dest[2] = extent[2] + value; 13443 dest[3] = extent[3] + value; 13444 return dest; 13445 } else { 13446 return [ 13447 extent[0] - value, 13448 extent[1] - value, 13449 extent[2] + value, 13450 extent[3] + value, 13451 ]; 13452 } 13453} 13454 13455/** 13456 * Creates a clone of an extent. 13457 * 13458 * @param {Extent} extent Extent to clone. 13459 * @param {Extent} [dest] Extent. 13460 * @return {Extent} The clone. 13461 */ 13462function clone(extent, dest) { 13463 if (dest) { 13464 dest[0] = extent[0]; 13465 dest[1] = extent[1]; 13466 dest[2] = extent[2]; 13467 dest[3] = extent[3]; 13468 return dest; 13469 } else { 13470 return extent.slice(); 13471 } 13472} 13473 13474/** 13475 * @param {Extent} extent Extent. 13476 * @param {number} x X. 13477 * @param {number} y Y. 13478 * @return {number} Closest squared distance. 13479 */ 13480function closestSquaredDistanceXY(extent, x, y) { 13481 let dx, dy; 13482 if (x < extent[0]) { 13483 dx = extent[0] - x; 13484 } else if (extent[2] < x) { 13485 dx = x - extent[2]; 13486 } else { 13487 dx = 0; 13488 } 13489 if (y < extent[1]) { 13490 dy = extent[1] - y; 13491 } else if (extent[3] < y) { 13492 dy = y - extent[3]; 13493 } else { 13494 dy = 0; 13495 } 13496 return dx * dx + dy * dy; 13497} 13498 13499/** 13500 * Check if the passed coordinate is contained or on the edge of the extent. 13501 * 13502 * @param {Extent} extent Extent. 13503 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. 13504 * @return {boolean} The coordinate is contained in the extent. 13505 * @api 13506 */ 13507function containsCoordinate(extent, coordinate) { 13508 return containsXY(extent, coordinate[0], coordinate[1]); 13509} 13510 13511/** 13512 * Check if one extent contains another. 13513 * 13514 * An extent is deemed contained if it lies completely within the other extent, 13515 * including if they share one or more edges. 13516 * 13517 * @param {Extent} extent1 Extent 1. 13518 * @param {Extent} extent2 Extent 2. 13519 * @return {boolean} The second extent is contained by or on the edge of the 13520 * first. 13521 * @api 13522 */ 13523function containsExtent(extent1, extent2) { 13524 return ( 13525 extent1[0] <= extent2[0] && 13526 extent2[2] <= extent1[2] && 13527 extent1[1] <= extent2[1] && 13528 extent2[3] <= extent1[3] 13529 ); 13530} 13531 13532/** 13533 * Check if the passed coordinate is contained or on the edge of the extent. 13534 * 13535 * @param {Extent} extent Extent. 13536 * @param {number} x X coordinate. 13537 * @param {number} y Y coordinate. 13538 * @return {boolean} The x, y values are contained in the extent. 13539 * @api 13540 */ 13541function containsXY(extent, x, y) { 13542 return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3]; 13543} 13544 13545/** 13546 * Get the relationship between a coordinate and extent. 13547 * @param {Extent} extent The extent. 13548 * @param {import("./coordinate.js").Coordinate} coordinate The coordinate. 13549 * @return {import("./extent/Relationship.js").default} The relationship (bitwise compare with
13550 * import("./extent/Relationship.js").Relationship). 13551 */ 13552function coordinateRelationship(extent, coordinate) { 13553 const minX = extent[0]; 13554 const minY = extent[1]; 13555 const maxX = extent[2]; 13556 const maxY = extent[3]; 13557 const x = coordinate[0]; 13558 const y = coordinate[1]; 13559 let relationship = Relationship.UNKNOWN; 13560 if (x < minX) { 13561 relationship = relationship | Relationship.LEFT; 13562 } else if (x > maxX) { 13563 relationship = relationship | Relationship.RIGHT; 13564 } 13565 if (y < minY) { 13566 relationship = relationship | Relationship.BELOW; 13567 } else if (y > maxY) { 13568 relationship = relationship | Relationship.ABOVE; 13569 } 13570 if (relationship === Relationship.UNKNOWN) { 13571 relationship = Relationship.INTERSECTING; 13572 } 13573 return relationship; 13574} 13575 13576/** 13577 * Create an empty extent. 13578 * @return {Extent} Empty extent. 13579 * @api 13580 */ 13581function createEmpty() { 13582 return [Infinity, Infinity, -Infinity, -Infinity]; 13583} 13584 13585/** 13586 * Create a new extent or update the provided extent. 13587 * @param {number} minX Minimum X. 13588 * @param {number} minY Minimum Y. 13589 * @param {number} maxX Maximum X. 13590 * @param {number} maxY Maximum Y. 13591 * @param {Extent} [dest] Destination extent. 13592 * @return {Extent} Extent. 13593 */ 13594function createOrUpdate(minX, minY, maxX, maxY, dest) { 13595 if (dest) { 13596 dest[0] = minX; 13597 dest[1] = minY; 13598 dest[2] = maxX; 13599 dest[3] = maxY; 13600 return dest; 13601 } else { 13602 return [minX, minY, maxX, maxY]; 13603 } 13604} 13605 13606/** 13607 * Create a new empty extent or make the provided one empty. 13608 * @param {Extent} [dest] Extent. 13609 * @return {Extent} Extent. 13610 */ 13611function createOrUpdateEmpty(dest) { 13612 return createOrUpdate(Infinity, Infinity, -Infinity, -Infinity, dest); 13613} 13614 13615/** 13616 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. 13617 * @param {Extent} [dest] Extent. 13618 * @return {Extent} Extent. 13619 */ 13620function createOrUpdateFromCoordinate(coordinate, dest) { 13621 const x = coordinate[0]; 13622 const y = coordinate[1]; 13623 return createOrUpdate(x, y, x, y, dest); 13624} 13625 13626/** 13627 * @param {Array<import("./coordinate.js").Coordinate>} coordinates Coordinates. 13628 * @param {Extent} [dest] Extent. 13629 * @return {Extent} Extent. 13630 */ 13631function createOrUpdateFromCoordinates(coordinates, dest) { 13632 const extent = createOrUpdateEmpty(dest); 13633 return extendCoordinates(extent, coordinates); 13634} 13635 13636/** 13637 * @param {Array<number>} flatCoordinates Flat coordinates. 13638 * @param {number} offset Offset. 13639 * @param {number} end End. 13640 * @param {number} stride Stride. 13641 * @param {Extent} [dest] Extent. 13642 * @return {Extent} Extent. 13643 */ 13644function createOrUpdateFromFlatCoordinates( 13645 flatCoordinates, 13646 offset, 13647 end, 13648 stride, 13649 dest 13650) { 13651 const extent = createOrUpdateEmpty(dest); 13652 return extendFlatCoordinates(extent, flatCoordinates, offset, end, stride); 13653} 13654 13655/** 13656 * @param {Array<Array<import("./coordinate.js").Coordinate>>} rings Rings. 13657 * @param {Extent} [dest] Extent. 13658 * @return {Extent} Extent. 13659 */ 13660function createOrUpdateFromRings(rings, dest) { 13661 const extent = createOrUpdateEmpty(dest); 13662 return extendRings(extent, rings); 13663} 13664 13665/** 13666 * Determine if two extents are equivalent. 13667 * @param {Extent} extent1 Extent 1. 13668 * @param {Extent} extent2 Extent 2. 13669 * @return {boolean} The two extents are equivalent. 13670 * @api 13671 */ 13672function extent_equals(extent1, extent2) { 13673 return ( 13674 extent1[0] == extent2[0] && 13675 extent1[2] == extent2[2] && 13676 extent1[1] == extent2[1] && 13677 extent1[3] == extent2[3] 13678 ); 13679} 13680 13681/** 13682 * Determine if two extents are approximately equivalent. 13683 * @param {Extent} extent1 Extent 1. 13684 * @param {Extent} extent2 Extent 2. 13685 * @param {number} tolerance Tolerance in extent coordinate units. 13686 * @return {boolean} The two extents differ by less than the tolerance. 13687 */ 13688function approximatelyEquals(extent1, extent2, tolerance) { 13689 return ( 13690 Math.abs(extent1[0] - extent2[0]) < tolerance && 13691 Math.abs(extent1[2] - extent2[2]) < tolerance && 13692 Math.abs(extent1[1] - extent2[1]) < tolerance && 13693 Math.abs(extent1[3] - extent2[3]) < tolerance 13694 ); 13695} 13696 13697/** 13698 * Modify an extent to include another extent. 13699 * @param {Extent} extent1 The extent to be modified. 13700 * @param {Extent} extent2 The extent that will be included in the first. 13701 * @return {Extent} A reference to the first (extended) extent. 13702 * @api 13703 */ 13704function extent_extend(extent1, extent2) { 13705 if (extent2[0] < extent1[0]) { 13706 extent1[0] = extent2[0]; 13707 } 13708 if (extent2[2] > extent1[2]) { 13709 extent1[2] = extent2[2]; 13710 } 13711 if (extent2[1] < extent1[1]) { 13712 extent1[1] = extent2[1]; 13713 } 13714 if (extent2[3] > extent1[3]) { 13715 extent1[3] = extent2[3]; 13716 } 13717 return extent1; 13718} 13719 13720/** 13721 * @param {Extent} extent Extent. 13722 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. 13723 */ 13724function extendCoordinate(extent, coordinate) { 13725 if (coordinate[0] < extent[0]) {
13726 extent[0] = coordinate[0]; 13727 } 13728 if (coordinate[0] > extent[2]) { 13729 extent[2] = coordinate[0]; 13730 } 13731 if (coordinate[1] < extent[1]) { 13732 extent[1] = coordinate[1]; 13733 } 13734 if (coordinate[1] > extent[3]) { 13735 extent[3] = coordinate[1]; 13736 } 13737} 13738 13739/** 13740 * @param {Extent} extent Extent. 13741 * @param {Array<import("./coordinate.js").Coordinate>} coordinates Coordinates. 13742 * @return {Extent} Extent. 13743 */ 13744function extendCoordinates(extent, coordinates) { 13745 for (let i = 0, ii = coordinates.length; i < ii; ++i) { 13746 extendCoordinate(extent, coordinates[i]); 13747 } 13748 return extent; 13749} 13750 13751/** 13752 * @param {Extent} extent Extent. 13753 * @param {Array<number>} flatCoordinates Flat coordinates. 13754 * @param {number} offset Offset. 13755 * @param {number} end End. 13756 * @param {number} stride Stride. 13757 * @return {Extent} Extent. 13758 */ 13759function extendFlatCoordinates( 13760 extent, 13761 flatCoordinates, 13762 offset, 13763 end, 13764 stride 13765) { 13766 for (; offset < end; offset += stride) { 13767 extendXY(extent, flatCoordinates[offset], flatCoordinates[offset + 1]); 13768 } 13769 return extent; 13770} 13771 13772/** 13773 * @param {Extent} extent Extent. 13774 * @param {Array<Array<import("./coordinate.js").Coordinate>>} rings Rings. 13775 * @return {Extent} Extent. 13776 */ 13777function extendRings(extent, rings) { 13778 for (let i = 0, ii = rings.length; i < ii; ++i) { 13779 extendCoordinates(extent, rings[i]); 13780 } 13781 return extent; 13782} 13783 13784/** 13785 * @param {Extent} extent Extent. 13786 * @param {number} x X. 13787 * @param {number} y Y. 13788 */ 13789function extendXY(extent, x, y) { 13790 extent[0] = Math.min(extent[0], x); 13791 extent[1] = Math.min(extent[1], y); 13792 extent[2] = Math.max(extent[2], x); 13793 extent[3] = Math.max(extent[3], y); 13794} 13795 13796/** 13797 * This function calls `callback` for each corner of the extent. If the 13798 * callback returns a truthy value the function returns that value 13799 * immediately. Otherwise the function returns `false`. 13800 * @param {Extent} extent Extent. 13801 * @param {function(import("./coordinate.js").Coordinate): S} callback Callback. 13802 * @return {S|boolean} Value. 13803 * @template S 13804 */ 13805function forEachCorner(extent, callback) { 13806 let val; 13807 val = callback(getBottomLeft(extent)); 13808 if (val) { 13809 return val; 13810 } 13811 val = callback(getBottomRight(extent)); 13812 if (val) { 13813 return val; 13814 } 13815 val = callback(getTopRight(extent)); 13816 if (val) { 13817 return val; 13818 } 13819 val = callback(getTopLeft(extent)); 13820 if (val) { 13821 return val; 13822 } 13823 return false; 13824} 13825 13826/** 13827 * Get the size of an extent. 13828 * @param {Extent} extent Extent. 13829 * @return {number} Area. 13830 * @api 13831 */ 13832function getArea(extent) { 13833 let area = 0; 13834 if (!extent_isEmpty(extent)) { 13835 area = extent_getWidth(extent) * extent_getHeight(extent); 13836 } 13837 return area; 13838} 13839 13840/** 13841 * Get the bottom left coordinate of an extent. 13842 * @param {Extent} extent Extent. 13843 * @return {import("./coordinate.js").Coordinate} Bottom left coordinate. 13844 * @api 13845 */ 13846function getBottomLeft(extent) { 13847 return [extent[0], extent[1]]; 13848} 13849 13850/** 13851 * Get the bottom right coordinate of an extent. 13852 * @param {Extent} extent Extent. 13853 * @return {import("./coordinate.js").Coordinate} Bottom right coordinate. 13854 * @api 13855 */ 13856function getBottomRight(extent) { 13857 return [extent[2], extent[1]]; 13858} 13859 13860/** 13861 * Get the center coordinate of an extent. 13862 * @param {Extent} extent Extent. 13863 * @return {import("./coordinate.js").Coordinate} Center. 13864 * @api 13865 */ 13866function getCenter(extent) { 13867 return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2]; 13868} 13869 13870/** 13871 * Get a corner coordinate of an extent. 13872 * @param {Extent} extent Extent. 13873 * @param {Corner} corner Corner. 13874 * @return {import("./coordinate.js").Coordinate} Corner coordinate. 13875 */ 13876function getCorner(extent, corner) { 13877 let coordinate; 13878 if (corner === 'bottom-left') { 13879 coordinate = getBottomLeft(extent); 13880 } else if (corner === 'bottom-right') { 13881 coordinate = getBottomRight(extent); 13882 } else if (corner === 'top-left') { 13883 coordinate = getTopLeft(extent); 13884 } else if (corner === 'top-right') { 13885 coordinate = getTopRight(extent); 13886 } else { 13887 asserts_assert(false, 13); // Invalid corner 13888 } 13889 return coordinate; 13890} 13891 13892/** 13893 * @param {Extent} extent1 Extent 1. 13894 * @param {Extent} extent2 Extent 2. 13895 * @return {number} Enlarged area. 13896 */ 13897function getEnlargedArea(extent1, extent2) { 13898 const minX = Math.min(extent1[0], extent2[0]); 13899 const minY = Math.min(extent1[1], extent2[1]); 13900 const maxX = Math.max(extent1[2], extent2[2]); 13901 const maxY = Math.max(extent1[3], extent2[3]); 13902 return (maxX - minX) * (maxY - minY); 13903} 13904 13905/** 13906 * @param {import("./coordinate.js").Coordinate} center Center. 13907 * @param {number} resolution Resolution. 13908 * @param {number} rotation Rotation. 13909 * @param {import("./size.js").Size} size Size. 13910 * @param {Extent} [dest] Destination extent. 13911 * @return {Extent} Extent. 13912 */ 13913function getForViewAndSize(center, resolution, rotation, size, dest) { 13914 const [x0, y0, x1, y1, x2, y2, x3, y3] = getRotatedViewport( 13915 center, 13916 resolution, 13917 rotation, 13918 size 13919 ); 13920 return createOrUpdate( 13921 Math.min(x0, x1, x2, x3), 13922 Math.min(y0, y1, y2, y3), 13923 Math.max(x0, x1, x2, x3), 13924 Math.max(y0, y1, y2, y3), 13925 dest 13926 ); 13927} 13928 13929/** 13930 * @param {import("./coordinate.js").Coordinate} center Center. 13931 * @param {number} resolution Resolution. 13932 * @param {number} rotation Rotation. 13933 * @param {import("./size.js").Size} size Size. 13934 * @return {Array<number>} Linear ring representing the viewport. 13935 */ 13936function getRotatedViewport(center, resolution, rotation, size) { 13937 const dx = (resolution * size[0]) / 2; 13938 const dy = (resolution * size[1]) / 2; 13939 const cosRotation = Math.cos(rotation); 13940 const sinRotation = Math.sin(rotation); 13941 const xCos = dx * cosRotation;
13942 const xSin = dx * sinRotation; 13943 const yCos = dy * cosRotation; 13944 const ySin = dy * sinRotation; 13945 const x = center[0]; 13946 const y = center[1]; 13947 return [ 13948 x - xCos + ySin, 13949 y - xSin - yCos, 13950 x - xCos - ySin, 13951 y - xSin + yCos, 13952 x + xCos - ySin, 13953 y + xSin + yCos, 13954 x + xCos + ySin, 13955 y + xSin - yCos, 13956 x - xCos + ySin, 13957 y - xSin - yCos, 13958 ]; 13959} 13960 13961/** 13962 * Get the height of an extent. 13963 * @param {Extent} extent Extent. 13964 * @return {number} Height. 13965 * @api 13966 */ 13967function extent_getHeight(extent) { 13968 return extent[3] - extent[1]; 13969} 13970 13971/** 13972 * @param {Extent} extent1 Extent 1. 13973 * @param {Extent} extent2 Extent 2. 13974 * @return {number} Intersection area. 13975 */ 13976function getIntersectionArea(extent1, extent2) { 13977 const intersection = getIntersection(extent1, extent2); 13978 return getArea(intersection); 13979} 13980 13981/** 13982 * Get the intersection of two extents. 13983 * @param {Extent} extent1 Extent 1. 13984 * @param {Extent} extent2 Extent 2. 13985 * @param {Extent} [dest] Optional extent to populate with intersection. 13986 * @return {Extent} Intersecting extent. 13987 * @api 13988 */ 13989function getIntersection(extent1, extent2, dest) { 13990 const intersection = dest ? dest : createEmpty(); 13991 if (intersects(extent1, extent2)) { 13992 if (extent1[0] > extent2[0]) { 13993 intersection[0] = extent1[0]; 13994 } else { 13995 intersection[0] = extent2[0]; 13996 } 13997 if (extent1[1] > extent2[1]) { 13998 intersection[1] = extent1[1]; 13999 } else { 14000 intersection[1] = extent2[1]; 14001 } 14002 if (extent1[2] < extent2[2]) { 14003 intersection[2] = extent1[2]; 14004 } else { 14005 intersection[2] = extent2[2]; 14006 } 14007 if (extent1[3] < extent2[3]) { 14008 intersection[3] = extent1[3]; 14009 } else { 14010 intersection[3] = extent2[3]; 14011 } 14012 } else { 14013 createOrUpdateEmpty(intersection); 14014 } 14015 return intersection; 14016} 14017 14018/** 14019 * @param {Extent} extent Extent. 14020 * @return {number} Margin. 14021 */ 14022function getMargin(extent) { 14023 return extent_getWidth(extent) + extent_getHeight(extent); 14024} 14025 14026/** 14027 * Get the size (width, height) of an extent. 14028 * @param {Extent} extent The extent. 14029 * @return {import("./size.js").Size} The extent size. 14030 * @api 14031 */ 14032function getSize(extent) { 14033 return [extent[2] - extent[0], extent[3] - extent[1]]; 14034} 14035 14036/** 14037 * Get the top left coordinate of an extent. 14038 * @param {Extent} extent Extent. 14039 * @return {import("./coordinate.js").Coordinate} Top left coordinate. 14040 * @api 14041 */ 14042function getTopLeft(extent) { 14043 return [extent[0], extent[3]]; 14044} 14045 14046/** 14047 * Get the top right coordinate of an extent. 14048 * @param {Extent} extent Extent. 14049 * @return {import("./coordinate.js").Coordinate} Top right coordinate. 14050 * @api 14051 */ 14052function getTopRight(extent) { 14053 return [extent[2], extent[3]]; 14054} 14055 14056/** 14057 * Get the width of an extent. 14058 * @param {Extent} extent Extent. 14059 * @return {number} Width. 14060 * @api 14061 */ 14062function extent_getWidth(extent) { 14063 return extent[2] - extent[0]; 14064} 14065 14066/** 14067 * Determine if one extent intersects another. 14068 * @param {Extent} extent1 Extent 1. 14069 * @param {Extent} extent2 Extent. 14070 * @return {boolean} The two extents intersect. 14071 * @api 14072 */ 14073function intersects(extent1, extent2) { 14074 return ( 14075 extent1[0] <= extent2[2] && 14076 extent1[2] >= extent2[0] && 14077 extent1[1] <= extent2[3] && 14078 extent1[3] >= extent2[1] 14079 ); 14080} 14081 14082/** 14083 * Determine if an extent is empty. 14084 * @param {Extent} extent Extent. 14085 * @return {boolean} Is empty. 14086 * @api 14087 */ 14088function extent_isEmpty(extent) { 14089 return extent[2] < extent[0] || extent[3] < extent[1]; 14090} 14091 14092/** 14093 * @param {Extent} extent Extent. 14094 * @param {Extent} [dest] Extent. 14095 * @return {Extent} Extent. 14096 */ 14097function returnOrUpdate(extent, dest) { 14098 if (dest) { 14099 dest[0] = extent[0]; 14100 dest[1] = extent[1]; 14101 dest[2] = extent[2]; 14102 dest[3] = extent[3]; 14103 return dest; 14104 } else { 14105 return extent; 14106 } 14107} 14108 14109/** 14110 * @param {Extent} extent Extent. 14111 * @param {number} value Value. 14112 */ 14113function scaleFromCenter(extent, value) { 14114 const deltaX = ((extent[2] - extent[0]) / 2) * (value - 1); 14115 const deltaY = ((extent[3] - extent[1]) / 2) * (value - 1); 14116 extent[0] -= deltaX; 14117 extent[2] += deltaX; 14118 extent[1] -= deltaY; 14119 extent[3] += deltaY; 14120} 14121 14122/** 14123 * Determine if the segment between two coordinates intersects (crosses, 14124 * touches, or is contained by) the provided extent. 14125 * @param {Extent} extent The extent. 14126 * @param {import("./coordinate.js").Coordinate} start Segment start coordinate. 14127 * @param {import("./coordinate.js").Coordinate} end Segment end coordinate. 14128 * @return {boolean} The segment intersects the extent. 14129 */ 14130function intersectsSegment(extent, start, end) { 14131 let intersects = false;
vendor: 5,289 bytes, lines 14132-14311
14132 const startRel = coordinateRelationship(extent, start); 14133 const endRel = coordinateRelationship(extent, end); 14134 if ( 14135 startRel === Relationship.INTERSECTING || 14136 endRel === Relationship.INTERSECTING 14137 ) { 14138 intersects = true; 14139 } else { 14140 const minX = extent[0]; 14141 const minY = extent[1]; 14142 const maxX = extent[2]; 14143 const maxY = extent[3]; 14144 const startX = start[0]; 14145 const startY = start[1]; 14146 const endX = end[0]; 14147 const endY = end[1]; 14148 const slope = (endY - startY) / (endX - startX); 14149 let x, y; 14150 if (!!(endRel & Relationship.ABOVE) && !(startRel & Relationship.ABOVE)) { 14151 // potentially intersects top 14152 x = endX - (endY - maxY) / slope; 14153 intersects = x >= minX && x <= maxX; 14154 } 14155 if ( 14156 !intersects && 14157 !!(endRel & Relationship.RIGHT) && 14158 !(startRel & Relationship.RIGHT) 14159 ) { 14160 // potentially intersects right 14161 y = endY - (endX - maxX) * slope; 14162 intersects = y >= minY && y <= maxY; 14163 } 14164 if ( 14165 !intersects && 14166 !!(endRel & Relationship.BELOW) && 14167 !(startRel & Relationship.BELOW) 14168 ) { 14169 // potentially intersects bottom 14170 x = endX - (endY - minY) / slope; 14171 intersects = x >= minX && x <= maxX; 14172 } 14173 if ( 14174 !intersects && 14175 !!(endRel & Relationship.LEFT) && 14176 !(startRel & Relationship.LEFT) 14177 ) { 14178 // potentially intersects left 14179 y = endY - (endX - minX) * slope; 14180 intersects = y >= minY && y <= maxY; 14181 } 14182 } 14183 return intersects; 14184} 14185 14186/** 14187 * Apply a transform function to the extent. 14188 * @param {Extent} extent Extent. 14189 * @param {import("./proj.js").TransformFunction} transformFn Transform function. 14190 * Called with `[minX, minY, maxX, maxY]` extent coordinates. 14191 * @param {Extent} [dest] Destination extent. 14192 * @param {number} [stops] Number of stops per side used for the transform. 14193 * By default only the corners are used. 14194 * @return {Extent} Extent. 14195 * @api 14196 */ 14197function applyTransform(extent, transformFn, dest, stops) { 14198 let coordinates = []; 14199 if (stops > 1) { 14200 const width = extent[2] - extent[0]; 14201 const height = extent[3] - extent[1]; 14202 for (let i = 0; i < stops; ++i) { 14203 coordinates.push( 14204 extent[0] + (width * i) / stops, 14205 extent[1], 14206 extent[2], 14207 extent[1] + (height * i) / stops, 14208 extent[2] - (width * i) / stops, 14209 extent[3], 14210 extent[0], 14211 extent[3] - (height * i) / stops 14212 ); 14213 } 14214 } else { 14215 coordinates = [ 14216 extent[0], 14217 extent[1], 14218 extent[2], 14219 extent[1], 14220 extent[2], 14221 extent[3], 14222 extent[0], 14223 extent[3], 14224 ]; 14225 } 14226 transformFn(coordinates, coordinates, 2); 14227 const xs = []; 14228 const ys = []; 14229 for (let i = 0, l = coordinates.length; i < l; i += 2) { 14230 xs.push(coordinates[i]); 14231 ys.push(coordinates[i + 1]); 14232 } 14233 return _boundingExtentXYs(xs, ys, dest); 14234} 14235 14236/** 14237 * Modifies the provided extent in-place to be within the real world 14238 * extent. 14239 * 14240 * @param {Extent} extent Extent. 14241 * @param {import("./proj/Projection.js").default} projection Projection 14242 * @return {Extent} The extent within the real world extent. 14243 */ 14244function wrapX(extent, projection) { 14245 const projectionExtent = projection.getExtent(); 14246 const center = getCenter(extent); 14247 if ( 14248 projection.canWrapX() && 14249 (center[0] < projectionExtent[0] || center[0] >= projectionExtent[2]) 14250 ) { 14251 const worldWidth = extent_getWidth(projectionExtent); 14252 const worldsAway = Math.floor( 14253 (center[0] - projectionExtent[0]) / worldWidth 14254 ); 14255 const offset = worldsAway * worldWidth; 14256 extent[0] -= offset; 14257 extent[2] -= offset; 14258 } 14259 return extent; 14260} 14261 14262/** 14263 * Fits the extent to the real world 14264 * 14265 * If the extent does not cross the anti meridian, this will return the extent in an array 14266 * If the extent crosses the anti meridian, the extent will be sliced, so each part fits within the 14267 * real world 14268 * 14269 * 14270 * @param {Extent} extent Extent. 14271 * @param {import("./proj/Projection.js").default} projection Projection 14272 * @return {Array<Extent>} The extent within the real world extent. 14273 */ 14274function wrapAndSliceX(extent, projection) { 14275 if (projection.canWrapX()) { 14276 const projectionExtent = projection.getExtent(); 14277 14278 if (!isFinite(extent[0]) || !isFinite(extent[2])) { 14279 return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]]; 14280 } 14281 14282 wrapX(extent, projection); 14283 const worldWidth = extent_getWidth(projectionExtent); 14284 14285 if (extent_getWidth(extent) > worldWidth) { 14286 // the extent wraps around on itself 14287 return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]]; 14288 } else if (extent[0] < projectionExtent[0]) { 14289 // the extent crosses the anti meridian, so it needs to be sliced 14290 return [ 14291 [extent[0] + worldWidth, extent[1], projectionExtent[2], extent[3]], 14292 [projectionExtent[0], extent[1], extent[2], extent[3]], 14293 ]; 14294 } else if (extent[2] > projectionExtent[2]) { 14295 // the extent crosses the anti meridian, so it needs to be sliced 14296 return [ 14297 [extent[0], extent[1], projectionExtent[2], extent[3]], 14298 [projectionExtent[0], extent[1], extent[2] - worldWidth, extent[3]], 14299 ]; 14300 } 14301 } 14302 14303 return [extent]; 14304} 14305 14306;// CONCATENATED MODULE: ./node_modules/ol/math.js 14307/** 14308 * @module ol/math 14309 */ 14310 14311/**
14312 * Takes a number and clamps it to within the provided bounds. 14313 * @param {number} value The input number. 14314 * @param {number} min The minimum value to return. 14315 * @param {number} max The maximum value to return. 14316 * @return {number} The input number if it is within bounds, or the nearest 14317 * number within the bounds. 14318 */ 14319function math_clamp(value, min, max) { 14320 return Math.min(Math.max(value, min), max); 14321} 14322 14323/** 14324 * Returns the square of the closest distance between the point (x, y) and the 14325 * line segment (x1, y1) to (x2, y2). 14326 * @param {number} x X. 14327 * @param {number} y Y. 14328 * @param {number} x1 X1. 14329 * @param {number} y1 Y1. 14330 * @param {number} x2 X2. 14331 * @param {number} y2 Y2. 14332 * @return {number} Squared distance. 14333 */ 14334function squaredSegmentDistance(x, y, x1, y1, x2, y2) { 14335 const dx = x2 - x1; 14336 const dy = y2 - y1; 14337 if (dx !== 0 || dy !== 0) { 14338 const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); 14339 if (t > 1) { 14340 x1 = x2; 14341 y1 = y2; 14342 } else if (t > 0) { 14343 x1 += dx * t; 14344 y1 += dy * t; 14345 } 14346 } 14347 return math_squaredDistance(x, y, x1, y1); 14348} 14349 14350/** 14351 * Returns the square of the distance between the points (x1, y1) and (x2, y2). 14352 * @param {number} x1 X1. 14353 * @param {number} y1 Y1. 14354 * @param {number} x2 X2. 14355 * @param {number} y2 Y2. 14356 * @return {number} Squared distance. 14357 */ 14358function math_squaredDistance(x1, y1, x2, y2) { 14359 const dx = x2 - x1; 14360 const dy = y2 - y1; 14361 return dx * dx + dy * dy; 14362} 14363 14364/** 14365 * Solves system of linear equations using Gaussian elimination method. 14366 * 14367 * @param {Array<Array<number>>} mat Augmented matrix (n x n + 1 column) 14368 * in row-major order. 14369 * @return {Array<number>} The resulting vector. 14370 */ 14371function solveLinearSystem(mat) { 14372 const n = mat.length; 14373 14374 for (let i = 0; i < n; i++) { 14375 // Find max in the i-th column (ignoring i - 1 first rows) 14376 let maxRow = i; 14377 let maxEl = Math.abs(mat[i][i]); 14378 for (let r = i + 1; r < n; r++) { 14379 const absValue = Math.abs(mat[r][i]); 14380 if (absValue > maxEl) { 14381 maxEl = absValue; 14382 maxRow = r; 14383 } 14384 } 14385 14386 if (maxEl === 0) { 14387 return null; // matrix is singular 14388 } 14389 14390 // Swap max row with i-th (current) row 14391 const tmp = mat[maxRow]; 14392 mat[maxRow] = mat[i]; 14393 mat[i] = tmp; 14394 14395 // Subtract the i-th row to make all the remaining rows 0 in the i-th column 14396 for (let j = i + 1; j < n; j++) { 14397 const coef = -mat[j][i] / mat[i][i]; 14398 for (let k = i; k < n + 1; k++) { 14399 if (i == k) { 14400 mat[j][k] = 0; 14401 } else { 14402 mat[j][k] += coef * mat[i][k]; 14403 } 14404 } 14405 } 14406 } 14407 14408 // Solve Ax=b for upper triangular matrix A (mat) 14409 const x = new Array(n); 14410 for (let l = n - 1; l >= 0; l--) { 14411 x[l] = mat[l][n] / mat[l][l]; 14412 for (let m = l - 1; m >= 0; m--) { 14413 mat[m][n] -= mat[m][l] * x[l]; 14414 } 14415 } 14416 return x; 14417} 14418 14419/** 14420 * Converts radians to to degrees. 14421 * 14422 * @param {number} angleInRadians Angle in radians. 14423 * @return {number} Angle in degrees. 14424 */ 14425function math_toDegrees(angleInRadians) { 14426 return (angleInRadians * 180) / Math.PI; 14427} 14428 14429/** 14430 * Converts degrees to radians. 14431 * 14432 * @param {number} angleInDegrees Angle in degrees. 14433 * @return {number} Angle in radians. 14434 */ 14435function math_toRadians(angleInDegrees) { 14436 return (angleInDegrees * Math.PI) / 180; 14437} 14438 14439/** 14440 * Returns the modulo of a / b, depending on the sign of b. 14441 * 14442 * @param {number}
14442 a Dividend. 14443 * @param {number} b Divisor. 14444 * @return {number} Modulo. 14445 */ 14446function math_modulo(a, b) { 14447 const r = a % b; 14448 return r * b < 0 ? r + b : r; 14449} 14450 14451/** 14452 * Calculates the linearly interpolated value of x between a and b. 14453 * 14454 * @param {number} a Number 14455 * @param {number} b Number 14456 * @param {number} x Value to be interpolated. 14457 * @return {number} Interpolated value. 14458 */ 14459function lerp(a, b, x) { 14460 return a + x * (b - a); 14461} 14462 14463/** 14464 * Returns a number with a limited number of decimal digits. 14465 * @param {number} n The input number. 14466 * @param {number} decimals The maximum number of decimal digits. 14467 * @return {number} The input number with a limited number of decimal digits. 14468 */ 14469function math_toFixed(n, decimals) { 14470 const factor = Math.pow(10, decimals); 14471 return Math.round(n * factor) / factor; 14472} 14473 14474/** 14475 * Rounds a number to the nearest integer value considering only the given number 14476 * of decimal digits (with rounding on the final digit). 14477 * @param {number} n The input number. 14478 * @param {number} decimals The maximum number of decimal digits. 14479 * @return {number} The nearest integer. 14480 */ 14481function round(n, decimals) { 14482 return Math.round(math_toFixed(n, decimals)); 14483} 14484 14485/** 14486 * Rounds a number to the next smaller integer considering only the given number 14487 * of decimal digits (with rounding on the final digit). 14488 * @param {number} n The input number. 14489 * @param {number} decimals The maximum number of decimal digits. 14490 * @return {number} The next smaller integer. 14491 */ 14492function floor(n, decimals) { 14493 return Math.floor(math_toFixed(n, decimals)); 14494} 14495 14496/** 14497 * Rounds a number to the next bigger integer considering only the given number 14498 * of decimal digits (with rounding on the final digit). 14499 * @param {number} n The input number. 14500 * @param {number} decimals The maximum number of decimal digits. 14501 * @return {number} The next bigger integer. 14502 */ 14503function ceil(n, decimals) { 14504 return Math.ceil(math_toFixed(n, decimals)); 14505} 14506 14507;// CONCATENATED MODULE: ./node_modules/ol/coordinate.js 14508/** 14509 * @module ol/coordinate 14510 */ 14511 14512 14513 14514 14515/** 14516 * An array of numbers representing an xy coordinate. Example: `[16, 48]`. 14517 * @typedef {Array<number>} Coordinate 14518 * @api 14519 */ 14520 14521/** 14522 * A function that takes a {@link module:ol/coordinate~Coordinate} and 14523 * transforms it into a `{string}`. 14524 * 14525 * @typedef {function((Coordinate|undefined)): string} CoordinateFormat 14526 * @api 14527 */ 14528 14529/** 14530 * Add `delta` to `coordinate`. `coordinate` is modified in place and returned 14531 * by the function. 14532 * 14533 * Example: 14534 * 14535 * import {add} from 'ol/coordinate'; 14536 * 14537 * const coord = [7.85, 47.983333]; 14538 * add(coord, [-2, 4]); 14539 * // coord is now [5.85, 51.983333] 14540 * 14541 * @param {Coordinate} coordinate Coordinate. 14542 * @param {Coordinate} delta Delta. 14543 * @return {Coordinate} The input coordinate adjusted by 14544 * the given delta. 14545 * @api 14546 */ 14547function coordinate_add(coordinate, delta) { 14548 coordinate[0] += +delta[0]; 14549 coordinate[1] += +delta[1]; 14550 return coordinate; 14551} 14552 14553/** 14554 * Calculates the point closest to the passed coordinate on the passed circle. 14555 * 14556 * @param {Coordinate} coordinate The coordinate. 14557 * @param {import("./geom/Circle.js").default} circle The circle. 14558 * @return {Coordinate} Closest point on the circumference. 14559 */ 14560function closestOnCircle(coordinate, circle) { 14561 const r = circle.getRadius(); 14562 const center = circle.getCenter(); 14563 const x0 = center[0]; 14564 const y0 = center[1]; 14565 const x1 = coordinate[0]; 14566 const y1 = coordinate[1]; 14567 14568 let dx = x1 - x0; 14569 const dy = y1 - y0; 14570 if (dx === 0 && dy === 0) { 14571 dx = 1; 14572 } 14573 const d = Math.sqrt(dx * dx + dy * dy); 14574 14575 const x = x0 + (r * dx) / d; 14576 const y = y0 + (r * dy) / d; 14577 14578 return [x, y]; 14579} 14580 14581/** 14582 * Calculates the point closest to the passed coordinate on the passed segment. 14583 * This is the foot of the perpendicular of the coordinate to the segment when 14584 * the foot is on the segment, or the closest segment coordinate when the foot 14585 * is outside the segment. 14586 * 14587 * @param {Coordinate} coordinate The coordinate. 14588 * @param {Array<Coordinate>} segment The two coordinates 14589 * of the segment. 14590 * @return {Coordinate} The foot of the perpendicular of 14591 * the coordinate to the segment. 14592 */ 14593function closestOnSegment(coordinate, segment) { 14594 const x0 = coordinate[0]; 14595 const y0 = coordinate[1]; 14596 const start = segment[0]; 14597 const end = segment[1]; 14598 const x1 = start[0]; 14599 const y1 = start[1]; 14600 const x2 = end[0]; 14601 const y2 = end[1]; 14602 const dx = x2 - x1; 14603 const dy = y2 - y1; 14604 const along = 14605 dx === 0 && dy === 0 14606 ? 0 14607 : (dx * (x0 - x1) + dy * (y0 - y1)) / (dx * dx + dy * dy || 0); 14608 let x, y; 14609 if (along <= 0) { 14610 x = x1; 14611 y = y1; 14612 } else if (along >= 1) { 14613 x = x2; 14614 y = y2; 14615 } else { 14616 x = x1 + along * dx; 14617 y = y1 + along * dy; 14618 } 14619 return [x, y]; 14620} 14621 14622/**
14623 * Returns a {@link module:ol/coordinate~CoordinateFormat} function that can be 14624 * used to format 14625 * a {Coordinate} to a string. 14626 * 14627 * Example without specifying the fractional digits: 14628 * 14629 * import {createStringXY} from 'ol/coordinate'; 14630 * 14631 * const coord = [7.85, 47.983333]; 14632 * const stringifyFunc = createStringXY(); 14633 * const out = stringifyFunc(coord); 14634 * // out is now '8, 48' 14635 * 14636 * Example with explicitly specifying 2 fractional digits: 14637 * 14638 * import {createStringXY} from 'ol/coordinate'; 14639 * 14640 * const coord = [7.85, 47.983333]; 14641 * const stringifyFunc = createStringXY(2); 14642 * const out = stringifyFunc(coord); 14643 * // out is now '7.85, 47.98' 14644 * 14645 * @param {number} [fractionDigits] The number of digits to include 14646 * after the decimal point. Default is `0`. 14647 * @return {CoordinateFormat} Coordinate format. 14648 * @api 14649 */ 14650function createStringXY(fractionDigits) { 14651 return ( 14652 /** 14653 * @param {Coordinate} coordinate Coordinate. 14654 * @return {string} String XY. 14655 */ 14656 function (coordinate) { 14657 return toStringXY(coordinate, fractionDigits); 14658 } 14659 ); 14660} 14661 14662/** 14663 * @param {string} hemispheres Hemispheres. 14664 * @param {number} degrees Degrees. 14665 * @param {number} [fractionDigits] The number of digits to include 14666 * after the decimal point. Default is `0`. 14667 * @return {string} String. 14668 */ 14669function degreesToStringHDMS(hemispheres, degrees, fractionDigits) { 14670 const normalizedDegrees = modulo(degrees + 180, 360) - 180; 14671 const x = Math.abs(3600 * normalizedDegrees); 14672 const decimals = fractionDigits || 0; 14673 14674 let deg = Math.floor(x / 3600); 14675 let min = Math.floor((x - deg * 3600) / 60); 14676 let sec = toFixed(x - deg * 3600 - min * 60, decimals); 14677 14678 if (sec >= 60) { 14679 sec = 0; 14680 min += 1; 14681 } 14682 14683 if (min >= 60) { 14684 min = 0; 14685 deg += 1; 14686 } 14687 14688 let hdms = deg + '\u00b0'; 14689 if (min !== 0 || sec !== 0) { 14690 hdms += ' ' + padNumber(min, 2) + '\u2032'; 14691 } 14692 if (sec !== 0) { 14693 hdms += ' ' + padNumber(sec, 2, decimals) + '\u2033'; 14694 } 14695 if (normalizedDegrees !== 0) { 14696 hdms += ' ' + hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0); 14697 } 14698 14699 return hdms; 14700} 14701 14702/** 14703 * Transforms the given {@link module:ol/coordinate~Coordinate} to a string 14704 * using the given string template. The strings `{x}` and `{y}` in the template 14705 * will be replaced with the first and second coordinate values respectively. 14706 * 14707 * Example without specifying the fractional digits: 14708 * 14709 * import {format} from 'ol/coordinate'; 14710 * 14711 * const coord = [7.85, 47.983333]; 14712 * const template = 'Coordinate is ({x}|{y}).'; 14713 * const out = format(coord, template); 14714 * // out is now 'Coordinate is (8|48).' 14715 * 14716 * Example explicitly specifying the fractional digits: 14717 * 14718 * import {format} from 'ol/coordinate'; 14719 * 14720 * const coord = [7.85, 47.983333]; 14721 * const template = 'Coordinate is ({x}|{y}).'; 14722 * const out = format(coord, template, 2); 14723 * // out is now 'Coordinate is (7.85|47.98).' 14724 * 14725 * @param {Coordinate} coordinate Coordinate. 14726 * @param {string} template A template string with `{x}` and `{y}` placeholders 14727 * that will be replaced by first and second coordinate values. 14728 * @param {number} [fractionDigits] The number of digits to include 14729 * after the decimal point. Default is `0`. 14730 * @return {string} Formatted coordinate. 14731 * @api 14732 */ 14733function format(coordinate, template, fractionDigits) { 14734 if (coordinate) { 14735 return template 14736 .replace('{x}', coordinate[0].toFixed(fractionDigits)) 14737 .replace('{y}', coordinate[1].toFixed(fractionDigits)); 14738 } else { 14739 return ''; 14740 } 14741} 14742 14743/** 14744 * @param {Coordinate} coordinate1 First coordinate. 14745 * @param {Coordinate} coordinate2 Second coordinate. 14746 * @return {boolean} The two coordinates are equal. 14747 */ 14748function coordinate_equals(coordinate1, coordinate2) { 14749 let equals = true; 14750 for (let i = coordinate1.length - 1; i >= 0; --i) { 14751 if (coordinate1[i] != coordinate2[i]) { 14752 equals = false; 14753 break; 14754 } 14755 } 14756 return equals; 14757} 14758 14759/** 14760 * Rotate `coordinate` by `angle`. `coordinate` is modified in place and 14761 * returned by the function. 14762 * 14763 * Example: 14764 * 14765 * import {rotate} from 'ol/coordinate'; 14766 * 14767 * const coord = [7.85, 47.983333]; 14768 * const rotateRadians = Math.PI / 2; // 90 degrees 14769 * rotate(coord, rotateRadians); 14770 * // coord is now [-47.983333, 7.85] 14771 * 14772 * @param {Coordinate} coordinate Coordinate. 14773 * @param {number} angle Angle in radian. 14774 * @return {Coordinate} Coordinate. 14775 * @api 14776 */ 14777function rotate(coordinate, angle) {
14778 const cosAngle = Math.cos(angle); 14779 const sinAngle = Math.sin(angle); 14780 const x = coordinate[0] * cosAngle - coordinate[1] * sinAngle; 14781 const y = coordinate[1] * cosAngle + coordinate[0] * sinAngle; 14782 coordinate[0] = x; 14783 coordinate[1] = y; 14784 return coordinate; 14785} 14786 14787/** 14788 * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned 14789 * by the function. 14790 * 14791 * Example: 14792 * 14793 * import {scale as scaleCoordinate} from 'ol/coordinate'; 14794 * 14795 * const coord = [7.85, 47.983333]; 14796 * const scale = 1.2; 14797 * scaleCoordinate(coord, scale); 14798 * // coord is now [9.42, 57.5799996] 14799 * 14800 * @param {Coordinate} coordinate Coordinate. 14801 * @param {number} scale Scale factor. 14802 * @return {Coordinate} Coordinate. 14803 */ 14804function scale(coordinate, scale) { 14805 coordinate[0] *= scale; 14806 coordinate[1] *= scale; 14807 return coordinate; 14808} 14809 14810/** 14811 * @param {Coordinate} coord1 First coordinate. 14812 * @param {Coordinate} coord2 Second coordinate. 14813 * @return {number} Squared distance between coord1 and coord2. 14814 */ 14815function coordinate_squaredDistance(coord1, coord2) { 14816 const dx = coord1[0] - coord2[0]; 14817 const dy = coord1[1] - coord2[1]; 14818 return dx * dx + dy * dy; 14819} 14820 14821/** 14822 * @param {Coordinate} coord1 First coordinate. 14823 * @param {Coordinate} coord2 Second coordinate. 14824 * @return {number} Distance between coord1 and coord2. 14825 */ 14826function distance(coord1, coord2) { 14827 return Math.sqrt(coordinate_squaredDistance(coord1, coord2)); 14828} 14829 14830/** 14831 * Calculate the squared distance from a coordinate to a line segment. 14832 * 14833 * @param {Coordinate} coordinate Coordinate of the point. 14834 * @param {Array<Coordinate>} segment Line segment (2 14835 * coordinates). 14836 * @return {number} Squared distance from the point to the line segment. 14837 */ 14838function squaredDistanceToSegment(coordinate, segment) { 14839 return coordinate_squaredDistance(coordinate, closestOnSegment(coordinate, segment)); 14840} 14841 14842/** 14843 * Format a geographic coordinate with the hemisphere, degrees, minutes, and 14844 * seconds. 14845 * 14846 * Example without specifying fractional digits: 14847 * 14848 * import {toStringHDMS} from 'ol/coordinate'; 14849 * 14850 * const coord = [7.85, 47.983333]; 14851 * const out = toStringHDMS(coord); 14852 * // out is now '47° 58Ⲡ60ⳠN 7° 50Ⲡ60ⳠE' 14853 * 14854 * Example explicitly specifying 1 fractional digit: 14855 * 14856 * import {toStringHDMS} from 'ol/coordinate'; 14857 * 14858 * const coord = [7.85, 47.983333]; 14859 * const out = toStringHDMS(coord, 1); 14860 * // out is now '47° 58Ⲡ60.0ⳠN 7° 50Ⲡ60.0ⳠE' 14861 * 14862 * @param {Coordinate} coordinate Coordinate. 14863 * @param {number} [fractionDigits] The number of digits to include 14864 * after the decimal point. Default is `0`. 14865 * @return {string} Hemisphere, degrees, minutes and seconds. 14866 * @api 14867 */ 14868function toStringHDMS(coordinate, fractionDigits) { 14869 if (coordinate) { 14870 return ( 14871 degreesToStringHDMS('NS', coordinate[1], fractionDigits) + 14872 ' ' + 14873 degreesToStringHDMS('EW', coordinate[0], fractionDigits) 14874 ); 14875 } else { 14876 return ''; 14877 } 14878} 14879 14880/** 14881 * Format a coordinate as a comma delimited string. 14882 * 14883 * Example without specifying fractional digits: 14884 * 14885 * import {toStringXY} from 'ol/coordinate'; 14886 * 14887 * const coord = [7.85, 47.983333]; 14888 * const out = toStringXY(coord); 14889 * // out is now '8, 48' 14890 * 14891 * Example explicitly specifying 1 fractional digit: 14892 * 14893 * import {toStringXY} from 'ol/coordinate'; 14894 * 14895 * const coord = [7.85, 47.983333]; 14896 * const out = toStringXY(coord, 1); 14897 * // out is now '7.8, 48.0' 14898 * 14899 * @param {Coordinate} coordinate Coordinate. 14900 * @param {number} [fractionDigits] The number of digits to include 14901 * after the decimal point. Default is `0`. 14902 * @return {string} XY. 14903 * @api 14904 */ 14905function toStringXY(coordinate, fractionDigits) { 14906 return format(coordinate, '{x}, {y}', fractionDigits); 14907} 14908 14909/** 14910 * Modifies the provided coordinate in-place to be within the real world 14911 * extent. The lower projection extent boundary is inclusive, the upper one 14912 * exclusive. 14913 * 14914 * @param {Coordinate} coordinate Coordinate. 14915 * @param {import("./proj/Projection.js").default} projection Projection. 14916 * @return {Coordinate} The coordinate within the real world extent. 14917 */ 14918function coordinate_wrapX(coordinate, projection) { 14919 if (projection.canWrapX()) { 14920 const worldWidth = extent_getWidth(projection.getExtent()); 14921 const worldsAway = coordinate_getWorldsAway(coordinate, projection, worldWidth); 14922 if (worldsAway) { 14923 coordinate[0] -= worldsAway * worldWidth; 14924 } 14925 } 14926 return coordinate; 14927} 14928/** 14929 * @param {Coordinate} coordinate Coordinate. 14930 * @param {import("./proj/Projection.js").default} projection Projection. 14931 * @param {number} [sourceExtentWidth] Width of the source extent. 14932 * @return {number} Offset in world widths. 14933 */ 14934function coordinate_getWorldsAway(coordinate, projection, sourceExtentWidth) { 14935 const projectionExtent = projection.getExtent(); 14936 let worldsAway = 0; 14937 if ( 14938 projection.canWrapX() && 14939 (coordinate[0] < projectionExtent[0] || coordinate[0] > projectionExtent[2]) 14940 ) { 14941 sourceExtentWidth = sourceExtentWidth || extent_getWidth(projectionExtent); 14942 worldsAway = Math.floor( 14943 (coordinate[0] - projectionExtent[0]) / sourceExtentWidth 14944 ); 14945 } 14946 return worldsAway; 14947} 14948 14949;// CONCATENATED MODULE: ./node_modules/ol/sphere.js 14950/** 14951 * @module ol/sphere 14952 */ 14953 14954 14955/** 14956 * Object literal with options for the {@link getLength} or {@link getArea} 14957 * functions. 14958 * @typedef {Object} SphereMetricOptions 14959 * @property {import("./proj.js").ProjectionLike} [projection='EPSG:3857'] 14960 * Projection of the geometry. By default, the geometry is assumed to be in 14961 * Web Mercator. 14962 * @property {number} [radius=6371008.8] Sphere radius. By default, the 14963 * [mean Earth radius](https://en.wikipedia.org/wiki/Earth_radius#Mean_radius) 14964 * for the WGS84 ellipsoid is used. 14965 */ 14966 14967/** 14968 * The mean Earth radius (1/3 * (2a + b)) for the WGS84 ellipsoid. 14969 * https://en.wikipedia.org/wiki/Earth_radius#Mean_radius 14970 * @type {number} 14971 */ 14972const DEFAULT_RADIUS = 6371008.8; 14973 14974/** 14975 * Get the great circle distance (in meters) between two geographic coordinates. 14976 * @param {Array} c1 Starting coordinate. 14977 * @param {Array} c2 Ending coordinate. 14978 * @param {number} [radius] The sphere radius to use. Defaults to the Earth's 14979 * mean radius using the WGS84 ellipsoid. 14980 * @return {number} The great circle distance between the points (in meters). 14981 * @api 14982 */ 14983function getDistance(c1, c2, radius) {
vendor: 7,264 bytes, lines 14984-15196
14984 radius = radius || DEFAULT_RADIUS; 14985 const lat1 = math_toRadians(c1[1]); 14986 const lat2 = math_toRadians(c2[1]); 14987 const deltaLatBy2 = (lat2 - lat1) / 2; 14988 const deltaLonBy2 = math_toRadians(c2[0] - c1[0]) / 2; 14989 const a = 14990 Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + 14991 Math.sin(deltaLonBy2) * 14992 Math.sin(deltaLonBy2) * 14993 Math.cos(lat1) * 14994 Math.cos(lat2); 14995 return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 14996} 14997 14998/** 14999 * Get the cumulative great circle length of linestring coordinates (geographic). 15000 * @param {Array} coordinates Linestring coordinates. 15001 * @param {number} radius The sphere radius to use. 15002 * @return {number} The length (in meters). 15003 */ 15004function getLengthInternal(coordinates, radius) { 15005 let length = 0; 15006 for (let i = 0, ii = coordinates.length; i < ii - 1; ++i) { 15007 length += getDistance(coordinates[i], coordinates[i + 1], radius); 15008 } 15009 return length; 15010} 15011 15012/** 15013 * Get the spherical length of a geometry. This length is the sum of the 15014 * great circle distances between coordinates. For polygons, the length is 15015 * the sum of all rings. For points, the length is zero. For multi-part 15016 * geometries, the length is the sum of the length of each part. 15017 * @param {import("./geom/Geometry.js").default} geometry A geometry. 15018 * @param {SphereMetricOptions} [options] Options for the 15019 * length calculation. By default, geometries are assumed to be in 'EPSG:3857'. 15020 * You can change this by providing a `projection` option. 15021 * @return {number} The spherical length (in meters). 15022 * @api 15023 */ 15024function getLength(geometry, options) { 15025 options = options || {}; 15026 const radius = options.radius || DEFAULT_RADIUS; 15027 const projection = options.projection || 'EPSG:3857'; 15028 const type = geometry.getType(); 15029 if (type !== 'GeometryCollection') { 15030 geometry = geometry.clone().transform(projection, 'EPSG:4326'); 15031 } 15032 let length = 0; 15033 let coordinates, coords, i, ii, j, jj; 15034 switch (type) { 15035 case 'Point': 15036 case 'MultiPoint': { 15037 break; 15038 } 15039 case 'LineString': 15040 case 'LinearRing': { 15041 coordinates = /** @type {import("./geom/SimpleGeometry.js").default} */ ( 15042 geometry 15043 ).getCoordinates(); 15044 length = getLengthInternal(coordinates, radius); 15045 break; 15046 } 15047 case 'MultiLineString': 15048 case 'Polygon': { 15049 coordinates = /** @type {import("./geom/SimpleGeometry.js").default} */ ( 15050 geometry 15051 ).getCoordinates(); 15052 for (i = 0, ii = coordinates.length; i < ii; ++i) { 15053 length += getLengthInternal(coordinates[i], radius); 15054 } 15055 break; 15056 } 15057 case 'MultiPolygon': { 15058 coordinates = /** @type {import("./geom/SimpleGeometry.js").default} */ ( 15059 geometry 15060 ).getCoordinates(); 15061 for (i = 0, ii = coordinates.length; i < ii; ++i) { 15062 coords = coordinates[i]; 15063 for (j = 0, jj = coords.length; j < jj; ++j) { 15064 length += getLengthInternal(coords[j], radius); 15065 } 15066 } 15067 break; 15068 } 15069 case 'GeometryCollection': { 15070 const geometries = 15071 /** @type {import("./geom/GeometryCollection.js").default} */ ( 15072 geometry 15073 ).getGeometries(); 15074 for (i = 0, ii = geometries.length; i < ii; ++i) { 15075 length += getLength(geometries[i], options); 15076 } 15077 break; 15078 } 15079 default: { 15080 throw new Error('Unsupported geometry type: ' + type); 15081 } 15082 } 15083 return length; 15084} 15085 15086/** 15087 * Returns the spherical area for a list of coordinates. 15088 * 15089 * [Reference](https://trs.jpl.nasa.gov/handle/2014/40409) 15090 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for 15091 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion 15092 * Laboratory, Pasadena, CA, June 2007 15093 * 15094 * @param {Array<import("./coordinate.js").Coordinate>} coordinates List of coordinates of a linear 15095 * ring. If the ring is oriented clockwise, the area will be positive, 15096 * otherwise it will be negative. 15097 * @param {number} radius The sphere radius. 15098 * @return {number} Area (in square meters). 15099 */ 15100function getAreaInternal(coordinates, radius) { 15101 let area = 0; 15102 const len = coordinates.length; 15103 let x1 = coordinates[len - 1][0]; 15104 let y1 = coordinates[len - 1][1]; 15105 for (let i = 0; i < len; i++) { 15106 const x2 = coordinates[i][0]; 15107 const y2 = coordinates[i][1]; 15108 area += 15109 toRadians(x2 - x1) * 15110 (2 + Math.sin(toRadians(y1)) + Math.sin(toRadians(y2))); 15111 x1 = x2; 15112 y1 = y2; 15113 } 15114 return (area * radius * radius) / 2.0; 15115} 15116 15117/** 15118 * Get the spherical area of a geometry. This is the area (in meters) assuming 15119 * that polygon edges are segments of great circles on a sphere. 15120 * @param {import("./geom/Geometry.js").default} geometry A geometry. 15121 * @param {SphereMetricOptions} [options] Options for the area 15122 * calculation. By default, geometries are assumed to be in 'EPSG:3857'. 15123 * You can change this by providing a `projection` option. 15124 * @return {number} The spherical area (in square meters). 15125 * @api 15126 */ 15127function sphere_getArea(geometry, options) { 15128 options = options || {}; 15129 const radius = options.radius || DEFAULT_RADIUS; 15130 const projection = options.projection || 'EPSG:3857'; 15131 const type = geometry.getType(); 15132 if (type !== 'GeometryCollection') { 15133 geometry = geometry.clone().transform(projection, 'EPSG:4326'); 15134 } 15135 let area = 0; 15136 let coordinates, coords, i, ii, j, jj; 15137 switch (type) { 15138 case 'Point': 15139 case 'MultiPoint': 15140 case 'LineString': 15141 case 'MultiLineString': 15142 case 'LinearRing': { 15143 break; 15144 } 15145 case 'Polygon': { 15146 coordinates = /** @type {import("./geom/Polygon.js").default} */ ( 15147 geometry 15148 ).getCoordinates(); 15149 area = Math.abs(getAreaInternal(coordinates[0], radius)); 15150 for (i = 1, ii = coordinates.length; i < ii; ++i) { 15151 area -= Math.abs(getAreaInternal(coordinates[i], radius)); 15152 } 15153 break; 15154 } 15155 case 'MultiPolygon': { 15156 coordinates = /** @type {import("./geom/SimpleGeometry.js").default} */ ( 15157 geometry 15158 ).getCoordinates(); 15159 for (i = 0, ii = coordinates.length; i < ii; ++i) { 15160 coords = coordinates[i]; 15161 area += Math.abs(getAreaInternal(coords[0], radius)); 15162 for (j = 1, jj = coords.length; j < jj; ++j) { 15163 area -= Math.abs(getAreaInternal(coords[j], radius)); 15164 } 15165 } 15166 break; 15167 } 15168 case 'GeometryCollection': { 15169 const geometries = 15170 /** @type {import("./geom/GeometryCollection.js").default} */ ( 15171 geometry 15172 ).getGeometries(); 15173 for (i = 0, ii = geometries.length; i < ii; ++i) { 15174 area += sphere_getArea(geometries[i], options); 15175 } 15176 break; 15177 } 15178 default: { 15179 throw new Error('Unsupported geometry type: ' + type); 15180 } 15181 } 15182 return area; 15183} 15184 15185/** 15186 * Returns the coordinate at the given distance and bearing from `c1`. 15187 * 15188 * @param {import("./coordinate.js").Coordinate} c1 The origin point (`[lon, lat]` in degrees). 15189 * @param {number} distance The great-circle distance between the origin 15190 * point and the target point. 15191 * @param {number} bearing The bearing (in radians). 15192 * @param {number} [radius] The sphere radius to use. Defaults to the Earth's 15193 * mean radius using the WGS84 ellipsoid. 15194 * @return {import("./coordinate.js").Coordinate} The target point. 15195 */ 15196function offset(c1, distance, bearing, radius) {
15197 radius = radius || DEFAULT_RADIUS; 15198 const lat1 = toRadians(c1[1]); 15199 const lon1 = toRadians(c1[0]); 15200 const dByR = distance / radius; 15201 const lat = Math.asin( 15202 Math.sin(lat1) * Math.cos(dByR) + 15203 Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing) 15204 ); 15205 const lon = 15206 lon1 + 15207 Math.atan2( 15208 Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), 15209 Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat) 15210 ); 15211 return [toDegrees(lon), toDegrees(lat)]; 15212} 15213 15214;// CONCATENATED MODULE: ./node_modules/ol/proj.js 15215/** 15216 * @module ol/proj 15217 */ 15218 15219/** 15220 * The ol/proj module stores: 15221 * * a list of {@link module:ol/proj/Projection~Projection} 15222 * objects, one for each projection supported by the application 15223 * * a list of transform functions needed to convert coordinates in one projection 15224 * into another. 15225 * 15226 * The static functions are the methods used to maintain these. 15227 * Each transform function can handle not only simple coordinate pairs, but also 15228 * large arrays of coordinates such as vector geometries. 15229 * 15230 * When loaded, the library adds projection objects for EPSG:4326 (WGS84 15231 * geographic coordinates) and EPSG:3857 (Web or Spherical Mercator, as used 15232 * for example by Bing Maps or OpenStreetMap), together with the relevant 15233 * transform functions. 15234 * 15235 * Additional transforms may be added by using the http://proj4js.org/ 15236 * library (version 2.2 or later). You can use the full build supplied by 15237 * Proj4js, or create a custom build to support those projections you need; see 15238 * the Proj4js website for how to do this. You also need the Proj4js definitions 15239 * for the required projections. These definitions can be obtained from 15240 * https://epsg.io/, and are a JS function, so can be loaded in a script 15241 * tag (as in the examples) or pasted into your application. 15242 * 15243 * After all required projection definitions are added to proj4's registry (by 15244 * using `proj4.defs()`), simply call `register(proj4)` from the `ol/proj/proj4` 15245 * package. Existing transforms are not changed by this function. See 15246 * examples/wms-image-custom-proj for an example of this. 15247 * 15248 * Additional projection definitions can be registered with `proj4.defs()` any 15249 * time. Just make sure to call `register(proj4)` again; for example, with user-supplied data where you don't 15250 * know in advance what projections are needed, you can initially load minimal 15251 * support and then load whichever are requested. 15252 * 15253 * Note that Proj4js does not support projection extents. If you want to add 15254 * one for creating default tile grids, you can add it after the Projection 15255 * object has been created with `setExtent`, for example, 15256 * `get('EPSG:1234').setExtent(extent)`. 15257 * 15258 * In addition to Proj4js support, any transform functions can be added with 15259 * {@link module:ol/proj.addCoordinateTransforms}. To use this, you must first create 15260 * a {@link module:ol/proj/Projection~Projection} object for the new projection and add it with 15261 * {@link module:ol/proj.addProjection}. You can then add the forward and inverse 15262 * functions with {@link module:ol/proj.addCoordinateTransforms}. See 15263 * examples/wms-custom-proj for an example of this. 15264 *
15265 * Note that if no transforms are needed and you only need to define the 15266 * projection, just add a {@link module:ol/proj/Projection~Projection} with 15267 * {@link module:ol/proj.addProjection}. See examples/wms-no-proj for an example of 15268 * this. 15269 */ 15270 15271 15272 15273 15274 15275 15276 15277 15278 15279 15280 15281/** 15282 * A projection as {@link module:ol/proj/Projection~Projection}, SRS identifier 15283 * string or undefined. 15284 * @typedef {Projection|string|undefined} ProjectionLike 15285 * @api 15286 */ 15287 15288/** 15289 * A transform function accepts an array of input coordinate values, an optional 15290 * output array, and an optional dimension (default should be 2). The function 15291 * transforms the input coordinate values, populates the output array, and 15292 * returns the output array. 15293 * 15294 * @typedef {function(Array<number>, Array<number>=, number=): Array<number>} TransformFunction 15295 * @api 15296 */ 15297 15298 15299 15300 15301 15302let showCoordinateWarning = true; 15303 15304/** 15305 * @param {boolean} [disable = true] Disable console info about `useGeographic()` 15306 */ 15307function disableCoordinateWarning(disable) { 15308 const hide = disable === undefined ? true : disable; 15309 showCoordinateWarning = !hide; 15310} 15311 15312/** 15313 * @param {Array<number>} input Input coordinate array. 15314 * @param {Array<number>} [output] Output array of coordinate values. 15315 * @param {number} [dimension] Dimension. 15316 * @return {Array<number>} Output coordinate array (new array, same coordinate 15317 * values). 15318 */ 15319function cloneTransform(input, output, dimension) { 15320 if (output !== undefined) { 15321 for (let i = 0, ii = input.length; i < ii; ++i) { 15322 output[i] = input[i]; 15323 } 15324 output = output; 15325 } else { 15326 output = input.slice(); 15327 } 15328 return output; 15329} 15330 15331/** 15332 * @param {Array<number>} input Input coordinate array. 15333 * @param {Array<number>} [output] Output array of coordinate values. 15334 * @param {number} [dimension] Dimension. 15335 * @return {Array<number>} Input coordinate array (same array as input). 15336 */ 15337function identityTransform(input, output, dimension) { 15338 if (output !== undefined && input !== output) { 15339 for (let i = 0, ii = input.length; i < ii; ++i) { 15340 output[i] = input[i]; 15341 } 15342 input = output; 15343 } 15344 return input; 15345} 15346 15347/** 15348 * Add a Projection object to the list of supported projections that can be 15349 * looked up by their code. 15350 * 15351 * @param {Projection} projection Projection instance. 15352 * @api 15353 */ 15354function addProjection(projection) { 15355 add(projection.getCode(), projection); 15356 transforms_add(projection, projection, cloneTransform); 15357} 15358 15359/** 15360 * @param {Array<Projection>} projections Projections. 15361 */ 15362function addProjections(projections) { 15363 projections.forEach(addProjection); 15364} 15365 15366/** 15367 * Fetches a Projection object for the code specified. 15368 * 15369 * @param {ProjectionLike} projectionLike Either a code string which is 15370 * a combination of authority and identifier such as "EPSG:4326", or an 15371 * existing projection object, or undefined. 15372 * @return {Projection|null} Projection object, or null if not in list. 15373 * @api 15374 */ 15375function proj_get(projectionLike) { 15376 return typeof projectionLike === 'string' 15377 ? get(/** @type {string} */ (projectionLike)) 15378 : /** @type {Projection} */ (projectionLike) || null; 15379} 15380 15381/** 15382 * Get the resolution of the point in degrees or distance units. 15383 * For projections with degrees as the unit this will simply return the 15384 * provided resolution. For other projections the point resolution is 15385 * by default estimated by transforming the `point` pixel to EPSG:4326, 15386 * measuring its width and height on the normal sphere, 15387 * and taking the average of the width and height. 15388 * A custom function can be provided for a specific projection, either 15389 * by setting the `getPointResolution` option in the 15390 * {@link module:ol/proj/Projection~Projection} constructor or by using 15391 * {@link module:ol/proj/Projection~Projection#setGetPointResolution} to change an existing 15392 * projection object. 15393 * @param {ProjectionLike} projection The projection. 15394 * @param {number} resolution Nominal resolution in projection units. 15395 * @param {import("./coordinate.js").Coordinate} point Point to find adjusted resolution at. 15396 * @param {import("./proj/Units.js").Units} [units] Units to get the point resolution in. 15397 * Default is the projection's units. 15398 * @return {number} Point resolution. 15399 * @api 15400 */ 15401function getPointResolution(projection, resolution, point, units) { 15402 projection = proj_get(projection); 15403 let pointResolution; 15404 const getter = projection.getPointResolutionFunc(); 15405 if (getter) { 15406 pointResolution = getter(resolution, point); 15407 if (units && units !== projection.getUnits()) { 15408 const metersPerUnit = projection.getMetersPerUnit(); 15409 if (metersPerUnit) { 15410 pointResolution =
15411 (pointResolution * metersPerUnit) / Units_METERS_PER_UNIT[units]; 15412 } 15413 } 15414 } else { 15415 const projUnits = projection.getUnits(); 15416 if ((projUnits == 'degrees' && !units) || units == 'degrees') { 15417 pointResolution = resolution; 15418 } else { 15419 // Estimate point resolution by transforming the center pixel to EPSG:4326, 15420 // measuring its width and height on the normal sphere, and taking the 15421 // average of the width and height. 15422 const toEPSG4326 = getTransformFromProjections( 15423 projection, 15424 proj_get('EPSG:4326') 15425 ); 15426 if (toEPSG4326 === identityTransform && projUnits !== 'degrees') { 15427 // no transform is available 15428 pointResolution = resolution * projection.getMetersPerUnit(); 15429 } else { 15430 let vertices = [ 15431 point[0] - resolution / 2, 15432 point[1], 15433 point[0] + resolution / 2, 15434 point[1], 15435 point[0], 15436 point[1] - resolution / 2, 15437 point[0], 15438 point[1] + resolution / 2, 15439 ]; 15440 vertices = toEPSG4326(vertices, vertices, 2); 15441 const width = getDistance(vertices.slice(0, 2), vertices.slice(2, 4)); 15442 const height = getDistance(vertices.slice(4, 6), vertices.slice(6, 8)); 15443 pointResolution = (width + height) / 2; 15444 } 15445 const metersPerUnit = units 15446 ? Units_METERS_PER_UNIT[units] 15447 : projection.getMetersPerUnit(); 15448 if (metersPerUnit !== undefined) { 15449 pointResolution /= metersPerUnit; 15450 } 15451 } 15452 } 15453 return pointResolution; 15454} 15455 15456/** 15457 * Registers transformation functions that don't alter coordinates. Those allow 15458 * to transform between projections with equal meaning. 15459 * 15460 * @param {Array<Projection>} projections Projections. 15461 * @api 15462 */ 15463function addEquivalentProjections(projections) { 15464 addProjections(projections); 15465 projections.forEach(function (source) { 15466 projections.forEach(function (destination) { 15467 if (source !== destination) { 15468 transforms_add(source, destination, cloneTransform); 15469 } 15470 }); 15471 }); 15472} 15473 15474/** 15475 * Registers transformation functions to convert coordinates in any projection 15476 * in projection1 to any projection in projection2. 15477 * 15478 * @param {Array<Projection>} projections1 Projections with equal 15479 * meaning. 15480 * @param {Array<Projection>} projections2 Projections with equal 15481 * meaning. 15482 * @param {TransformFunction} forwardTransform Transformation from any 15483 * projection in projection1 to any projection in projection2. 15484 * @param {TransformFunction} inverseTransform Transform from any projection 15485 * in projection2 to any projection in projection1.. 15486 */ 15487function addEquivalentTransforms( 15488 projections1, 15489 projections2, 15490 forwardTransform, 15491 inverseTransform 15492) { 15493 projections1.forEach(function (projection1) { 15494 projections2.forEach(function (projection2) { 15495 transforms_add(projection1, projection2, forwardTransform); 15496 transforms_add(projection2, projection1, inverseTransform); 15497 }); 15498 }); 15499} 15500 15501/** 15502 * Clear all cached projections and transforms. 15503 */ 15504function clearAllProjections() { 15505 clearProj(); 15506 clearTransformFuncs(); 15507} 15508 15509/** 15510 * @param {Projection|string|undefined} projection Projection. 15511 * @param {string} defaultCode Default code. 15512 * @return {Projection} Projection. 15513 */ 15514function createProjection(projection, defaultCode) { 15515 if (!projection) { 15516 return proj_get(defaultCode); 15517 } else if (typeof projection === 'string') { 15518 return proj_get(projection); 15519 } else { 15520 return /** @type {Projection} */ (projection); 15521 } 15522} 15523 15524/** 15525 * Creates a {@link module:ol/proj~TransformFunction} from a simple 2D coordinate transform 15526 * function. 15527 * @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} coordTransform Coordinate 15528 * transform. 15529 * @return {TransformFunction} Transform function. 15530 */ 15531function createTransformFromCoordinateTransform(coordTransform) { 15532 return ( 15533 /** 15534 * @param {Array<number>} input Input. 15535 * @param {Array<number>} [output] Output. 15536 * @param {number} [dimension] Dimension. 15537 * @return {Array<number>} Output. 15538 */ 15539 function (input, output, dimension) { 15540 const length = input.length; 15541 dimension = dimension !== undefined ? dimension : 2; 15542 output = output !== undefined ? output : new Array(length); 15543 for (let i = 0; i < length; i += dimension) { 15544 const point = coordTransform(input.slice(i, i + dimension)); 15545 const pointLength = point.length; 15546 for (let j = 0, jj = dimension; j < jj; ++j) { 15547 output[i + j] = j >= pointLength ? input[i + j] : point[j]; 15548 } 15549 } 15550 return output; 15551 } 15552 ); 15553} 15554 15555/** 15556 * Registers coordinate transform functions to convert coordinates between the 15557 * source projection and the destination projection. 15558 * The forward and inverse functions convert coordinate pairs; this function 15559 * converts these into the functions used internally which also handle 15560 * extents and coordinate arrays. 15561 * 15562 * @param {ProjectionLike} source Source projection. 15563 * @param {ProjectionLike} destination Destination projection. 15564 * @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} forward The forward transform 15565 * function (that is, from the source projection to the destination
15566 * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns 15567 * the transformed {@link module:ol/coordinate~Coordinate}. 15568 * @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} inverse The inverse transform 15569 * function (that is, from the destination projection to the source 15570 * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns 15571 * the transformed {@link module:ol/coordinate~Coordinate}. If the transform function can only 15572 * transform less dimensions than the input coordinate, it is supposeed to return a coordinate 15573 * with only the length it can transform. The other dimensions will be taken unchanged from the 15574 * source. 15575 * @api 15576 */ 15577function addCoordinateTransforms(source, destination, forward, inverse) { 15578 const sourceProj = proj_get(source); 15579 const destProj = proj_get(destination); 15580 addTransformFunc( 15581 sourceProj, 15582 destProj, 15583 createTransformFromCoordinateTransform(forward) 15584 ); 15585 addTransformFunc( 15586 destProj, 15587 sourceProj, 15588 createTransformFromCoordinateTransform(inverse) 15589 ); 15590} 15591 15592/** 15593 * Transforms a coordinate from longitude/latitude to a different projection. 15594 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate as longitude and latitude, i.e. 15595 * an array with longitude as 1st and latitude as 2nd element. 15596 * @param {ProjectionLike} [projection] Target projection. The 15597 * default is Web Mercator, i.e. 'EPSG:3857'. 15598 * @return {import("./coordinate.js").Coordinate} Coordinate projected to the target projection. 15599 * @api 15600 */ 15601function fromLonLat(coordinate, projection) { 15602 disableCoordinateWarning(); 15603 return transform( 15604 coordinate, 15605 'EPSG:4326', 15606 projection !== undefined ? projection : 'EPSG:3857' 15607 ); 15608} 15609 15610/** 15611 * Transforms a coordinate to longitude/latitude. 15612 * @param {import("./coordinate.js").Coordinate} coordinate Projected coordinate. 15613 * @param {ProjectionLike} [projection] Projection of the coordinate. 15614 * The default is Web Mercator, i.e. 'EPSG:3857'. 15615 * @return {import("./coordinate.js").Coordinate} Coordinate as longitude and latitude, i.e. an array 15616 * with longitude as 1st and latitude as 2nd element. 15617 * @api 15618 */ 15619function toLonLat(coordinate, projection) { 15620 const lonLat = transform( 15621 coordinate, 15622 projection !== undefined ? projection : 'EPSG:3857', 15623 'EPSG:4326' 15624 ); 15625 const lon = lonLat[0]; 15626 if (lon < -180 || lon > 180) { 15627 lonLat[0] = math_modulo(lon + 180, 360) - 180; 15628 } 15629 return lonLat; 15630} 15631 15632/** 15633 * Checks if two projections are the same, that is every coordinate in one 15634 * projection does represent the same geographic point as the same coordinate in 15635 * the other projection. 15636 * 15637 * @param {Projection} projection1 Projection 1. 15638 * @param {Projection} projection2 Projection 2. 15639 * @return {boolean} Equivalent. 15640 * @api 15641 */ 15642function equivalent(projection1, projection2) { 15643 if (projection1 === projection2) { 15644 return true; 15645 } 15646 const equalUnits = projection1.getUnits() === projection2.getUnits(); 15647 if (projection1.getCode() === projection2.getCode()) { 15648 return equalUnits; 15649 } else { 15650 const transformFunc = getTransformFromProjections(projection1, projection2); 15651 return transformFunc === cloneTransform && equalUnits; 15652 } 15653} 15654 15655/** 15656 * Searches in the list of transform functions for the function for converting 15657 * coordinates from the source projection to the destination projection. 15658 * 15659 * @param {Projection} sourceProjection Source Projection object. 15660 * @param {Projection} destinationProjection Destination Projection 15661 * object. 15662 * @return {TransformFunction} Transform function. 15663 */ 15664function getTransformFromProjections( 15665 sourceProjection, 15666 destinationProjection 15667) { 15668 const sourceCode = sourceProjection.getCode(); 15669 const destinationCode = destinationProjection.getCode(); 15670 let transformFunc = transforms_get(sourceCode, destinationCode); 15671 if (!transformFunc) { 15672 transformFunc = identityTransform; 15673 } 15674 return transformFunc; 15675} 15676 15677/** 15678 * Given the projection-like objects, searches for a transformation 15679 * function to convert a coordinates array from the source projection to the 15680 * destination projection. 15681 * 15682 * @param {ProjectionLike} source Source. 15683 * @param {ProjectionLike} destination Destination. 15684 * @return {TransformFunction} Transform function. 15685 * @api 15686 */ 15687function getTransform(source, destination) { 15688 const sourceProjection = proj_get(source); 15689 const destinationProjection = proj_get(destination); 15690 return getTransformFromProjections(sourceProjection, destinationProjection); 15691} 15692 15693/** 15694 * Transforms a coordinate from source projection to destination projection. 15695 * This returns a new coordinate (and does not modify the original). 15696 * 15697 * See {@link module:ol/proj.transformExtent} for extent transformation. 15698 * See the transform method of {@link module:ol/geom/Geometry~Geometry} and its 15699 * subclasses for geometry transforms. 15700 * 15701 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. 15702 * @param {ProjectionLike} source Source projection-like. 15703 * @param {ProjectionLike} destination Destination projection-like. 15704 * @return {import("./coordinate.js").Coordinate} Coordinate. 15705 * @api 15706 */ 15707function transform(coordinate, source, destination) { 15708 const transformFunc = getTransform(source, destination);
15709 return transformFunc(coordinate, undefined, coordinate.length); 15710} 15711 15712/** 15713 * Transforms an extent from source projection to destination projection. This 15714 * returns a new extent (and does not modify the original). 15715 * 15716 * @param {import("./extent.js").Extent} extent The extent to transform. 15717 * @param {ProjectionLike} source Source projection-like. 15718 * @param {ProjectionLike} destination Destination projection-like. 15719 * @param {number} [stops] Number of stops per side used for the transform. 15720 * By default only the corners are used. 15721 * @return {import("./extent.js").Extent} The transformed extent. 15722 * @api 15723 */ 15724function proj_transformExtent(extent, source, destination, stops) { 15725 const transformFunc = getTransform(source, destination); 15726 return applyTransform(extent, transformFunc, undefined, stops); 15727} 15728 15729/** 15730 * Transforms the given point to the destination projection. 15731 * 15732 * @param {import("./coordinate.js").Coordinate} point Point. 15733 * @param {Projection} sourceProjection Source projection. 15734 * @param {Projection} destinationProjection Destination projection. 15735 * @return {import("./coordinate.js").Coordinate} Point. 15736 */ 15737function transformWithProjections( 15738 point, 15739 sourceProjection, 15740 destinationProjection 15741) { 15742 const transformFunc = getTransformFromProjections( 15743 sourceProjection, 15744 destinationProjection 15745 ); 15746 return transformFunc(point); 15747} 15748 15749/** 15750 * @type {Projection|null} 15751 */ 15752let userProjection = null; 15753 15754/** 15755 * Set the projection for coordinates supplied from and returned by API methods. 15756 * This includes all API methods except for those interacting with tile grids. 15757 * @param {ProjectionLike} projection The user projection. 15758 * @api 15759 */ 15760function setUserProjection(projection) { 15761 userProjection = proj_get(projection); 15762} 15763 15764/** 15765 * Clear the user projection if set. 15766 * @api 15767 */ 15768function clearUserProjection() { 15769 userProjection = null; 15770} 15771 15772/** 15773 * Get the projection for coordinates supplied from and returned by API methods. 15774 * Note that this method is not yet a part of the stable API. Support for user 15775 * projections is not yet complete and should be considered experimental. 15776 * @return {Projection|null} The user projection (or null if not set). 15777 * @api 15778 */ 15779function getUserProjection() { 15780 return userProjection; 15781} 15782 15783/** 15784 * Use geographic coordinates (WGS-84 datum) in API methods. This includes all API 15785 * methods except for those interacting with tile grids. 15786 * @api 15787 */ 15788function useGeographic() { 15789 setUserProjection('EPSG:4326'); 15790} 15791 15792/** 15793 * Return a coordinate transformed into the user projection. If no user projection 15794 * is set, the original coordinate is returned. 15795 * @param {Array<number>} coordinate Input coordinate. 15796 * @param {ProjectionLike} sourceProjection The input coordinate projection. 15797 * @return {Array<number>} The input coordinate in the user projection. 15798 */ 15799function toUserCoordinate(coordinate, sourceProjection) { 15800 if (!userProjection) { 15801 return coordinate; 15802 } 15803 return transform(coordinate, sourceProjection, userProjection); 15804} 15805 15806/** 15807 * Return a coordinate transformed from the user projection. If no user projection 15808 * is set, the original coordinate is returned. 15809 * @param {Array<number>} coordinate Input coordinate. 15810 * @param {ProjectionLike} destProjection The destination projection. 15811 * @return {Array<number>} The input coordinate transformed. 15812 */ 15813function fromUserCoordinate(coordinate, destProjection) { 15814 if (!userProjection) { 15815 if ( 15816 showCoordinateWarning && 15817 !coordinate_equals(coordinate, [0, 0]) && 15818 coordinate[0] >= -180 && 15819 coordinate[0] <= 180 && 15820 coordinate[1] >= -90 && 15821 coordinate[1] <= 90 15822 ) { 15823 showCoordinateWarning = false; 15824 // eslint-disable-next-line no-console 15825 console.warn( 15826 'Call useGeographic() from ol/proj once to work with [longitude, latitude] coordinates.' 15827 ); 15828 } 15829 return coordinate; 15830 } 15831 return transform(coordinate, userProjection, destProjection); 15832} 15833 15834/** 15835 * Return an extent transformed into the user projection. If no user projection 15836 * is set, the original extent is returned. 15837 * @param {import("./extent.js").Extent} extent Input extent. 15838 * @param {ProjectionLike} sourceProjection The input extent projection. 15839 * @return {import("./extent.js").Extent} The input extent in the user projection. 15840 */ 15841function proj_toUserExtent(extent, sourceProjection) { 15842 if (!userProjection) { 15843 return extent; 15844 } 15845 return proj_transformExtent(extent, sourceProjection, userProjection); 15846} 15847 15848/** 15849 * Return an extent transformed from the user projection. If no user projection 15850 * is set, the original extent is returned. 15851 * @param {import("./extent.js").Extent} extent Input extent. 15852 * @param {ProjectionLike} destProjection The destination projection. 15853 * @return {import("./extent.js").Extent} The input extent transformed. 15854 */ 15855function proj_fromUserExtent(extent, destProjection) { 15856 if (!userProjection) { 15857 return extent; 15858 } 15859 return proj_transformExtent(extent, userProjection, destProjection); 15860} 15861 15862/** 15863 * Return the resolution in user projection units per pixel. If no user projection 15864 * is set, or source or user projection are missing units, the original resolution 15865 * is returned. 15866 * @param {number} resolution Resolution in input projection units per pixel. 15867 * @param {ProjectionLike} sourceProjection The input projection. 15868 * @return {number} Resolution in user projection units per pixel. 15869 */ 15870function toUserResolution(resolution, sourceProjection) { 15871 if (!userProjection) { 15872 return resolution; 15873 } 15874 const sourceUnits = proj_get(sourceProjection).getUnits(); 15875 const userUnits = userProjection.getUnits(); 15876 return sourceUnits && userUnits
15877 ? (resolution * Units_METERS_PER_UNIT[sourceUnits]) / Units_METERS_PER_UNIT[userUnits] 15878 : resolution; 15879} 15880 15881/** 15882 * Return the resolution in user projection units per pixel. If no user projection 15883 * is set, or source or user projection are missing units, the original resolution 15884 * is returned. 15885 * @param {number} resolution Resolution in user projection units per pixel. 15886 * @param {ProjectionLike} destProjection The destination projection. 15887 * @return {number} Resolution in destination projection units per pixel. 15888 */ 15889function proj_fromUserResolution(resolution, destProjection) { 15890 if (!userProjection) { 15891 return resolution; 15892 } 15893 const sourceUnits = proj_get(destProjection).getUnits(); 15894 const userUnits = userProjection.getUnits(); 15895 return sourceUnits && userUnits 15896 ? (resolution * METERS_PER_UNIT[userUnits]) / METERS_PER_UNIT[sourceUnits] 15897 : resolution; 15898} 15899 15900/** 15901 * Creates a safe coordinate transform function from a coordinate transform function. 15902 * "Safe" means that it can handle wrapping of x-coordinates for global projections, 15903 * and that coordinates exceeding the source projection validity extent's range will be 15904 * clamped to the validity range. 15905 * @param {Projection} sourceProj Source projection. 15906 * @param {Projection} destProj Destination projection. 15907 * @param {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} transform Transform function (source to destiation). 15908 * @return {function(import("./coordinate.js").Coordinate): import("./coordinate.js").Coordinate} Safe transform function (source to destiation). 15909 */ 15910function createSafeCoordinateTransform(sourceProj, destProj, transform) { 15911 return function (coord) { 15912 let transformed, worldsAway; 15913 if (sourceProj.canWrapX()) { 15914 const sourceExtent = sourceProj.getExtent(); 15915 const sourceExtentWidth = getWidth(sourceExtent); 15916 coord = coord.slice(0); 15917 worldsAway = getWorldsAway(coord, sourceProj, sourceExtentWidth); 15918 if (worldsAway) { 15919 // Move x to the real world 15920 coord[0] = coord[0] - worldsAway * sourceExtentWidth; 15921 } 15922 coord[0] = clamp(coord[0], sourceExtent[0], sourceExtent[2]); 15923 coord[1] = clamp(coord[1], sourceExtent[1], sourceExtent[3]); 15924 transformed = transform(coord); 15925 } else { 15926 transformed = transform(coord); 15927 } 15928 if (worldsAway && destProj.canWrapX()) { 15929 // Move transformed coordinate back to the offset world 15930 transformed[0] += worldsAway * getWidth(destProj.getExtent()); 15931 } 15932 return transformed; 15933 }; 15934} 15935 15936/** 15937 * Add transforms to and from EPSG:4326 and EPSG:3857. This function is called 15938 * by when this module is executed and should only need to be called again after 15939 * `clearAllProjections()` is called (e.g. in tests). 15940 */ 15941function addCommon() { 15942 // Add transformations that don't alter coordinates to convert within set of 15943 // projections with equal meaning. 15944 addEquivalentProjections(PROJECTIONS); 15945 addEquivalentProjections(epsg4326_PROJECTIONS); 15946 // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like 15947 // coordinates and back. 15948 addEquivalentTransforms( 15949 epsg4326_PROJECTIONS, 15950 PROJECTIONS, 15951 fromEPSG4326, 15952 toEPSG4326 15953 ); 15954} 15955 15956addCommon(); 15957 15958;// CONCATENATED MODULE: ./node_modules/ol/centerconstraint.js 15959/** 15960 * @module ol/centerconstraint 15961 */ 15962 15963 15964/** 15965 * @typedef {function((import("./coordinate.js").Coordinate|undefined), number, import("./size.js").Size, boolean=, Array<number>=): (import("./coordinate.js").Coordinate|undefined)} Type 15966 */ 15967 15968/** 15969 * @param {import("./extent.js").Extent} extent Extent. 15970 * @param {boolean} onlyCenter If true, the constraint will only apply to the view center. 15971 * @param {boolean} smooth If true, the view will be able to go slightly out of the given extent 15972 * (only during interaction and animation). 15973 * @return {Type} The constraint. 15974 */ 15975function createExtent(extent, onlyCenter, smooth) { 15976 return ( 15977 /** 15978 * @param {import("./coordinate.js").Coordinate|undefined} center Center. 15979 * @param {number|undefined} resolution Resolution. 15980 * @param {import("./size.js").Size} size Viewport size; unused if `onlyCenter` was specified. 15981 * @param {boolean} [isMoving] True if an interaction or animation is in progress. 15982 * @param {Array<number>} [centerShift] Shift between map center and viewport center. 15983 * @return {import("./coordinate.js").Coordinate|undefined} Center. 15984 */ 15985 function (center, resolution, size, isMoving, centerShift) { 15986 if (!center) { 15987 return undefined; 15988 } 15989 if (!resolution && !onlyCenter) { 15990 return center; 15991 } 15992 const viewWidth = onlyCenter ? 0 : size[0] * resolution; 15993 const viewHeight = onlyCenter ? 0 : size[1] * resolution; 15994 const shiftX = centerShift ? centerShift[0] : 0; 15995 const shiftY = centerShift ? centerShift[1] : 0; 15996 let minX = extent[0] + viewWidth / 2 + shiftX; 15997 let maxX = extent[2] - viewWidth / 2 + shiftX; 15998 let minY = extent[1] + viewHeight / 2 + shiftY; 15999 let maxY = extent[3] - viewHeight / 2 + shiftY; 16000 16001 // note: when zooming out of bounds, min and max values for x and y may 16002 // end up inverted (min > max); this has to be accounted for 16003 if (minX > maxX) { 16004 minX = (maxX + minX) / 2; 16005 maxX = minX; 16006 } 16007 if (minY > maxY) { 16008 minY = (maxY + minY) / 2; 16009 maxY = minY; 16010 } 16011 16012 let x = math_clamp(center[0], minX, maxX); 16013 let y = math_clamp(center[1], minY, maxY); 16014 16015 // during an interaction, allow some overscroll 16016 if (isMoving && smooth && resolution) { 16017 const ratio = 30 * resolution; 16018 x += 16019 -ratio * Math.log(1 + Math.max(0, minX - center[0]) / ratio) + 16020 ratio * Math.log(1 + Math.max(0, center[0] - maxX) / ratio); 16021 y += 16022 -ratio * Math.log(1 + Math.max(0, minY - center[1]) / ratio) + 16023 ratio * Math.log(1 + Math.max(0, center[1] - maxY) / ratio); 16024 } 16025 16026 return [x, y]; 16027 } 16028 ); 16029} 16030 16031/** 16032 * @param {import("./coordinate.js").Coordinate} [center] Center. 16033 * @return {import("./coordinate.js").Coordinate|undefined} Center. 16034 */ 16035function none(center) { 16036 return center; 16037} 16038 16039;// CONCATENATED MODULE: ./node_modules/ol/resolutionconstraint.js 16040/** 16041 * @module ol/resolutionconstraint 16042 */ 16043 16044 16045 16046 16047/** 16048 * @typedef {function((number|undefined), number, import("./size.js").Size, boolean=): (number|undefined)} Type 16049 */ 16050 16051/** 16052 * Returns a modified resolution taking into account the viewport size and maximum 16053 * allowed extent. 16054 * @param {number} resolution Resolution 16055 * @param {import("./extent.js").Extent} maxExtent Maximum allowed extent. 16056 * @param {import("./size.js").Size} viewportSize Viewport size. 16057 * @param {boolean} showFullExtent Whether to show the full extent. 16058 * @return {number} Capped resolution. 16059 */ 16060function getViewportClampedResolution( 16061 resolution, 16062 maxExtent, 16063 viewportSize,
16064 showFullExtent 16065) { 16066 const xResolution = extent_getWidth(maxExtent) / viewportSize[0]; 16067 const yResolution = extent_getHeight(maxExtent) / viewportSize[1]; 16068 16069 if (showFullExtent) { 16070 return Math.min(resolution, Math.max(xResolution, yResolution)); 16071 } 16072 return Math.min(resolution, Math.min(xResolution, yResolution)); 16073} 16074 16075/** 16076 * Returns a modified resolution to be between maxResolution and minResolution while 16077 * still allowing the value to be slightly out of bounds. 16078 * Note: the computation is based on the logarithm function (ln): 16079 * - at 1, ln(x) is 0 16080 * - above 1, ln(x) keeps increasing but at a much slower pace than x 16081 * The final result is clamped to prevent getting too far away from bounds. 16082 * @param {number} resolution Resolution. 16083 * @param {number} maxResolution Max resolution. 16084 * @param {number} minResolution Min resolution. 16085 * @return {number} Smoothed resolution. 16086 */ 16087function getSmoothClampedResolution(resolution, maxResolution, minResolution) { 16088 let result = Math.min(resolution, maxResolution); 16089 const ratio = 50; 16090 16091 result *= 16092 Math.log(1 + ratio * Math.max(0, resolution / maxResolution - 1)) / ratio + 16093 1; 16094 if (minResolution) { 16095 result = Math.max(result, minResolution); 16096 result /= 16097 Math.log(1 + ratio * Math.max(0, minResolution / resolution - 1)) / 16098 ratio + 16099 1; 16100 } 16101 return math_clamp(result, minResolution / 2, maxResolution * 2); 16102} 16103 16104/** 16105 * @param {Array<number>} resolutions Resolutions. 16106 * @param {boolean} [smooth] If true, the view will be able to slightly exceed resolution limits. Default: true. 16107 * @param {import("./extent.js").Extent} [maxExtent] Maximum allowed extent. 16108 * @param {boolean} [showFullExtent] If true, allows us to show the full extent. Default: false. 16109 * @return {Type} Zoom function. 16110 */ 16111function createSnapToResolutions( 16112 resolutions, 16113 smooth, 16114 maxExtent, 16115 showFullExtent 16116) { 16117 smooth = smooth !== undefined ? smooth : true; 16118 return ( 16119 /** 16120 * @param {number|undefined} resolution Resolution. 16121 * @param {number} direction Direction. 16122 * @param {import("./size.js").Size} size Viewport size. 16123 * @param {boolean} [isMoving] True if an interaction or animation is in progress. 16124 * @return {number|undefined} Resolution. 16125 */ 16126 function (resolution, direction, size, isMoving) { 16127 if (resolution !== undefined) { 16128 const maxResolution = resolutions[0]; 16129 const minResolution = resolutions[resolutions.length - 1]; 16130 const cappedMaxRes = maxExtent 16131 ? getViewportClampedResolution( 16132 maxResolution, 16133 maxExtent, 16134 size, 16135 showFullExtent 16136 ) 16137 : maxResolution; 16138 16139 // during interacting or animating, allow intermediary values 16140 if (isMoving) { 16141 if (!smooth) { 16142 return math_clamp(resolution, minResolution, cappedMaxRes); 16143 } 16144 return getSmoothClampedResolution( 16145 resolution, 16146 cappedMaxRes, 16147 minResolution 16148 ); 16149 } 16150 16151 const capped = Math.min(cappedMaxRes, resolution); 16152 const z = Math.floor(linearFindNearest(resolutions, capped, direction)); 16153 if (resolutions[z] > cappedMaxRes && z < resolutions.length - 1) { 16154 return resolutions[z + 1]; 16155 } 16156 return resolutions[z]; 16157 } else { 16158 return undefined; 16159 } 16160 } 16161 ); 16162} 16163 16164/** 16165 * @param {number} power Power. 16166 * @param {number} maxResolution Maximum resolution. 16167 * @param {number} [minResolution] Minimum resolution. 16168 * @param {boolean} [smooth] If true, the view will be able to slightly exceed resolution limits. Default: true. 16169 * @param {import("./extent.js").Extent} [maxExtent] Maximum allowed extent. 16170 * @param {boolean} [showFullExtent] If true, allows us to show the full extent. Default: false. 16171 * @return {Type} Zoom function. 16172 */ 16173function createSnapToPower( 16174 power, 16175 maxResolution, 16176 minResolution, 16177 smooth, 16178 maxExtent, 16179 showFullExtent 16180) { 16181 smooth = smooth !== undefined ? smooth : true; 16182 minResolution = minResolution !== undefined ? minResolution : 0; 16183 16184 return ( 16185 /** 16186 * @param {number|undefined} resolution Resolution. 16187 * @param {number} direction Direction. 16188 * @param {import("./size.js").Size} size Viewport size. 16189 * @param {boolean} [isMoving] True if an interaction or animation is in progress. 16190 * @return {number|undefined} Resolution. 16191 */ 16192 function (resolution, direction, size, isMoving) { 16193 if (resolution !== undefined) { 16194 const cappedMaxRes = maxExtent 16195 ? getViewportClampedResolution( 16196 maxResolution, 16197 maxExtent, 16198 size, 16199 showFullExtent 16200 ) 16201 : maxResolution; 16202 16203 // during interacting or animating, allow intermediary values 16204 if (isMoving) { 16205 if (!smooth) { 16206 return math_clamp(resolution, minResolution, cappedMaxRes); 16207 } 16208 return getSmoothClampedResolution( 16209 resolution, 16210 cappedMaxRes, 16211 minResolution 16212 ); 16213 } 16214 16215 const tolerance = 1e-9;
16216 const minZoomLevel = Math.ceil( 16217 Math.log(maxResolution / cappedMaxRes) / Math.log(power) - tolerance 16218 ); 16219 const offset = -direction * (0.5 - tolerance) + 0.5; 16220 const capped = Math.min(cappedMaxRes, resolution); 16221 const cappedZoomLevel = Math.floor( 16222 Math.log(maxResolution / capped) / Math.log(power) + offset 16223 ); 16224 const zoomLevel = Math.max(minZoomLevel, cappedZoomLevel); 16225 const newResolution = maxResolution / Math.pow(power, zoomLevel); 16226 return math_clamp(newResolution, minResolution, cappedMaxRes); 16227 } else { 16228 return undefined; 16229 } 16230 } 16231 ); 16232} 16233 16234/** 16235 * @param {number} maxResolution Max resolution. 16236 * @param {number} minResolution Min resolution. 16237 * @param {boolean} [smooth] If true, the view will be able to slightly exceed resolution limits. Default: true. 16238 * @param {import("./extent.js").Extent} [maxExtent] Maximum allowed extent. 16239 * @param {boolean} [showFullExtent] If true, allows us to show the full extent. Default: false. 16240 * @return {Type} Zoom function. 16241 */ 16242function createMinMaxResolution( 16243 maxResolution, 16244 minResolution, 16245 smooth, 16246 maxExtent, 16247 showFullExtent 16248) { 16249 smooth = smooth !== undefined ? smooth : true; 16250 16251 return ( 16252 /** 16253 * @param {number|undefined} resolution Resolution. 16254 * @param {number} direction Direction. 16255 * @param {import("./size.js").Size} size Viewport size. 16256 * @param {boolean} [isMoving] True if an interaction or animation is in progress. 16257 * @return {number|undefined} Resolution. 16258 */ 16259 function (resolution, direction, size, isMoving) { 16260 if (resolution !== undefined) { 16261 const cappedMaxRes = maxExtent 16262 ? getViewportClampedResolution( 16263 maxResolution, 16264 maxExtent, 16265 size, 16266 showFullExtent 16267 ) 16268 : maxResolution; 16269 16270 if (!smooth || !isMoving) { 16271 return math_clamp(resolution, minResolution, cappedMaxRes); 16272 } 16273 return getSmoothClampedResolution( 16274 resolution, 16275 cappedMaxRes, 16276 minResolution 16277 ); 16278 } else { 16279 return undefined; 16280 } 16281 } 16282 ); 16283} 16284 16285;// CONCATENATED MODULE: ./node_modules/ol/rotationconstraint.js 16286/** 16287 * @module ol/rotationconstraint 16288 */ 16289 16290 16291/** 16292 * @typedef {function((number|undefined), boolean=): (number|undefined)} Type 16293 */ 16294 16295/** 16296 * @param {number|undefined} rotation Rotation. 16297 * @return {number|undefined} Rotation. 16298 */ 16299function disable(rotation) { 16300 if (rotation !== undefined) { 16301 return 0; 16302 } else { 16303 return undefined; 16304 } 16305} 16306 16307/** 16308 * @param {number|undefined} rotation Rotation. 16309 * @return {number|undefined} Rotation. 16310 */ 16311function rotationconstraint_none(rotation) { 16312 if (rotation !== undefined) { 16313 return rotation; 16314 } else { 16315 return undefined; 16316 } 16317} 16318 16319/** 16320 * @param {number} n N. 16321 * @return {Type} Rotation constraint. 16322 */ 16323function createSnapToN(n) { 16324 const theta = (2 * Math.PI) / n; 16325 return ( 16326 /** 16327 * @param {number|undefined} rotation Rotation. 16328 * @param {boolean} [isMoving] True if an interaction or animation is in progress. 16329 * @return {number|undefined} Rotation. 16330 */ 16331 function (rotation, isMoving) { 16332 if (isMoving) { 16333 return rotation; 16334 } 16335 16336 if (rotation !== undefined) { 16337 rotation = Math.floor(rotation / theta + 0.5) * theta; 16338 return rotation; 16339 } else { 16340 return undefined; 16341 } 16342 } 16343 ); 16344} 16345 16346/** 16347 * @param {number} [tolerance] Tolerance. 16348 * @return {Type} Rotation constraint. 16349 */ 16350function createSnapToZero(tolerance) { 16351 tolerance = tolerance || math_toRadians(5); 16352 return ( 16353 /** 16354 * @param {number|undefined} rotation Rotation. 16355 * @param {boolean} [isMoving] True if an interaction or animation is in progress. 16356 * @return {number|undefined} Rotation. 16357 */ 16358 function (rotation, isMoving) { 16359 if (isMoving) { 16360 return rotation; 16361 } 16362 16363 if (rotation !== undefined) { 16364 if (Math.abs(rotation) <= tolerance) { 16365 return 0; 16366 } else { 16367 return rotation; 16368 } 16369 } else { 16370 return undefined; 16371 } 16372 } 16373 ); 16374} 16375 16376;// CONCATENATED MODULE: ./node_modules/ol/easing.js 16377/** 16378 * @module ol/easing 16379 */ 16380 16381/** 16382 * Start slow and speed up. 16383 * @param {number} t Input between 0 and 1. 16384 * @return {number} Output between 0 and 1. 16385 * @api 16386 */ 16387function easeIn(t) { 16388 return Math.pow(t, 3); 16389} 16390 16391/** 16392 * Start fast and slow down. 16393 * @param {number} t Input between 0 and 1. 16394 * @return {number} Output between 0 and 1. 16395 * @api 16396 */ 16397function easeOut(t) { 16398 return 1 - easeIn(1 - t); 16399} 16400 16401/** 16402 * Start slow, speed up, and then slow down again. 16403 * @param {number} t Input between 0 and 1. 16404 * @return {number} Output between 0 and 1. 16405 * @api 16406 */ 16407function inAndOut(t) { 16408 return 3 * t * t - 2 * t * t * t; 16409} 16410 16411/** 16412 * Maintain a constant speed over time. 16413 * @param {number} t Input between 0 and 1. 16414 * @return {number} Output between 0 and 1. 16415 * @api 16416 */ 16417function linear(t) { 16418 return t; 16419} 16420 16421/** 16422 * Start slow, speed up, and at the very end slow down again. This has the 16423 * same general behavior as {@link module:ol/easing.inAndOut}, but the final 16424 * slowdown is delayed. 16425 * @param {number} t Input between 0 and 1. 16426 * @return {number} Output between 0 and 1. 16427 * @api 16428 */ 16429function upAndDown(t) { 16430 if (t < 0.5) { 16431 return inAndOut(2 * t); 16432 } else { 16433 return 1 - inAndOut(2 * (t - 0.5)); 16434 } 16435} 16436 16437;// CONCATENATED MODULE: ./node_modules/ol/has.js 16438/** 16439 * @module ol/has 16440 */ 16441 16442const ua = 16443 typeof navigator !== 'undefined' && typeof navigator.userAgent !== 'undefined' 16444 ? navigator.userAgent.toLowerCase() 16445 : ''; 16446 16447/** 16448 * User agent string says we are dealing with Firefox as browser. 16449 * @type {boolean} 16450 */ 16451const FIREFOX = ua.includes('firefox'); 16452 16453/** 16454 * User agent string says we are dealing with Safari as browser. 16455 * @type {boolean} 16456 */ 16457const SAFARI = ua.includes('safari') && !ua.includes('chrom'); 16458 16459/** 16460 * https://bugs.webkit.org/show_bug.cgi?id=237906 16461 * @type {boolean} 16462 */ 16463const SAFARI_BUG_237906 = 16464 SAFARI && 16465 (ua.includes('version/15.4') || 16466 /cpu (os|iphone os) 15_4 like mac os x/.test(ua)); 16467 16468/** 16469 * User agent string says we are dealing with a WebKit engine. 16470 * @type {boolean} 16471 */ 16472const WEBKIT = ua.includes('webkit') && !ua.includes('edge'); 16473 16474/** 16475 * User agent string says we are dealing with a Mac as platform. 16476 * @type {boolean} 16477 */ 16478const has_MAC = ua.includes('macintosh'); 16479 16480/** 16481 * The ratio between physical pixels and device-independent pixels 16482 * (dips) on the device (`window.devicePixelRatio`). 16483 * @const 16484 * @type {number} 16485 * @api 16486 */ 16487const DEVICE_PIXEL_RATIO = 16488 typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1; 16489 16490/** 16491 * The execution context is a worker with OffscreenCanvas available. 16492 * @const 16493 * @type {boolean} 16494 */ 16495const WORKER_OFFSCREEN_CANVAS = 16496 typeof WorkerGlobalScope !== 'undefined' && 16497 typeof OffscreenCanvas !== 'undefined' && 16498 self instanceof WorkerGlobalScope; //eslint-disable-line 16499 16500/** 16501 * Image.prototype.decode() is supported. 16502 * @type {boolean} 16503 */ 16504const IMAGE_DECODE = 16505 typeof Image !== 'undefined' && Image.prototype.decode; 16506 16507/** 16508 * @type {boolean} 16509 */ 16510const PASSIVE_EVENT_LISTENERS = (function () { 16511 let passive = false;
16512 try { 16513 const options = Object.defineProperty({}, 'passive', { 16514 get: function () { 16515 passive = true; 16516 }, 16517 }); 16518 16519 window.addEventListener('_', null, options); 16520 window.removeEventListener('_', null, options); 16521 } catch (error) { 16522 // passive not supported 16523 } 16524 return passive; 16525})(); 16526 16527;// CONCATENATED MODULE: ./node_modules/ol/transform.js 16528/** 16529 * @module ol/transform 16530 */ 16531 16532 16533 16534/** 16535 * An array representing an affine 2d transformation for use with 16536 * {@link module:ol/transform} functions. The array has 6 elements. 16537 * @typedef {!Array<number>} Transform 16538 * @api 16539 */ 16540 16541/** 16542 * Collection of affine 2d transformation functions. The functions work on an 16543 * array of 6 elements. The element order is compatible with the [SVGMatrix 16544 * interface](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix) and is 16545 * a subset (elements a to f) of a 3Ã3 matrix: 16546 * ``` 16547 * [ a c e ] 16548 * [ b d f ] 16549 * [ 0 0 1 ] 16550 * ``` 16551 */ 16552 16553/** 16554 * @private 16555 * @type {Transform} 16556 */ 16557const tmp_ = new Array(6); 16558 16559/** 16560 * Create an identity transform. 16561 * @return {!Transform} Identity transform. 16562 */ 16563function create() { 16564 return [1, 0, 0, 1, 0, 0]; 16565} 16566 16567/** 16568 * Resets the given transform to an identity transform. 16569 * @param {!Transform} transform Transform. 16570 * @return {!Transform} Transform. 16571 */ 16572function transform_reset(transform) { 16573 return set(transform, 1, 0, 0, 1, 0, 0); 16574} 16575 16576/** 16577 * Multiply the underlying matrices of two transforms and return the result in 16578 * the first transform. 16579 * @param {!Transform} transform1 Transform parameters of matrix 1. 16580 * @param {!Transform} transform2 Transform parameters of matrix 2. 16581 * @return {!Transform} transform1 multiplied with transform2. 16582 */ 16583function multiply(transform1, transform2) { 16584 const a1 = transform1[0]; 16585 const b1 = transform1[1]; 16586 const c1 = transform1[2]; 16587 const d1 = transform1[3]; 16588 const e1 = transform1[4]; 16589 const f1 = transform1[5]; 16590 const a2 = transform2[0]; 16591 const b2 = transform2[1]; 16592 const c2 = transform2[2]; 16593 const d2 = transform2[3]; 16594 const e2 = transform2[4]; 16595 const f2 = transform2[5]; 16596 16597 transform1[0] = a1 * a2 + c1 * b2; 16598 transform1[1] = b1 * a2 + d1 * b2; 16599 transform1[2] = a1 * c2 + c1 * d2; 16600 transform1[3] = b1 * c2 + d1 * d2; 16601 transform1[4] = a1 * e2 + c1 * f2 + e1; 16602 transform1[5] = b1 * e2 + d1 * f2 + f1; 16603 16604 return transform1; 16605} 16606 16607/** 16608 * Set the transform components a-f on a given transform. 16609 * @param {!Transform} transform Transform. 16610 * @param {number} a The a component of the transform. 16611 * @param {number} b The b component of the transform. 16612 * @param {number} c The c component of the transform. 16613 * @param {number} d The d component of the transform. 16614 * @param {number} e The e component of the transform. 16615 * @param {number} f The f component of the transform. 16616 * @return {!Transform} Matrix with transform applied. 16617 */ 16618function set(transform, a, b, c, d, e, f) { 16619 transform[0] = a; 16620 transform[1] = b; 16621 transform[2] = c; 16622 transform[3] = d; 16623 transform[4] = e; 16624 transform[5] = f; 16625 return transform; 16626} 16627 16628/** 16629 * Set transform on one matrix from another matrix. 16630 * @param {!Transform} transform1 Matrix to set transform to. 16631 * @param {!Transform} transform2 Matrix to set transform from. 16632 * @return {!Transform} transform1 with transform from transform2 applied. 16633 */ 16634function setFromArray(transform1, transform2) { 16635 transform1[0] = transform2[0]; 16636 transform1[1] = transform2[1]; 16637 transform1[2] = transform2[2]; 16638 transform1[3] = transform2[3]; 16639 transform1[4] = transform2[4]; 16640 transform1[5] = transform2[5]; 16641 return transform1; 16642} 16643 16644/** 16645 * Transforms the given coordinate with the given transform returning the 16646 * resulting, transformed coordinate. The coordinate will be modified in-place. 16647 * 16648 * @param {Transform} transform The transformation. 16649 * @param {import("./coordinate.js").Coordinate|import("./pixel.js").Pixel} coordinate The coordinate to transform. 16650 * @return {import("./coordinate.js").Coordinate|import("./pixel.js").Pixel} return coordinate so that operations can be 16651 * chained together. 16652 */ 16653function apply(transform, coordinate) { 16654 const x = coordinate[0]; 16655 const y = coordinate[1]; 16656 coordinate[0] = transform[0] * x + transform[2] * y + transform[4]; 16657 coordinate[1] = transform[1] * x + transform[3] * y + transform[5]; 16658 return coordinate; 16659} 16660 16661/** 16662 * Applies rotation to the given transform. 16663 * @param {!Transform} transform Transform. 16664 * @param {number} angle Angle in radians. 16665 * @return {!Transform} The rotated transform. 16666 */ 16667function transform_rotate(transform, angle) { 16668 const cos = Math.cos(angle); 16669 const sin = Math.sin(angle); 16670 return multiply(transform, set(tmp_, cos, sin, -sin, cos, 0, 0)); 16671} 16672 16673/** 16674 * Applies scale to a given transform. 16675 * @param {!Transform} transform Transform. 16676 * @param {number} x Scale factor x. 16677 * @param {number} y Scale factor y. 16678 * @return {!Transform} The scaled transform. 16679 */ 16680function transform_scale(transform, x, y) { 16681 return multiply(transform, set(tmp_, x, 0, 0, y, 0, 0)); 16682} 16683 16684/** 16685 * Creates a scale transform. 16686 * @param {!Transform} target Transform to overwrite. 16687 * @param {number} x Scale factor x. 16688 * @param {number} y Scale factor y. 16689 * @return {!Transform} The scale transform. 16690 */ 16691function makeScale(target, x, y) { 16692 return set(target, x, 0, 0, y, 0, 0); 16693} 16694 16695/** 16696 * Applies translation to the given transform. 16697 * @param {!Transform} transform Transform. 16698 * @param {number} dx Translation x. 16699 * @param {number} dy Translation y. 16700 * @return {!Transform} The translated transform. 16701 */ 16702function translate(transform, dx, dy) { 16703 return multiply(transform, set(tmp_, 1, 0, 0, 1, dx, dy)); 16704} 16705 16706/** 16707 * Creates a composite transform given an initial translation, scale, rotation, and 16708 * final translation (in that order only, not commutative). 16709 * @param {!Transform} transform The transform (will be modified in place). 16710 * @param {number} dx1 Initial translation x. 16711 * @param {number} dy1 Initial translation y. 16712 * @param {number} sx Scale factor x. 16713 * @param {number} sy Scale factor y. 16714 * @param {number} angle Rotation (in counter-clockwise radians). 16715 * @param {number} dx2 Final translation x. 16716 * @param {number} dy2 Final translation y. 16717 * @return {!Transform} The composite transform. 16718 */ 16719function compose(transform, dx1, dy1, sx, sy, angle, dx2, dy2) { 16720 const sin = Math.sin(angle); 16721 const cos = Math.cos(angle); 16722 transform[0] = sx * cos; 16723 transform[1] = sy * sin; 16724 transform[2] = -sx * sin; 16725 transform[3] = sy * cos; 16726 transform[4] = dx2 * sx * cos - dy2 * sx * sin + dx1; 16727 transform[5] = dx2 * sy * sin + dy2 * sy * cos + dy1; 16728 return transform; 16729} 16730 16731/** 16732 * Creates a composite transform given an initial translation, scale, rotation, and 16733 * final translation (in that order only, not commutative). The resulting transform 16734 * string can be applied as `transform` property of an HTMLElement's style. 16735 * @param {number} dx1 Initial translation x. 16736 * @param {number} dy1 Initial translation y. 16737 * @param {number} sx Scale factor x. 16738 * @param {number} sy Scale factor y. 16739 * @param {number} angle Rotation (in counter-clockwise radians). 16740 * @param {number} dx2 Final translation x. 16741 * @param {number} dy2 Final translation y. 16742 * @return {string} The composite css transform. 16743 * @api 16744 */ 16745function composeCssTransform(dx1, dy1, sx, sy, angle, dx2, dy2) { 16746 return transform_toString(compose(create(), dx1, dy1, sx, sy, angle, dx2, dy2)); 16747} 16748 16749/** 16750 * Invert the given transform. 16751 * @param {!Transform} source The source transform to invert. 16752 * @return {!Transform} The inverted (source) transform. 16753 */ 16754function invert(source) { 16755 return makeInverse(source, source); 16756} 16757 16758/** 16759 * Invert the given transform. 16760 * @param {!Transform} target Transform to be set as the inverse of 16761 * the source transform. 16762 * @param {!Transform} source The source transform to invert. 16763 * @return {!Transform} The inverted (target) transform. 16764 */ 16765function makeInverse(target, source) { 16766 const det = determinant(source); 16767 asserts_assert(det !== 0, 32); // Transformation matrix cannot be inverted 16768 16769 const a = source[0]; 16770 const b = source[1]; 16771 const c = source[2]; 16772 const d = source[3]; 16773 const e = source[4]; 16774 const f = source[5]; 16775 16776 target[0] = d / det; 16777 target[1] = -b / det; 16778 target[2] = -c / det; 16779 target[3] = a / det; 16780 target[4] = (c * f - d * e) / det; 16781 target[5] = -(a * f - b * e) / det; 16782 16783 return target; 16784} 16785 16786/** 16787 * Returns the determinant of the given matrix. 16788 * @param {!Transform} mat Matrix. 16789 * @return {number} Determinant. 16790 */ 16791function determinant(mat) { 16792 return mat[0] * mat[3] - mat[1] * mat[2]; 16793} 16794 16795/** 16796 * @type {HTMLElement} 16797 * @private 16798 */ 16799let transformStringDiv; 16800 16801/** 16802 * A rounded string version of the transform. This can be used 16803 * for CSS transforms. 16804 * @param {!Transform} mat Matrix. 16805 * @return {string} The transform as a string. 16806 */ 16807function transform_toString(mat) { 16808 const transformString = 'matrix(' + mat.join(', ') + ')'; 16809 if (WORKER_OFFSCREEN_CANVAS) { 16810 return transformString; 16811 } 16812 const node = 16813 transformStringDiv || (transformStringDiv = document.createElement('div')); 16814 node.style.transform = transformString; 16815 return node.style.transform; 16816} 16817 16818;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/transform.js 16819/** 16820 * @module ol/geom/flat/transform 16821 */ 16822 16823/** 16824 * @param {Array<number>} flatCoordinates Flat coordinates. 16825 * @param {number} offset Offset. 16826 * @param {number} end End. 16827 * @param {number} stride Stride. 16828 * @param {import("../../transform.js").Transform} transform Transform. 16829 * @param {Array<number>} [dest] Destination. 16830 * @return {Array<number>} Transformed coordinates. 16831 */ 16832function transform2D( 16833 flatCoordinates, 16834 offset, 16835 end, 16836 stride, 16837 transform, 16838 dest 16839) { 16840 dest = dest ? dest : []; 16841 let i = 0; 16842 for (let j = offset; j < end; j += stride) { 16843 const x = flatCoordinates[j]; 16844 const y = flatCoordinates[j + 1]; 16845 dest[i++] = transform[0] * x + transform[2] * y + transform[4]; 16846 dest[i++] = transform[1] * x + transform[3] * y + transform[5]; 16847 } 16848 if (dest && dest.length != i) { 16849 dest.length = i; 16850 } 16851 return dest; 16852} 16853
vendor: 9,004 bytes, lines 16854-17187
16854/** 16855 * @param {Array<number>} flatCoordinates Flat coordinates. 16856 * @param {number} offset Offset. 16857 * @param {number} end End. 16858 * @param {number} stride Stride. 16859 * @param {number} angle Angle. 16860 * @param {Array<number>} anchor Rotation anchor point. 16861 * @param {Array<number>} [dest] Destination. 16862 * @return {Array<number>} Transformed coordinates. 16863 */ 16864function flat_transform_rotate( 16865 flatCoordinates, 16866 offset, 16867 end, 16868 stride, 16869 angle, 16870 anchor, 16871 dest 16872) { 16873 dest = dest ? dest : []; 16874 const cos = Math.cos(angle); 16875 const sin = Math.sin(angle); 16876 const anchorX = anchor[0]; 16877 const anchorY = anchor[1]; 16878 let i = 0; 16879 for (let j = offset; j < end; j += stride) { 16880 const deltaX = flatCoordinates[j] - anchorX; 16881 const deltaY = flatCoordinates[j + 1] - anchorY; 16882 dest[i++] = anchorX + deltaX * cos - deltaY * sin; 16883 dest[i++] = anchorY + deltaX * sin + deltaY * cos; 16884 for (let k = j + 2; k < j + stride; ++k) { 16885 dest[i++] = flatCoordinates[k]; 16886 } 16887 } 16888 if (dest && dest.length != i) { 16889 dest.length = i; 16890 } 16891 return dest; 16892} 16893 16894/** 16895 * Scale the coordinates. 16896 * @param {Array<number>} flatCoordinates Flat coordinates. 16897 * @param {number} offset Offset. 16898 * @param {number} end End. 16899 * @param {number} stride Stride. 16900 * @param {number} sx Scale factor in the x-direction. 16901 * @param {number} sy Scale factor in the y-direction. 16902 * @param {Array<number>} anchor Scale anchor point. 16903 * @param {Array<number>} [dest] Destination. 16904 * @return {Array<number>} Transformed coordinates. 16905 */ 16906function flat_transform_scale( 16907 flatCoordinates, 16908 offset, 16909 end, 16910 stride, 16911 sx, 16912 sy, 16913 anchor, 16914 dest 16915) { 16916 dest = dest ? dest : []; 16917 const anchorX = anchor[0]; 16918 const anchorY = anchor[1]; 16919 let i = 0; 16920 for (let j = offset; j < end; j += stride) { 16921 const deltaX = flatCoordinates[j] - anchorX; 16922 const deltaY = flatCoordinates[j + 1] - anchorY; 16923 dest[i++] = anchorX + sx * deltaX; 16924 dest[i++] = anchorY + sy * deltaY; 16925 for (let k = j + 2; k < j + stride; ++k) { 16926 dest[i++] = flatCoordinates[k]; 16927 } 16928 } 16929 if (dest && dest.length != i) { 16930 dest.length = i; 16931 } 16932 return dest; 16933} 16934 16935/** 16936 * @param {Array<number>} flatCoordinates Flat coordinates. 16937 * @param {number} offset Offset. 16938 * @param {number} end End. 16939 * @param {number} stride Stride. 16940 * @param {number} deltaX Delta X. 16941 * @param {number} deltaY Delta Y. 16942 * @param {Array<number>} [dest] Destination. 16943 * @return {Array<number>} Transformed coordinates. 16944 */ 16945function transform_translate( 16946 flatCoordinates, 16947 offset, 16948 end, 16949 stride, 16950 deltaX, 16951 deltaY, 16952 dest 16953) { 16954 dest = dest ? dest : []; 16955 let i = 0; 16956 for (let j = offset; j < end; j += stride) { 16957 dest[i++] = flatCoordinates[j] + deltaX; 16958 dest[i++] = flatCoordinates[j + 1] + deltaY; 16959 for (let k = j + 2; k < j + stride; ++k) { 16960 dest[i++] = flatCoordinates[k]; 16961 } 16962 } 16963 if (dest && dest.length != i) { 16964 dest.length = i; 16965 } 16966 return dest; 16967} 16968 16969;// CONCATENATED MODULE: ./node_modules/ol/geom/Geometry.js 16970/** 16971 * @module ol/geom/Geometry 16972 */ 16973 16974 16975 16976 16977 16978 16979 16980 16981/** 16982 * @typedef {'XY' | 'XYZ' | 'XYM' | 'XYZM'} GeometryLayout 16983 * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z') 16984 * or measure ('M') coordinate is available. 16985 */ 16986 16987/** 16988 * @typedef {'Point' | 'LineString' | 'LinearRing' | 'Polygon' | 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' | 'GeometryCollection' | 'Circle'} Type 16989 * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`, 16990 * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`, 16991 * `'GeometryCollection'`, or `'Circle'`. 16992 */ 16993 16994/** 16995 * @type {import("../transform.js").Transform} 16996 */ 16997const tmpTransform = create(); 16998 16999/** 17000 * @classdesc 17001 * Abstract base class; normally only used for creating subclasses and not 17002 * instantiated in apps. 17003 * Base class for vector geometries. 17004 * 17005 * To get notified of changes to the geometry, register a listener for the 17006 * generic `change` event on your geometry instance. 17007 * 17008 * @abstract 17009 * @api 17010 */ 17011class Geometry extends ol_Object { 17012 constructor() { 17013 super(); 17014 17015 /** 17016 * @private 17017 * @type {import("../extent.js").Extent} 17018 */ 17019 this.extent_ = createEmpty(); 17020 17021 /** 17022 * @private 17023 * @type {number} 17024 */ 17025 this.extentRevision_ = -1; 17026 17027 /** 17028 * @protected 17029 * @type {number} 17030 */ 17031 this.simplifiedGeometryMaxMinSquaredTolerance = 0; 17032 17033 /** 17034 * @protected 17035 * @type {number} 17036 */ 17037 this.simplifiedGeometryRevision = 0; 17038 17039 /** 17040 * Get a transformed and simplified version of the geometry. 17041 * @abstract 17042 * @param {number} revision The geometry revision. 17043 * @param {number} squaredTolerance Squared tolerance. 17044 * @param {import("../proj.js").TransformFunction} [transform] Optional transform function. 17045 * @return {Geometry} Simplified geometry. 17046 */ 17047 this.simplifyTransformedInternal = memoizeOne(function ( 17048 revision, 17049 squaredTolerance, 17050 transform 17051 ) { 17052 if (!transform) { 17053 return this.getSimplifiedGeometry(squaredTolerance); 17054 } 17055 const clone = this.clone(); 17056 clone.applyTransform(transform); 17057 return clone.getSimplifiedGeometry(squaredTolerance); 17058 }); 17059 } 17060 17061 /** 17062 * Get a transformed and simplified version of the geometry. 17063 * @abstract 17064 * @param {number} squaredTolerance Squared tolerance. 17065 * @param {import("../proj.js").TransformFunction} [transform] Optional transform function. 17066 * @return {Geometry} Simplified geometry. 17067 */ 17068 simplifyTransformed(squaredTolerance, transform) { 17069 return this.simplifyTransformedInternal( 17070 this.getRevision(), 17071 squaredTolerance, 17072 transform 17073 ); 17074 } 17075 17076 /** 17077 * Make a complete copy of the geometry. 17078 * @abstract 17079 * @return {!Geometry} Clone. 17080 */ 17081 clone() { 17082 return util_abstract(); 17083 } 17084 17085 /** 17086 * @abstract 17087 * @param {number} x X. 17088 * @param {number} y Y. 17089 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 17090 * @param {number} minSquaredDistance Minimum squared distance. 17091 * @return {number} Minimum squared distance. 17092 */ 17093 closestPointXY(x, y, closestPoint, minSquaredDistance) { 17094 return util_abstract(); 17095 } 17096 17097 /** 17098 * @param {number} x X. 17099 * @param {number} y Y. 17100 * @return {boolean} Contains (x, y). 17101 */ 17102 containsXY(x, y) { 17103 const coord = this.getClosestPoint([x, y]); 17104 return coord[0] === x && coord[1] === y; 17105 } 17106 17107 /** 17108 * Return the closest point of the geometry to the passed point as 17109 * {@link module:ol/coordinate~Coordinate coordinate}. 17110 * @param {import("../coordinate.js").Coordinate} point Point. 17111 * @param {import("../coordinate.js").Coordinate} [closestPoint] Closest point. 17112 * @return {import("../coordinate.js").Coordinate} Closest point. 17113 * @api 17114 */ 17115 getClosestPoint(point, closestPoint) { 17116 closestPoint = closestPoint ? closestPoint : [NaN, NaN]; 17117 this.closestPointXY(point[0], point[1], closestPoint, Infinity); 17118 return closestPoint; 17119 } 17120 17121 /** 17122 * Returns true if this geometry includes the specified coordinate. If the 17123 * coordinate is on the boundary of the geometry, returns false. 17124 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 17125 * @return {boolean} Contains coordinate. 17126 * @api 17127 */ 17128 intersectsCoordinate(coordinate) { 17129 return this.containsXY(coordinate[0], coordinate[1]); 17130 } 17131 17132 /** 17133 * @abstract 17134 * @param {import("../extent.js").Extent} extent Extent. 17135 * @protected 17136 * @return {import("../extent.js").Extent} extent Extent. 17137 */ 17138 computeExtent(extent) { 17139 return util_abstract(); 17140 } 17141 17142 /** 17143 * Get the extent of the geometry. 17144 * @param {import("../extent.js").Extent} [extent] Extent. 17145 * @return {import("../extent.js").Extent} extent Extent. 17146 * @api 17147 */ 17148 getExtent(extent) { 17149 if (this.extentRevision_ != this.getRevision()) { 17150 const extent = this.computeExtent(this.extent_); 17151 if (isNaN(extent[0]) || isNaN(extent[1])) { 17152 createOrUpdateEmpty(extent); 17153 } 17154 this.extentRevision_ = this.getRevision(); 17155 } 17156 return returnOrUpdate(this.extent_, extent); 17157 } 17158 17159 /** 17160 * Rotate the geometry around a given coordinate. This modifies the geometry 17161 * coordinates in place. 17162 * @abstract 17163 * @param {number} angle Rotation angle in radians. 17164 * @param {import("../coordinate.js").Coordinate} anchor The rotation center. 17165 * @api 17166 */ 17167 rotate(angle, anchor) { 17168 util_abstract(); 17169 } 17170 17171 /** 17172 * Scale the geometry (with an optional origin). This modifies the geometry 17173 * coordinates in place. 17174 * @abstract 17175 * @param {number} sx The scaling factor in the x-direction. 17176 * @param {number} [sy] The scaling factor in the y-direction (defaults to sx). 17177 * @param {import("../coordinate.js").Coordinate} [anchor] The scale origin (defaults to the center 17178 * of the geometry extent). 17179 * @api 17180 */ 17181 scale(sx, sy, anchor) { 17182 util_abstract(); 17183 } 17184 17185 /** 17186 * Create a simplified version of this geometry. For linestrings, this uses 17187 * the [Douglas Peucker](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm)
17188 * algorithm. For polygons, a quantization-based 17189 * simplification is used to preserve topology. 17190 * @param {number} tolerance The tolerance distance for simplification. 17191 * @return {Geometry} A new, simplified version of the original geometry. 17192 * @api 17193 */ 17194 simplify(tolerance) { 17195 return this.getSimplifiedGeometry(tolerance * tolerance); 17196 } 17197 17198 /** 17199 * Create a simplified version of this geometry using the Douglas Peucker 17200 * algorithm. 17201 * See https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm. 17202 * @abstract 17203 * @param {number} squaredTolerance Squared tolerance. 17204 * @return {Geometry} Simplified geometry. 17205 */ 17206 getSimplifiedGeometry(squaredTolerance) { 17207 return util_abstract(); 17208 } 17209 17210 /** 17211 * Get the type of this geometry. 17212 * @abstract 17213 * @return {Type} Geometry type. 17214 */ 17215 getType() { 17216 return util_abstract(); 17217 } 17218 17219 /** 17220 * Apply a transform function to the coordinates of the geometry. 17221 * The geometry is modified in place. 17222 * If you do not want the geometry modified in place, first `clone()` it and 17223 * then use this function on the clone. 17224 * @abstract 17225 * @param {import("../proj.js").TransformFunction} transformFn Transform function. 17226 * Called with a flat array of geometry coordinates. 17227 */ 17228 applyTransform(transformFn) { 17229 util_abstract(); 17230 } 17231 17232 /** 17233 * Test if the geometry and the passed extent intersect. 17234 * @abstract 17235 * @param {import("../extent.js").Extent} extent Extent. 17236 * @return {boolean} `true` if the geometry and the extent intersect. 17237 */ 17238 intersectsExtent(extent) { 17239 return util_abstract(); 17240 } 17241 17242 /** 17243 * Translate the geometry. This modifies the geometry coordinates in place. If 17244 * instead you want a new geometry, first `clone()` this geometry. 17245 * @abstract 17246 * @param {number} deltaX Delta X. 17247 * @param {number} deltaY Delta Y. 17248 * @api 17249 */ 17250 translate(deltaX, deltaY) { 17251 util_abstract(); 17252 } 17253 17254 /** 17255 * Transform each coordinate of the geometry from one coordinate reference 17256 * system to another. The geometry is modified in place. 17257 * For example, a line will be transformed to a line and a circle to a circle. 17258 * If you do not want the geometry modified in place, first `clone()` it and 17259 * then use this function on the clone. 17260 * 17261 * @param {import("../proj.js").ProjectionLike} source The current projection. Can be a 17262 * string identifier or a {@link module:ol/proj/Projection~Projection} object. 17263 * @param {import("../proj.js").ProjectionLike} destination The desired projection. Can be a 17264 * string identifier or a {@link module:ol/proj/Projection~Projection} object. 17265 * @return {Geometry} This geometry. Note that original geometry is 17266 * modified in place. 17267 * @api 17268 */ 17269 transform(source, destination) { 17270 /** @type {import("../proj/Projection.js").default} */ 17271 const sourceProj = proj_get(source); 17272 const transformFn = 17273 sourceProj.getUnits() == 'tile-pixels' 17274 ? function (inCoordinates, outCoordinates, stride) { 17275 const pixelExtent = sourceProj.getExtent(); 17276 const projectedExtent = sourceProj.getWorldExtent(); 17277 const scale = extent_getHeight(projectedExtent) / extent_getHeight(pixelExtent); 17278 compose( 17279 tmpTransform, 17280 projectedExtent[0], 17281 projectedExtent[3], 17282 scale, 17283 -scale, 17284 0, 17285 0, 17286 0 17287 ); 17288 transform2D( 17289 inCoordinates, 17290 0, 17291 inCoordinates.length, 17292 stride, 17293 tmpTransform, 17294 outCoordinates 17295 ); 17296 return getTransform(sourceProj, destination)( 17297 inCoordinates, 17298 outCoordinates, 17299 stride 17300 ); 17301 } 17302 : getTransform(sourceProj, destination); 17303 this.applyTransform(transformFn); 17304 return this; 17305 } 17306} 17307 17308/* harmony default export */ const geom_Geometry = (Geometry); 17309 17310;// CONCATENATED MODULE: ./node_modules/ol/geom/SimpleGeometry.js 17311/** 17312 * @module ol/geom/SimpleGeometry 17313 */ 17314 17315 17316 17317 17318 17319/** 17320 * @classdesc 17321 * Abstract base class; only used for creating subclasses; do not instantiate 17322 * in apps, as cannot be rendered. 17323 * 17324 * @abstract 17325 * @api 17326 */ 17327class SimpleGeometry extends geom_Geometry { 17328 constructor() { 17329 super(); 17330 17331 /** 17332 * @protected 17333 * @type {import("./Geometry.js").GeometryLayout} 17334 */ 17335 this.layout = 'XY'; 17336 17337 /** 17338 * @protected 17339 * @type {number} 17340 */ 17341 this.stride = 2; 17342 17343 /** 17344 * @protected 17345 * @type {Array<number>} 17346 */ 17347 this.flatCoordinates = null; 17348 } 17349 17350 /** 17351 * @param {import("../extent.js").Extent} extent Extent. 17352 * @protected 17353 * @return {import("../extent.js").Extent} extent Extent. 17354 */ 17355 computeExtent(extent) { 17356 return createOrUpdateFromFlatCoordinates( 17357 this.flatCoordinates, 17358 0, 17359 this.flatCoordinates.length, 17360 this.stride, 17361 extent 17362 ); 17363 } 17364 17365 /** 17366 * @abstract 17367 * @return {Array<*> | null} Coordinates. 17368 */ 17369 getCoordinates() { 17370 return util_abstract(); 17371 } 17372 17373 /** 17374 * Return the first coordinate of the geometry. 17375 * @return {import("../coordinate.js").Coordinate} First coordinate. 17376 * @api 17377 */ 17378 getFirstCoordinate() { 17379 return this.flatCoordinates.slice(0, this.stride); 17380 } 17381 17382 /** 17383 * @return {Array<number>} Flat coordinates. 17384 */ 17385 getFlatCoordinates() { 17386 return this.flatCoordinates; 17387 } 17388 17389 /** 17390 * Return the last coordinate of the geometry. 17391 * @return {import("../coordinate.js").Coordinate} Last point. 17392 * @api 17393 */ 17394 getLastCoordinate() { 17395 return this.flatCoordinates.slice( 17396 this.flatCoordinates.length - this.stride 17397 ); 17398 } 17399 17400 /** 17401 * Return the {@link import("./Geometry.js").GeometryLayout layout} of the geometry. 17402 * @return {import("./Geometry.js").GeometryLayout} Layout. 17403 * @api 17404 */ 17405 getLayout() { 17406 return this.layout; 17407 } 17408 17409 /** 17410 * Create a simplified version of this geometry using the Douglas Peucker algorithm. 17411 * @param {number} squaredTolerance Squared tolerance. 17412 * @return {SimpleGeometry} Simplified geometry. 17413 */ 17414 getSimplifiedGeometry(squaredTolerance) { 17415 if (this.simplifiedGeometryRevision !== this.getRevision()) { 17416 this.simplifiedGeometryMaxMinSquaredTolerance = 0; 17417 this.simplifiedGeometryRevision = this.getRevision(); 17418 } 17419 // If squaredTolerance is negative or if we know that simplification will not 17420 // have any effect then just return this. 17421 if ( 17422 squaredTolerance < 0 || 17423 (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && 17424 squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance) 17425 ) { 17426 return this; 17427 } 17428 17429 const simplifiedGeometry =
17430 this.getSimplifiedGeometryInternal(squaredTolerance); 17431 const simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates(); 17432 if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) { 17433 return simplifiedGeometry; 17434 } else { 17435 // Simplification did not actually remove any coordinates. We now know 17436 // that any calls to getSimplifiedGeometry with a squaredTolerance less 17437 // than or equal to the current squaredTolerance will also not have any 17438 // effect. This allows us to short circuit simplification (saving CPU 17439 // cycles) and prevents the cache of simplified geometries from filling 17440 // up with useless identical copies of this geometry (saving memory). 17441 this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; 17442 return this; 17443 } 17444 } 17445 17446 /** 17447 * @param {number} squaredTolerance Squared tolerance. 17448 * @return {SimpleGeometry} Simplified geometry. 17449 * @protected 17450 */ 17451 getSimplifiedGeometryInternal(squaredTolerance) { 17452 return this; 17453 } 17454 17455 /** 17456 * @return {number} Stride. 17457 */ 17458 getStride() { 17459 return this.stride; 17460 } 17461 17462 /** 17463 * @param {import("./Geometry.js").GeometryLayout} layout Layout. 17464 * @param {Array<number>} flatCoordinates Flat coordinates. 17465 */ 17466 setFlatCoordinates(layout, flatCoordinates) { 17467 this.stride = getStrideForLayout(layout); 17468 this.layout = layout; 17469 this.flatCoordinates = flatCoordinates; 17470 } 17471 17472 /** 17473 * @abstract 17474 * @param {!Array<*>} coordinates Coordinates. 17475 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 17476 */ 17477 setCoordinates(coordinates, layout) { 17478 util_abstract(); 17479 } 17480 17481 /** 17482 * @param {import("./Geometry.js").GeometryLayout|undefined} layout Layout. 17483 * @param {Array<*>} coordinates Coordinates. 17484 * @param {number} nesting Nesting. 17485 * @protected 17486 */ 17487 setLayout(layout, coordinates, nesting) { 17488 /** @type {number} */ 17489 let stride; 17490 if (layout) { 17491 stride = getStrideForLayout(layout); 17492 } else { 17493 for (let i = 0; i < nesting; ++i) { 17494 if (coordinates.length === 0) { 17495 this.layout = 'XY'; 17496 this.stride = 2; 17497 return; 17498 } else { 17499 coordinates = /** @type {Array} */ (coordinates[0]); 17500 } 17501 } 17502 stride = coordinates.length; 17503 layout = getLayoutForStride(stride); 17504 } 17505 this.layout = layout; 17506 this.stride = stride; 17507 } 17508 17509 /** 17510 * Apply a transform function to the coordinates of the geometry. 17511 * The geometry is modified in place. 17512 * If you do not want the geometry modified in place, first `clone()` it and 17513 * then use this function on the clone. 17514 * @param {import("../proj.js").TransformFunction} transformFn Transform function. 17515 * Called with a flat array of geometry coordinates. 17516 * @api 17517 */ 17518 applyTransform(transformFn) { 17519 if (this.flatCoordinates) { 17520 transformFn(this.flatCoordinates, this.flatCoordinates, this.stride); 17521 this.changed(); 17522 } 17523 } 17524 17525 /** 17526 * Rotate the geometry around a given coordinate. This modifies the geometry 17527 * coordinates in place. 17528 * @param {number} angle Rotation angle in counter-clockwise radians. 17529 * @param {import("../coordinate.js").Coordinate} anchor The rotation center. 17530 * @api 17531 */ 17532 rotate(angle, anchor) { 17533 const flatCoordinates = this.getFlatCoordinates(); 17534 if (flatCoordinates) { 17535 const stride = this.getStride(); 17536 flat_transform_rotate( 17537 flatCoordinates, 17538 0, 17539 flatCoordinates.length, 17540 stride, 17541 angle, 17542 anchor, 17543 flatCoordinates 17544 ); 17545 this.changed(); 17546 } 17547 } 17548 17549 /** 17550 * Scale the geometry (with an optional origin). This modifies the geometry 17551 * coordinates in place. 17552 * @param {number} sx The scaling factor in the x-direction. 17553 * @param {number} [sy] The scaling factor in the y-direction (defaults to sx). 17554 * @param {import("../coordinate.js").Coordinate} [anchor] The scale origin (defaults to the center 17555 * of the geometry extent). 17556 * @api 17557 */ 17558 scale(sx, sy, anchor) { 17559 if (sy === undefined) { 17560 sy = sx; 17561 } 17562 if (!anchor) { 17563 anchor = getCenter(this.getExtent()); 17564 } 17565 const flatCoordinates = this.getFlatCoordinates(); 17566 if (flatCoordinates) {
17567 const stride = this.getStride(); 17568 flat_transform_scale( 17569 flatCoordinates, 17570 0, 17571 flatCoordinates.length, 17572 stride, 17573 sx, 17574 sy, 17575 anchor, 17576 flatCoordinates 17577 ); 17578 this.changed(); 17579 } 17580 } 17581 17582 /** 17583 * Translate the geometry. This modifies the geometry coordinates in place. If 17584 * instead you want a new geometry, first `clone()` this geometry. 17585 * @param {number} deltaX Delta X. 17586 * @param {number} deltaY Delta Y. 17587 * @api 17588 */ 17589 translate(deltaX, deltaY) { 17590 const flatCoordinates = this.getFlatCoordinates(); 17591 if (flatCoordinates) { 17592 const stride = this.getStride(); 17593 transform_translate( 17594 flatCoordinates, 17595 0, 17596 flatCoordinates.length, 17597 stride, 17598 deltaX, 17599 deltaY, 17600 flatCoordinates 17601 ); 17602 this.changed(); 17603 } 17604 } 17605} 17606 17607/** 17608 * @param {number} stride Stride. 17609 * @return {import("./Geometry.js").GeometryLayout} layout Layout. 17610 */ 17611function getLayoutForStride(stride) { 17612 let layout; 17613 if (stride == 2) { 17614 layout = 'XY'; 17615 } else if (stride == 3) { 17616 layout = 'XYZ'; 17617 } else if (stride == 4) { 17618 layout = 'XYZM'; 17619 } 17620 return /** @type {import("./Geometry.js").GeometryLayout} */ (layout); 17621} 17622 17623/** 17624 * @param {import("./Geometry.js").GeometryLayout} layout Layout. 17625 * @return {number} Stride. 17626 */ 17627function getStrideForLayout(layout) { 17628 let stride; 17629 if (layout == 'XY') { 17630 stride = 2; 17631 } else if (layout == 'XYZ' || layout == 'XYM') { 17632 stride = 3; 17633 } else if (layout == 'XYZM') { 17634 stride = 4; 17635 } 17636 return /** @type {number} */ (stride); 17637} 17638 17639/** 17640 * @param {SimpleGeometry} simpleGeometry Simple geometry. 17641 * @param {import("../transform.js").Transform} transform Transform. 17642 * @param {Array<number>} [dest] Destination. 17643 * @return {Array<number>} Transformed flat coordinates. 17644 */ 17645function transformGeom2D(simpleGeometry, transform, dest) { 17646 const flatCoordinates = simpleGeometry.getFlatCoordinates(); 17647 if (!flatCoordinates) { 17648 return null; 17649 } else { 17650 const stride = simpleGeometry.getStride(); 17651 return transform2D( 17652 flatCoordinates, 17653 0, 17654 flatCoordinates.length, 17655 stride, 17656 transform, 17657 dest 17658 ); 17659 } 17660} 17661 17662/* harmony default export */ const geom_SimpleGeometry = (SimpleGeometry); 17663 17664;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/closest.js 17665/** 17666 * @module ol/geom/flat/closest 17667 */ 17668 17669 17670/** 17671 * Returns the point on the 2D line segment flatCoordinates[offset1] to 17672 * flatCoordinates[offset2] that is closest to the point (x, y). Extra 17673 * dimensions are linearly interpolated. 17674 * @param {Array<number>} flatCoordinates Flat coordinates. 17675 * @param {number} offset1 Offset 1. 17676 * @param {number} offset2 Offset 2. 17677 * @param {number} stride Stride. 17678 * @param {number} x X. 17679 * @param {number} y Y. 17680 * @param {Array<number>} closestPoint Closest point. 17681 */ 17682function assignClosest( 17683 flatCoordinates, 17684 offset1, 17685 offset2, 17686 stride, 17687 x, 17688 y, 17689 closestPoint 17690) { 17691 const x1 = flatCoordinates[offset1]; 17692 const y1 = flatCoordinates[offset1 + 1]; 17693 const dx = flatCoordinates[offset2] - x1; 17694 const dy = flatCoordinates[offset2 + 1] - y1; 17695 let offset; 17696 if (dx === 0 && dy === 0) { 17697 offset = offset1; 17698 } else { 17699 const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); 17700 if (t > 1) { 17701 offset = offset2; 17702 } else if (t > 0) { 17703 for (let i = 0; i < stride; ++i) { 17704 closestPoint[i] = lerp( 17705 flatCoordinates[offset1 + i], 17706 flatCoordinates[offset2 + i], 17707 t 17708 ); 17709 } 17710 closestPoint.length = stride; 17711 return; 17712 } else { 17713 offset = offset1; 17714 } 17715 } 17716 for (let i = 0; i < stride; ++i) { 17717 closestPoint[i] = flatCoordinates[offset + i]; 17718 } 17719 closestPoint.length = stride; 17720} 17721 17722/** 17723 * Return the squared of the largest distance between any pair of consecutive 17724 * coordinates. 17725 * @param {Array<number>} flatCoordinates Flat coordinates. 17726 * @param {number} offset Offset. 17727 * @param {number} end End. 17728 * @param {number} stride Stride. 17729 * @param {number} max Max squared delta. 17730 * @return {number} Max squared delta. 17731 */ 17732function maxSquaredDelta(flatCoordinates, offset, end, stride, max) { 17733 let x1 = flatCoordinates[offset]; 17734 let y1 = flatCoordinates[offset + 1]; 17735 for (offset += stride; offset < end; offset += stride) { 17736 const x2 = flatCoordinates[offset]; 17737 const y2 = flatCoordinates[offset + 1]; 17738 const squaredDelta = math_squaredDistance(x1, y1, x2, y2); 17739 if (squaredDelta > max) { 17740 max = squaredDelta; 17741 } 17742 x1 = x2; 17743 y1 = y2; 17744 } 17745 return max; 17746} 17747 17748/** 17749 * @param {Array<number>} flatCoordinates Flat coordinates. 17750 * @param {number} offset Offset. 17751 * @param {Array<number>} ends Ends. 17752 * @param {number} stride Stride. 17753 * @param {number} max Max squared delta.
17754 * @return {number} Max squared delta. 17755 */ 17756function arrayMaxSquaredDelta( 17757 flatCoordinates, 17758 offset, 17759 ends, 17760 stride, 17761 max 17762) { 17763 for (let i = 0, ii = ends.length; i < ii; ++i) { 17764 const end = ends[i]; 17765 max = maxSquaredDelta(flatCoordinates, offset, end, stride, max); 17766 offset = end; 17767 } 17768 return max; 17769} 17770 17771/** 17772 * @param {Array<number>} flatCoordinates Flat coordinates. 17773 * @param {number} offset Offset. 17774 * @param {Array<Array<number>>} endss Endss. 17775 * @param {number} stride Stride. 17776 * @param {number} max Max squared delta. 17777 * @return {number} Max squared delta. 17778 */ 17779function multiArrayMaxSquaredDelta( 17780 flatCoordinates, 17781 offset, 17782 endss, 17783 stride, 17784 max 17785) { 17786 for (let i = 0, ii = endss.length; i < ii; ++i) { 17787 const ends = endss[i]; 17788 max = arrayMaxSquaredDelta(flatCoordinates, offset, ends, stride, max); 17789 offset = ends[ends.length - 1]; 17790 } 17791 return max; 17792} 17793 17794/** 17795 * @param {Array<number>} flatCoordinates Flat coordinates. 17796 * @param {number} offset Offset. 17797 * @param {number} end End. 17798 * @param {number} stride Stride. 17799 * @param {number} maxDelta Max delta. 17800 * @param {boolean} isRing Is ring. 17801 * @param {number} x X. 17802 * @param {number} y Y. 17803 * @param {Array<number>} closestPoint Closest point. 17804 * @param {number} minSquaredDistance Minimum squared distance. 17805 * @param {Array<number>} [tmpPoint] Temporary point object. 17806 * @return {number} Minimum squared distance. 17807 */ 17808function assignClosestPoint( 17809 flatCoordinates, 17810 offset, 17811 end, 17812 stride, 17813 maxDelta, 17814 isRing, 17815 x, 17816 y, 17817 closestPoint, 17818 minSquaredDistance, 17819 tmpPoint 17820) { 17821 if (offset == end) { 17822 return minSquaredDistance; 17823 } 17824 let i, squaredDistance; 17825 if (maxDelta === 0) { 17826 // All points are identical, so just test the first point. 17827 squaredDistance = math_squaredDistance( 17828 x, 17829 y, 17830 flatCoordinates[offset], 17831 flatCoordinates[offset + 1] 17832 ); 17833 if (squaredDistance < minSquaredDistance) { 17834 for (i = 0; i < stride; ++i) { 17835 closestPoint[i] = flatCoordinates[offset + i]; 17836 } 17837 closestPoint.length = stride; 17838 return squaredDistance; 17839 } else { 17840 return minSquaredDistance; 17841 } 17842 } 17843 tmpPoint = tmpPoint ? tmpPoint : [NaN, NaN]; 17844 let index = offset + stride; 17845 while (index < end) { 17846 assignClosest( 17847 flatCoordinates, 17848 index - stride, 17849 index, 17850 stride, 17851 x, 17852 y, 17853 tmpPoint 17854 ); 17855 squaredDistance = math_squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); 17856 if (squaredDistance < minSquaredDistance) { 17857 minSquaredDistance = squaredDistance; 17858 for (i = 0; i < stride; ++i) { 17859 closestPoint[i] = tmpPoint[i]; 17860 } 17861 closestPoint.length = stride; 17862 index += stride; 17863 } else { 17864 // Skip ahead multiple points, because we know that all the skipped 17865 // points cannot be any closer than the closest point we have found so 17866 // far. We know this because we know how close the current point is, how 17867 // close the closest point we have found so far is, and the maximum 17868 // distance between consecutive points. For example, if we're currently 17869 // at distance 10, the best we've found so far is 3, and that the maximum 17870 // distance between consecutive points is 2, then we'll need to skip at 17871 // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of 17872 // finding a closer point. We use Math.max(..., 1) to ensure that we 17873 // always advance at least one point, to avoid an infinite loop. 17874 index += 17875 stride * 17876 Math.max( 17877 ((Math.sqrt(squaredDistance) - Math.sqrt(minSquaredDistance)) / 17878 maxDelta) | 17879 0, 17880 1 17881 ); 17882 } 17883 } 17884 if (isRing) { 17885 // Check the closing segment. 17886 assignClosest( 17887 flatCoordinates, 17888 end - stride, 17889 offset, 17890 stride, 17891 x, 17892 y, 17893 tmpPoint 17894 ); 17895 squaredDistance = math_squaredDistance(x, y, tmpPoint[0], tmpPoint[1]); 17896 if (squaredDistance < minSquaredDistance) { 17897 minSquaredDistance = squaredDistance; 17898 for (i = 0; i < stride; ++i) { 17899 closestPoint[i] = tmpPoint[i]; 17900 } 17901 closestPoint.length = stride; 17902 } 17903 } 17904 return minSquaredDistance; 17905} 17906 17907/** 17908 * @param {Array<number>} flatCoordinates Flat coordinates. 17909 * @param {number} offset Offset. 17910 * @param {Array<number>} ends Ends. 17911 * @param {number} stride Stride. 17912 * @param {number} maxDelta Max delta. 17913 * @param {boolean} isRing Is ring. 17914 * @param {number} x X. 17915 * @param {number} y Y. 17916 * @param {Array<number>} closestPoint Closest point. 17917 * @param {number} minSquaredDistance Minimum squared distance. 17918 * @param {Array<number>} [tmpPoint] Temporary point object. 17919 * @return {number} Minimum squared distance. 17920 */ 17921function assignClosestArrayPoint( 17922 flatCoordinates, 17923 offset, 17924 ends, 17925 stride, 17926 maxDelta, 17927 isRing, 17928 x, 17929 y, 17930 closestPoint, 17931 minSquaredDistance, 17932 tmpPoint 17933) { 17934 tmpPoint = tmpPoint ? tmpPoint : [NaN, NaN]; 17935 for (let i = 0, ii = ends.length; i < ii; ++i) { 17936 const end = ends[i]; 17937 minSquaredDistance = assignClosestPoint( 17938 flatCoordinates, 17939 offset, 17940 end,
vendor: 5,110 bytes, lines 17941-18132
17941 stride, 17942 maxDelta, 17943 isRing, 17944 x, 17945 y, 17946 closestPoint, 17947 minSquaredDistance, 17948 tmpPoint 17949 ); 17950 offset = end; 17951 } 17952 return minSquaredDistance; 17953} 17954 17955/** 17956 * @param {Array<number>} flatCoordinates Flat coordinates. 17957 * @param {number} offset Offset. 17958 * @param {Array<Array<number>>} endss Endss. 17959 * @param {number} stride Stride. 17960 * @param {number} maxDelta Max delta. 17961 * @param {boolean} isRing Is ring. 17962 * @param {number} x X. 17963 * @param {number} y Y. 17964 * @param {Array<number>} closestPoint Closest point. 17965 * @param {number} minSquaredDistance Minimum squared distance. 17966 * @param {Array<number>} [tmpPoint] Temporary point object. 17967 * @return {number} Minimum squared distance. 17968 */ 17969function assignClosestMultiArrayPoint( 17970 flatCoordinates, 17971 offset, 17972 endss, 17973 stride, 17974 maxDelta, 17975 isRing, 17976 x, 17977 y, 17978 closestPoint, 17979 minSquaredDistance, 17980 tmpPoint 17981) { 17982 tmpPoint = tmpPoint ? tmpPoint : [NaN, NaN]; 17983 for (let i = 0, ii = endss.length; i < ii; ++i) { 17984 const ends = endss[i]; 17985 minSquaredDistance = assignClosestArrayPoint( 17986 flatCoordinates, 17987 offset, 17988 ends, 17989 stride, 17990 maxDelta, 17991 isRing, 17992 x, 17993 y, 17994 closestPoint, 17995 minSquaredDistance, 17996 tmpPoint 17997 ); 17998 offset = ends[ends.length - 1]; 17999 } 18000 return minSquaredDistance; 18001} 18002 18003;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/deflate.js 18004/** 18005 * @module ol/geom/flat/deflate 18006 */ 18007 18008/** 18009 * @param {Array<number>} flatCoordinates Flat coordinates. 18010 * @param {number} offset Offset. 18011 * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate. 18012 * @param {number} stride Stride. 18013 * @return {number} offset Offset. 18014 */ 18015function deflateCoordinate(flatCoordinates, offset, coordinate, stride) { 18016 for (let i = 0, ii = coordinate.length; i < ii; ++i) { 18017 flatCoordinates[offset++] = coordinate[i]; 18018 } 18019 return offset; 18020} 18021 18022/** 18023 * @param {Array<number>} flatCoordinates Flat coordinates. 18024 * @param {number} offset Offset. 18025 * @param {Array<import("../../coordinate.js").Coordinate>} coordinates Coordinates. 18026 * @param {number} stride Stride. 18027 * @return {number} offset Offset. 18028 */ 18029function deflateCoordinates( 18030 flatCoordinates, 18031 offset, 18032 coordinates, 18033 stride 18034) { 18035 for (let i = 0, ii = coordinates.length; i < ii; ++i) { 18036 const coordinate = coordinates[i]; 18037 for (let j = 0; j < stride; ++j) { 18038 flatCoordinates[offset++] = coordinate[j]; 18039 } 18040 } 18041 return offset; 18042} 18043 18044/** 18045 * @param {Array<number>} flatCoordinates Flat coordinates. 18046 * @param {number} offset Offset. 18047 * @param {Array<Array<import("../../coordinate.js").Coordinate>>} coordinatess Coordinatess. 18048 * @param {number} stride Stride. 18049 * @param {Array<number>} [ends] Ends. 18050 * @return {Array<number>} Ends. 18051 */ 18052function deflateCoordinatesArray( 18053 flatCoordinates, 18054 offset, 18055 coordinatess, 18056 stride, 18057 ends 18058) { 18059 ends = ends ? ends : []; 18060 let i = 0; 18061 for (let j = 0, jj = coordinatess.length; j < jj; ++j) { 18062 const end = deflateCoordinates( 18063 flatCoordinates, 18064 offset, 18065 coordinatess[j], 18066 stride 18067 ); 18068 ends[i++] = end; 18069 offset = end; 18070 } 18071 ends.length = i; 18072 return ends; 18073} 18074 18075/** 18076 * @param {Array<number>} flatCoordinates Flat coordinates. 18077 * @param {number} offset Offset. 18078 * @param {Array<Array<Array<import("../../coordinate.js").Coordinate>>>} coordinatesss Coordinatesss. 18079 * @param {number} stride Stride. 18080 * @param {Array<Array<number>>} [endss] Endss. 18081 * @return {Array<Array<number>>} Endss. 18082 */ 18083function deflateMultiCoordinatesArray( 18084 flatCoordinates, 18085 offset, 18086 coordinatesss, 18087 stride, 18088 endss 18089) { 18090 endss = endss ? endss : []; 18091 let i = 0; 18092 for (let j = 0, jj = coordinatesss.length; j < jj; ++j) { 18093 const ends = deflateCoordinatesArray( 18094 flatCoordinates, 18095 offset, 18096 coordinatesss[j], 18097 stride, 18098 endss[i] 18099 ); 18100 if (ends.length === 0) { 18101 ends[0] = offset; 18102 } 18103 endss[i++] = ends; 18104 offset = ends[ends.length - 1]; 18105 } 18106 endss.length = i; 18107 return endss; 18108} 18109 18110;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/simplify.js 18111/** 18112 * @module ol/geom/flat/simplify 18113 */ 18114// Based on simplify-js https://github.com/mourner/simplify-js 18115// Copyright (c) 2012, Vladimir Agafonkin 18116// All rights reserved. 18117// 18118// Redistribution and use in source and binary forms, with or without 18119// modification, are permitted provided that the following conditions are met: 18120// 18121// 1. Redistributions of source code must retain the above copyright notice, 18122// this list of conditions and the following disclaimer. 18123// 18124// 2. Redistributions in binary form must reproduce the above copyright 18125// notice, this list of conditions and the following disclaimer in the 18126// documentation and/or other materials provided with the distribution. 18127// 18128// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18129// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18130// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18131// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18132// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18133// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 18134// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 18135// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 18136// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 18137// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 18138// POSSIBILITY OF SUCH DAMAGE. 18139 18140 18141 18142/** 18143 * @param {Array<number>} flatCoordinates Flat coordinates. 18144 * @param {number} offset Offset. 18145 * @param {number} end End. 18146 * @param {number} stride Stride. 18147 * @param {number} squaredTolerance Squared tolerance. 18148 * @param {boolean} highQuality Highest quality. 18149 * @param {Array<number>} [simplifiedFlatCoordinates] Simplified flat 18150 * coordinates. 18151 * @return {Array<number>} Simplified line string. 18152 */ 18153function simplifyLineString( 18154 flatCoordinates, 18155 offset, 18156 end, 18157 stride, 18158 squaredTolerance, 18159 highQuality, 18160 simplifiedFlatCoordinates 18161) { 18162 simplifiedFlatCoordinates = 18163 simplifiedFlatCoordinates !== undefined ? simplifiedFlatCoordinates : []; 18164 if (!highQuality) { 18165 end = radialDistance( 18166 flatCoordinates, 18167 offset, 18168 end, 18169 stride, 18170 squaredTolerance, 18171 simplifiedFlatCoordinates, 18172 0 18173 ); 18174 flatCoordinates = simplifiedFlatCoordinates; 18175 offset = 0; 18176 stride = 2; 18177 } 18178 simplifiedFlatCoordinates.length = douglasPeucker( 18179 flatCoordinates, 18180 offset, 18181 end, 18182 stride, 18183 squaredTolerance, 18184 simplifiedFlatCoordinates, 18185 0 18186 ); 18187 return simplifiedFlatCoordinates; 18188} 18189 18190/** 18191 * @param {Array<number>} flatCoordinates Flat coordinates. 18192 * @param {number} offset Offset. 18193 * @param {number} end End. 18194 * @param {number} stride Stride. 18195 * @param {number} squaredTolerance Squared tolerance. 18196 * @param {Array<number>} simplifiedFlatCoordinates Simplified flat 18197 * coordinates. 18198 * @param {number} simplifiedOffset Simplified offset. 18199 * @return {number} Simplified offset. 18200 */ 18201function douglasPeucker( 18202 flatCoordinates, 18203 offset, 18204 end, 18205 stride, 18206 squaredTolerance, 18207 simplifiedFlatCoordinates, 18208 simplifiedOffset 18209) { 18210 const n = (end - offset) / stride; 18211 if (n < 3) { 18212 for (; offset < end; offset += stride) { 18213 simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset]; 18214 simplifiedFlatCoordinates[simplifiedOffset++] = 18215 flatCoordinates[offset + 1]; 18216 } 18217 return simplifiedOffset; 18218 } 18219 /** @type {Array<number>} */ 18220 const markers = new Array(n); 18221 markers[0] = 1; 18222 markers[n - 1] = 1; 18223 /** @type {Array<number>} */ 18224 const stack = [offset, end - stride]; 18225 let index = 0; 18226 while (stack.length > 0) { 18227 const last = stack.pop(); 18228 const first = stack.pop(); 18229 let maxSquaredDistance = 0; 18230 const x1 = flatCoordinates[first]; 18231 const y1 = flatCoordinates[first + 1]; 18232 const x2 = flatCoordinates[last]; 18233 const y2 = flatCoordinates[last + 1]; 18234 for (let i = first + stride; i < last; i += stride) { 18235 const x = flatCoordinates[i]; 18236 const y = flatCoordinates[i + 1]; 18237 const squaredDistance = squaredSegmentDistance(x, y, x1, y1, x2, y2); 18238 if (squaredDistance > maxSquaredDistance) { 18239 index = i; 18240 maxSquaredDistance = squaredDistance; 18241 } 18242 } 18243 if (maxSquaredDistance > squaredTolerance) { 18244 markers[(index - offset) / stride] = 1; 18245 if (first + stride < index) { 18246 stack.push(first, index); 18247 } 18248 if (index + stride < last) { 18249 stack.push(index, last); 18250 } 18251 } 18252 } 18253 for (let i = 0; i < n; ++i) { 18254 if (markers[i]) { 18255 simplifiedFlatCoordinates[simplifiedOffset++] = 18256 flatCoordinates[offset + i * stride]; 18257 simplifiedFlatCoordinates[simplifiedOffset++] = 18258 flatCoordinates[offset + i * stride + 1]; 18259 } 18260 } 18261 return simplifiedOffset; 18262} 18263 18264/** 18265 * @param {Array<number>} flatCoordinates Flat coordinates. 18266 * @param {number} offset Offset. 18267 * @param {Array<number>} ends Ends. 18268 * @param {number} stride Stride. 18269 * @param {number} squaredTolerance Squared tolerance. 18270 * @param {Array<number>} simplifiedFlatCoordinates Simplified flat 18271 * coordinates. 18272 * @param {number} simplifiedOffset Simplified offset. 18273 * @param {Array<number>} simplifiedEnds Simplified ends. 18274 * @return {number} Simplified offset. 18275 */ 18276function douglasPeuckerArray( 18277 flatCoordinates, 18278 offset, 18279 ends, 18280 stride, 18281 squaredTolerance, 18282 simplifiedFlatCoordinates, 18283 simplifiedOffset, 18284 simplifiedEnds 18285) { 18286 for (let i = 0, ii = ends.length; i < ii; ++i) { 18287 const end = ends[i]; 18288 simplifiedOffset = douglasPeucker( 18289 flatCoordinates, 18290 offset, 18291 end,
18292 stride, 18293 squaredTolerance, 18294 simplifiedFlatCoordinates, 18295 simplifiedOffset 18296 ); 18297 simplifiedEnds.push(simplifiedOffset); 18298 offset = end; 18299 } 18300 return simplifiedOffset; 18301} 18302 18303/** 18304 * @param {Array<number>} flatCoordinates Flat coordinates. 18305 * @param {number} offset Offset. 18306 * @param {Array<Array<number>>} endss Endss. 18307 * @param {number} stride Stride. 18308 * @param {number} squaredTolerance Squared tolerance. 18309 * @param {Array<number>} simplifiedFlatCoordinates Simplified flat 18310 * coordinates. 18311 * @param {number} simplifiedOffset Simplified offset. 18312 * @param {Array<Array<number>>} simplifiedEndss Simplified endss. 18313 * @return {number} Simplified offset. 18314 */ 18315function douglasPeuckerMultiArray( 18316 flatCoordinates, 18317 offset, 18318 endss, 18319 stride, 18320 squaredTolerance, 18321 simplifiedFlatCoordinates, 18322 simplifiedOffset, 18323 simplifiedEndss 18324) { 18325 for (let i = 0, ii = endss.length; i < ii; ++i) { 18326 const ends = endss[i]; 18327 const simplifiedEnds = []; 18328 simplifiedOffset = douglasPeuckerArray( 18329 flatCoordinates, 18330 offset, 18331 ends, 18332 stride, 18333 squaredTolerance, 18334 simplifiedFlatCoordinates, 18335 simplifiedOffset, 18336 simplifiedEnds 18337 ); 18338 simplifiedEndss.push(simplifiedEnds); 18339 offset = ends[ends.length - 1]; 18340 } 18341 return simplifiedOffset; 18342} 18343 18344/** 18345 * @param {Array<number>} flatCoordinates Flat coordinates. 18346 * @param {number} offset Offset. 18347 * @param {number} end End. 18348 * @param {number} stride Stride. 18349 * @param {number} squaredTolerance Squared tolerance. 18350 * @param {Array<number>} simplifiedFlatCoordinates Simplified flat 18351 * coordinates. 18352 * @param {number} simplifiedOffset Simplified offset. 18353 * @return {number} Simplified offset. 18354 */ 18355function radialDistance( 18356 flatCoordinates, 18357 offset, 18358 end, 18359 stride, 18360 squaredTolerance, 18361 simplifiedFlatCoordinates, 18362 simplifiedOffset 18363) { 18364 if (end <= offset + stride) { 18365 // zero or one point, no simplification possible, so copy and return 18366 for (; offset < end; offset += stride) { 18367 simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset]; 18368 simplifiedFlatCoordinates[simplifiedOffset++] = 18369 flatCoordinates[offset + 1]; 18370 } 18371 return simplifiedOffset; 18372 } 18373 let x1 = flatCoordinates[offset]; 18374 let y1 = flatCoordinates[offset + 1]; 18375 // copy first point 18376 simplifiedFlatCoordinates[simplifiedOffset++] = x1; 18377 simplifiedFlatCoordinates[simplifiedOffset++] = y1; 18378 let x2 = x1; 18379 let y2 = y1; 18380 for (offset += stride; offset < end; offset += stride) { 18381 x2 = flatCoordinates[offset]; 18382 y2 = flatCoordinates[offset + 1]; 18383 if (squaredDistance(x1, y1, x2, y2) > squaredTolerance) { 18384 // copy point at offset 18385 simplifiedFlatCoordinates[simplifiedOffset++] = x2; 18386 simplifiedFlatCoordinates[simplifiedOffset++] = y2; 18387 x1 = x2; 18388 y1 = y2; 18389 } 18390 } 18391 if (x2 != x1 || y2 != y1) { 18392 // copy last point 18393 simplifiedFlatCoordinates[simplifiedOffset++] = x2; 18394 simplifiedFlatCoordinates[simplifiedOffset++] = y2; 18395 } 18396 return simplifiedOffset; 18397} 18398 18399/** 18400 * @param {number} value Value. 18401 * @param {number} tolerance Tolerance. 18402 * @return {number} Rounded value. 18403 */ 18404function snap(value, tolerance) { 18405 return tolerance * Math.round(value / tolerance); 18406} 18407 18408/** 18409 * Simplifies a line string using an algorithm designed by Tim Schaub. 18410 * Coordinates are snapped to the nearest value in a virtual grid and 18411 * consecutive duplicate coordinates are discarded. This effectively preserves 18412 * topology as the simplification of any subsection of a line string is 18413 * independent of the rest of the line string. This means that, for examples, 18414 * the common edge between two polygons will be simplified to the same line 18415 * string independently in both polygons. This implementation uses a single 18416 * pass over the coordinates and eliminates intermediate collinear points. 18417 * @param {Array<number>} flatCoordinates Flat coordinates. 18418 * @param {number} offset Offset. 18419 * @param {number} end End. 18420 * @param {number} stride Stride. 18421 * @param {number} tolerance Tolerance. 18422 * @param {Array<number>} simplifiedFlatCoordinates Simplified flat 18423 * coordinates. 18424 * @param {number} simplifiedOffset Simplified offset. 18425 * @return {number} Simplified offset. 18426 */ 18427function quantize( 18428 flatCoordinates, 18429 offset, 18430 end, 18431 stride, 18432 tolerance, 18433 simplifiedFlatCoordinates, 18434 simplifiedOffset 18435) { 18436 // do nothing if the line is empty 18437 if (offset == end) { 18438 return simplifiedOffset; 18439 } 18440 // snap the first coordinate (P1) 18441 let x1 = snap(flatCoordinates[offset], tolerance); 18442 let y1 = snap(flatCoordinates[offset + 1], tolerance); 18443 offset += stride; 18444 // add the first coordinate to the output 18445 simplifiedFlatCoordinates[simplifiedOffset++] = x1; 18446 simplifiedFlatCoordinates[simplifiedOffset++] = y1; 18447 // find the next coordinate that does not snap to the same value as the first 18448 // coordinate (P2) 18449 let x2, y2; 18450 do { 18451 x2 = snap(flatCoordinates[offset], tolerance); 18452 y2 = snap(flatCoordinates[offset + 1], tolerance); 18453 offset += stride; 18454 if (offset == end) { 18455 // all coordinates snap to the same value, the line collapses to a point 18456 // push the last snapped value anyway to ensure that the output contains 18457 // at least two points 18458 // FIXME should we really return at least two points anyway? 18459 simplifiedFlatCoordinates[simplifiedOffset++] = x2; 18460 simplifiedFlatCoordinates[simplifiedOffset++] = y2; 18461 return simplifiedOffset; 18462 } 18463 } while (x2 == x1 && y2 == y1); 18464 while (offset < end) { 18465 // snap the next coordinate (P3) 18466 const x3 = snap(flatCoordinates[offset], tolerance); 18467 const y3 = snap(flatCoordinates[offset + 1], tolerance); 18468 offset += stride; 18469 // skip P3 if it is equal to P2 18470 if (x3 == x2 && y3 == y2) { 18471 continue; 18472 } 18473 // calculate the delta between P1 and P2 18474 const dx1 = x2 - x1; 18475 const dy1 = y2 - y1; 18476 // calculate the delta between P3 and P1 18477 const dx2 = x3 - x1; 18478 const dy2 = y3 - y1; 18479 // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from 18480 // P1 in the same direction then P2 is on the straight line between P1 and 18481 // P3 18482 if ( 18483 dx1 * dy2 == dy1 * dx2 && 18484 ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) && 18485 ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1)) 18486 ) { 18487 // discard P2 and set P2 = P3 18488 x2 = x3; 18489 y2 = y3;
18490 continue; 18491 } 18492 // either P1, P2, and P3 are not colinear, or they are colinear but P3 is 18493 // between P3 and P1 or on the opposite half of the line to P2. add P2, 18494 // and continue with P1 = P2 and P2 = P3 18495 simplifiedFlatCoordinates[simplifiedOffset++] = x2; 18496 simplifiedFlatCoordinates[simplifiedOffset++] = y2; 18497 x1 = x2; 18498 y1 = y2; 18499 x2 = x3; 18500 y2 = y3; 18501 } 18502 // add the last point (P2) 18503 simplifiedFlatCoordinates[simplifiedOffset++] = x2; 18504 simplifiedFlatCoordinates[simplifiedOffset++] = y2; 18505 return simplifiedOffset; 18506} 18507 18508/** 18509 * @param {Array<number>} flatCoordinates Flat coordinates. 18510 * @param {number} offset Offset. 18511 * @param {Array<number>} ends Ends. 18512 * @param {number} stride Stride. 18513 * @param {number} tolerance Tolerance. 18514 * @param {Array<number>} simplifiedFlatCoordinates Simplified flat 18515 * coordinates. 18516 * @param {number} simplifiedOffset Simplified offset. 18517 * @param {Array<number>} simplifiedEnds Simplified ends. 18518 * @return {number} Simplified offset. 18519 */ 18520function quantizeArray( 18521 flatCoordinates, 18522 offset, 18523 ends, 18524 stride, 18525 tolerance, 18526 simplifiedFlatCoordinates, 18527 simplifiedOffset, 18528 simplifiedEnds 18529) { 18530 for (let i = 0, ii = ends.length; i < ii; ++i) { 18531 const end = ends[i]; 18532 simplifiedOffset = quantize( 18533 flatCoordinates, 18534 offset, 18535 end, 18536 stride, 18537 tolerance, 18538 simplifiedFlatCoordinates, 18539 simplifiedOffset 18540 ); 18541 simplifiedEnds.push(simplifiedOffset); 18542 offset = end; 18543 } 18544 return simplifiedOffset; 18545} 18546 18547/** 18548 * @param {Array<number>} flatCoordinates Flat coordinates. 18549 * @param {number} offset Offset. 18550 * @param {Array<Array<number>>} endss Endss. 18551 * @param {number} stride Stride. 18552 * @param {number} tolerance Tolerance. 18553 * @param {Array<number>} simplifiedFlatCoordinates Simplified flat 18554 * coordinates. 18555 * @param {number} simplifiedOffset Simplified offset. 18556 * @param {Array<Array<number>>} simplifiedEndss Simplified endss. 18557 * @return {number} Simplified offset. 18558 */ 18559function quantizeMultiArray( 18560 flatCoordinates, 18561 offset, 18562 endss, 18563 stride, 18564 tolerance, 18565 simplifiedFlatCoordinates, 18566 simplifiedOffset, 18567 simplifiedEndss 18568) { 18569 for (let i = 0, ii = endss.length; i < ii; ++i) { 18570 const ends = endss[i]; 18571 const simplifiedEnds = []; 18572 simplifiedOffset = quantizeArray( 18573 flatCoordinates, 18574 offset, 18575 ends, 18576 stride, 18577 tolerance, 18578 simplifiedFlatCoordinates, 18579 simplifiedOffset, 18580 simplifiedEnds 18581 ); 18582 simplifiedEndss.push(simplifiedEnds); 18583 offset = ends[ends.length - 1]; 18584 } 18585 return simplifiedOffset; 18586} 18587 18588;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/inflate.js 18589/** 18590 * @module ol/geom/flat/inflate 18591 */ 18592 18593/** 18594 * @param {Array<number>} flatCoordinates Flat coordinates. 18595 * @param {number} offset Offset. 18596 * @param {number} end End. 18597 * @param {number} stride Stride. 18598 * @param {Array<import("../../coordinate.js").Coordinate>} [coordinates] Coordinates. 18599 * @return {Array<import("../../coordinate.js").Coordinate>} Coordinates. 18600 */ 18601function inflateCoordinates( 18602 flatCoordinates, 18603 offset, 18604 end, 18605 stride, 18606 coordinates 18607) { 18608 coordinates = coordinates !== undefined ? coordinates : []; 18609 let i = 0; 18610 for (let j = offset; j < end; j += stride) { 18611 coordinates[i++] = flatCoordinates.slice(j, j + stride); 18612 } 18613 coordinates.length = i; 18614 return coordinates; 18615} 18616 18617/** 18618 * @param {Array<number>} flatCoordinates Flat coordinates. 18619 * @param {number} offset Offset. 18620 * @param {Array<number>} ends Ends. 18621 * @param {number} stride Stride. 18622 * @param {Array<Array<import("../../coordinate.js").Coordinate>>} [coordinatess] Coordinatess. 18623 * @return {Array<Array<import("../../coordinate.js").Coordinate>>} Coordinatess. 18624 */ 18625function inflateCoordinatesArray( 18626 flatCoordinates, 18627 offset, 18628 ends, 18629 stride, 18630 coordinatess 18631) { 18632 coordinatess = coordinatess !== undefined ? coordinatess : []; 18633 let i = 0; 18634 for (let j = 0, jj = ends.length; j < jj; ++j) { 18635 const end = ends[j]; 18636 coordinatess[i++] = inflateCoordinates( 18637 flatCoordinates, 18638 offset, 18639 end, 18640 stride, 18641 coordinatess[i] 18642 ); 18643 offset = end; 18644 } 18645 coordinatess.length = i; 18646 return coordinatess; 18647} 18648 18649/** 18650 * @param {Array<number>} flatCoordinates Flat coordinates. 18651 * @param {number} offset Offset. 18652 * @param {Array<Array<number>>} endss Endss. 18653 * @param {number} stride Stride. 18654 * @param {Array<Array<Array<import("../../coordinate.js").Coordinate>>>} [coordinatesss] 18655 * Coordinatesss. 18656 * @return {Array<Array<Array<import("../../coordinate.js").Coordinate>>>} Coordinatesss. 18657 */ 18658function inflateMultiCoordinatesArray( 18659 flatCoordinates, 18660 offset, 18661 endss, 18662 stride, 18663 coordinatesss 18664) { 18665 coordinatesss = coordinatesss !== undefined ? coordinatesss : []; 18666 let i = 0; 18667 for (let j = 0, jj = endss.length; j < jj; ++j) { 18668 const ends = endss[j]; 18669 coordinatesss[i++] = 18670 ends.length === 1 && ends[0] === offset 18671 ? [] 18672 : inflateCoordinatesArray( 18673 flatCoordinates, 18674 offset, 18675 ends,
18676 stride, 18677 coordinatesss[i] 18678 ); 18679 offset = ends[ends.length - 1]; 18680 } 18681 coordinatesss.length = i; 18682 return coordinatesss; 18683} 18684 18685;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/area.js 18686/** 18687 * @module ol/geom/flat/area 18688 */ 18689 18690/** 18691 * @param {Array<number>} flatCoordinates Flat coordinates. 18692 * @param {number} offset Offset. 18693 * @param {number} end End. 18694 * @param {number} stride Stride. 18695 * @return {number} Area. 18696 */ 18697function linearRing(flatCoordinates, offset, end, stride) { 18698 let twiceArea = 0; 18699 let x1 = flatCoordinates[end - stride]; 18700 let y1 = flatCoordinates[end - stride + 1]; 18701 for (; offset < end; offset += stride) { 18702 const x2 = flatCoordinates[offset]; 18703 const y2 = flatCoordinates[offset + 1]; 18704 twiceArea += y1 * x2 - x1 * y2; 18705 x1 = x2; 18706 y1 = y2; 18707 } 18708 return twiceArea / 2; 18709} 18710 18711/** 18712 * @param {Array<number>} flatCoordinates Flat coordinates. 18713 * @param {number} offset Offset. 18714 * @param {Array<number>} ends Ends. 18715 * @param {number} stride Stride. 18716 * @return {number} Area. 18717 */ 18718function linearRings(flatCoordinates, offset, ends, stride) { 18719 let area = 0; 18720 for (let i = 0, ii = ends.length; i < ii; ++i) { 18721 const end = ends[i]; 18722 area += linearRing(flatCoordinates, offset, end, stride); 18723 offset = end; 18724 } 18725 return area; 18726} 18727 18728/** 18729 * @param {Array<number>} flatCoordinates Flat coordinates. 18730 * @param {number} offset Offset. 18731 * @param {Array<Array<number>>} endss Endss. 18732 * @param {number} stride Stride. 18733 * @return {number} Area. 18734 */ 18735function linearRingss(flatCoordinates, offset, endss, stride) { 18736 let area = 0; 18737 for (let i = 0, ii = endss.length; i < ii; ++i) { 18738 const ends = endss[i]; 18739 area += linearRings(flatCoordinates, offset, ends, stride); 18740 offset = ends[ends.length - 1]; 18741 } 18742 return area; 18743} 18744 18745;// CONCATENATED MODULE: ./node_modules/ol/geom/LinearRing.js 18746/** 18747 * @module ol/geom/LinearRing 18748 */ 18749 18750 18751 18752 18753 18754 18755 18756 18757/** 18758 * @classdesc 18759 * Linear ring geometry. Only used as part of polygon; cannot be rendered 18760 * on its own. 18761 * 18762 * @api 18763 */ 18764class LinearRing extends geom_SimpleGeometry { 18765 /** 18766 * @param {Array<import("../coordinate.js").Coordinate>|Array<number>} coordinates Coordinates. 18767 * For internal use, flat coordinates in combination with `layout` are also accepted. 18768 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 18769 */ 18770 constructor(coordinates, layout) { 18771 super(); 18772 18773 /** 18774 * @private 18775 * @type {number} 18776 */ 18777 this.maxDelta_ = -1; 18778 18779 /** 18780 * @private 18781 * @type {number} 18782 */ 18783 this.maxDeltaRevision_ = -1; 18784 18785 if (layout !== undefined && !Array.isArray(coordinates[0])) { 18786 this.setFlatCoordinates( 18787 layout, 18788 /** @type {Array<number>} */ (coordinates) 18789 ); 18790 } else { 18791 this.setCoordinates( 18792 /** @type {Array<import("../coordinate.js").Coordinate>} */ ( 18793 coordinates 18794 ), 18795 layout 18796 ); 18797 } 18798 } 18799 18800 /** 18801 * Make a complete copy of the geometry. 18802 * @return {!LinearRing} Clone. 18803 * @api 18804 */ 18805 clone() { 18806 return new LinearRing(this.flatCoordinates.slice(), this.layout); 18807 } 18808 18809 /** 18810 * @param {number} x X. 18811 * @param {number} y Y. 18812 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 18813 * @param {number} minSquaredDistance Minimum squared distance. 18814 * @return {number} Minimum squared distance. 18815 */ 18816 closestPointXY(x, y, closestPoint, minSquaredDistance) { 18817 if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) { 18818 return minSquaredDistance; 18819 } 18820 if (this.maxDeltaRevision_ != this.getRevision()) { 18821 this.maxDelta_ = Math.sqrt( 18822 maxSquaredDelta( 18823 this.flatCoordinates, 18824 0, 18825 this.flatCoordinates.length, 18826 this.stride, 18827 0 18828 ) 18829 ); 18830 this.maxDeltaRevision_ = this.getRevision(); 18831 } 18832 return assignClosestPoint( 18833 this.flatCoordinates, 18834 0, 18835 this.flatCoordinates.length, 18836 this.stride, 18837 this.maxDelta_, 18838 true, 18839 x, 18840 y, 18841 closestPoint, 18842 minSquaredDistance 18843 ); 18844 } 18845 18846 /** 18847 * Return the area of the linear ring on projected plane. 18848 * @return {number} Area (on projected plane). 18849 * @api 18850 */ 18851 getArea() { 18852 return linearRing( 18853 this.flatCoordinates, 18854 0, 18855 this.flatCoordinates.length, 18856 this.stride 18857 ); 18858 } 18859 18860 /** 18861 * Return the coordinates of the linear ring. 18862 * @return {Array<import("../coordinate.js").Coordinate>} Coordinates. 18863 * @api 18864 */ 18865 getCoordinates() { 18866 return inflateCoordinates( 18867 this.flatCoordinates, 18868 0, 18869 this.flatCoordinates.length, 18870 this.stride 18871 ); 18872 } 18873 18874 /** 18875 * @param {number} squaredTolerance Squared tolerance. 18876 * @return {LinearRing} Simplified LinearRing. 18877 * @protected 18878 */ 18879 getSimplifiedGeometryInternal(squaredTolerance) { 18880 const simplifiedFlatCoordinates = []; 18881 simplifiedFlatCoordinates.length = douglasPeucker( 18882 this.flatCoordinates, 18883 0, 18884 this.flatCoordinates.length, 18885 this.stride, 18886 squaredTolerance, 18887 simplifiedFlatCoordinates, 18888 0 18889 ); 18890 return new LinearRing(simplifiedFlatCoordinates, 'XY'); 18891 } 18892 18893 /** 18894 * Get the type of this geometry. 18895 * @return {import("./Geometry.js").Type} Geometry type. 18896 * @api 18897 */ 18898 getType() { 18899 return 'LinearRing'; 18900 } 18901 18902 /** 18903 * Test if the geometry and the passed extent intersect. 18904 * @param {import("../extent.js").Extent} extent Extent. 18905 * @return {boolean} `true` if the geometry and the extent intersect. 18906 * @api 18907 */ 18908 intersectsExtent(extent) { 18909 return false;
18910 } 18911 18912 /** 18913 * Set the coordinates of the linear ring. 18914 * @param {!Array<import("../coordinate.js").Coordinate>} coordinates Coordinates. 18915 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 18916 * @api 18917 */ 18918 setCoordinates(coordinates, layout) { 18919 this.setLayout(layout, coordinates, 1); 18920 if (!this.flatCoordinates) { 18921 this.flatCoordinates = []; 18922 } 18923 this.flatCoordinates.length = deflateCoordinates( 18924 this.flatCoordinates, 18925 0, 18926 coordinates, 18927 this.stride 18928 ); 18929 this.changed(); 18930 } 18931} 18932 18933/* harmony default export */ const geom_LinearRing = (LinearRing); 18934 18935;// CONCATENATED MODULE: ./node_modules/ol/geom/Point.js 18936/** 18937 * @module ol/geom/Point 18938 */ 18939 18940 18941 18942 18943 18944/** 18945 * @classdesc 18946 * Point geometry. 18947 * 18948 * @api 18949 */ 18950class Point extends geom_SimpleGeometry { 18951 /** 18952 * @param {import("../coordinate.js").Coordinate} coordinates Coordinates. 18953 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 18954 */ 18955 constructor(coordinates, layout) { 18956 super(); 18957 this.setCoordinates(coordinates, layout); 18958 } 18959 18960 /** 18961 * Make a complete copy of the geometry. 18962 * @return {!Point} Clone. 18963 * @api 18964 */ 18965 clone() { 18966 const point = new Point(this.flatCoordinates.slice(), this.layout); 18967 point.applyProperties(this); 18968 return point; 18969 } 18970 18971 /** 18972 * @param {number} x X. 18973 * @param {number} y Y. 18974 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 18975 * @param {number} minSquaredDistance Minimum squared distance. 18976 * @return {number} Minimum squared distance. 18977 */ 18978 closestPointXY(x, y, closestPoint, minSquaredDistance) { 18979 const flatCoordinates = this.flatCoordinates; 18980 const squaredDistance = math_squaredDistance( 18981 x, 18982 y, 18983 flatCoordinates[0], 18984 flatCoordinates[1] 18985 ); 18986 if (squaredDistance < minSquaredDistance) { 18987 const stride = this.stride; 18988 for (let i = 0; i < stride; ++i) { 18989 closestPoint[i] = flatCoordinates[i]; 18990 } 18991 closestPoint.length = stride; 18992 return squaredDistance; 18993 } else { 18994 return minSquaredDistance; 18995 } 18996 } 18997 18998 /** 18999 * Return the coordinate of the point. 19000 * @return {import("../coordinate.js").Coordinate} Coordinates. 19001 * @api 19002 */ 19003 getCoordinates() { 19004 return !this.flatCoordinates ? [] : this.flatCoordinates.slice(); 19005 } 19006 19007 /** 19008 * @param {import("../extent.js").Extent} extent Extent. 19009 * @protected 19010 * @return {import("../extent.js").Extent} extent Extent. 19011 */ 19012 computeExtent(extent) { 19013 return createOrUpdateFromCoordinate(this.flatCoordinates, extent); 19014 } 19015 19016 /** 19017 * Get the type of this geometry. 19018 * @return {import("./Geometry.js").Type} Geometry type. 19019 * @api 19020 */ 19021 getType() { 19022 return 'Point'; 19023 } 19024 19025 /** 19026 * Test if the geometry and the passed extent intersect. 19027 * @param {import("../extent.js").Extent} extent Extent. 19028 * @return {boolean} `true` if the geometry and the extent intersect. 19029 * @api 19030 */ 19031 intersectsExtent(extent) { 19032 return containsXY(extent, this.flatCoordinates[0], this.flatCoordinates[1]); 19033 } 19034 19035 /** 19036 * @param {!Array<*>} coordinates Coordinates. 19037 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 19038 * @api 19039 */ 19040 setCoordinates(coordinates, layout) { 19041 this.setLayout(layout, coordinates, 0); 19042 if (!this.flatCoordinates) { 19043 this.flatCoordinates = []; 19044 } 19045 this.flatCoordinates.length = deflateCoordinate( 19046 this.flatCoordinates, 19047 0, 19048 coordinates, 19049 this.stride 19050 ); 19051 this.changed(); 19052 } 19053} 19054 19055/* harmony default export */ const geom_Point = (Point); 19056 19057;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/contains.js 19058/** 19059 * @module ol/geom/flat/contains 19060 */ 19061 19062 19063/** 19064 * @param {Array<number>} flatCoordinates Flat coordinates. 19065 * @param {number} offset Offset. 19066 * @param {number} end End. 19067 * @param {number} stride Stride. 19068 * @param {import("../../extent.js").Extent} extent Extent. 19069 * @return {boolean} Contains extent. 19070 */ 19071function linearRingContainsExtent( 19072 flatCoordinates, 19073 offset, 19074 end, 19075 stride, 19076 extent 19077) { 19078 const outside = forEachCorner( 19079 extent, 19080 /** 19081 * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate. 19082 * @return {boolean} Contains (x, y). 19083 */ 19084 function (coordinate) { 19085 return !linearRingContainsXY( 19086 flatCoordinates, 19087 offset, 19088 end,
vendor: 29,035 bytes, lines 19089-20222
19089 stride, 19090 coordinate[0], 19091 coordinate[1] 19092 ); 19093 } 19094 ); 19095 return !outside; 19096} 19097 19098/** 19099 * @param {Array<number>} flatCoordinates Flat coordinates. 19100 * @param {number} offset Offset. 19101 * @param {number} end End. 19102 * @param {number} stride Stride. 19103 * @param {number} x X. 19104 * @param {number} y Y. 19105 * @return {boolean} Contains (x, y). 19106 */ 19107function linearRingContainsXY( 19108 flatCoordinates, 19109 offset, 19110 end, 19111 stride, 19112 x, 19113 y 19114) { 19115 // https://geomalgorithms.com/a03-_inclusion.html 19116 // Copyright 2000 softSurfer, 2012 Dan Sunday 19117 // This code may be freely used and modified for any purpose 19118 // providing that this copyright notice is included with it. 19119 // SoftSurfer makes no warranty for this code, and cannot be held 19120 // liable for any real or imagined damage resulting from its use. 19121 // Users of this code must verify correctness for their application. 19122 let wn = 0; 19123 let x1 = flatCoordinates[end - stride]; 19124 let y1 = flatCoordinates[end - stride + 1]; 19125 for (; offset < end; offset += stride) { 19126 const x2 = flatCoordinates[offset]; 19127 const y2 = flatCoordinates[offset + 1]; 19128 if (y1 <= y) { 19129 if (y2 > y && (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1) > 0) { 19130 wn++; 19131 } 19132 } else if (y2 <= y && (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1) < 0) { 19133 wn--; 19134 } 19135 x1 = x2; 19136 y1 = y2; 19137 } 19138 return wn !== 0; 19139} 19140 19141/** 19142 * @param {Array<number>} flatCoordinates Flat coordinates. 19143 * @param {number} offset Offset. 19144 * @param {Array<number>} ends Ends. 19145 * @param {number} stride Stride. 19146 * @param {number} x X. 19147 * @param {number} y Y. 19148 * @return {boolean} Contains (x, y). 19149 */ 19150function linearRingsContainsXY( 19151 flatCoordinates, 19152 offset, 19153 ends, 19154 stride, 19155 x, 19156 y 19157) { 19158 if (ends.length === 0) { 19159 return false; 19160 } 19161 if (!linearRingContainsXY(flatCoordinates, offset, ends[0], stride, x, y)) { 19162 return false; 19163 } 19164 for (let i = 1, ii = ends.length; i < ii; ++i) { 19165 if ( 19166 linearRingContainsXY(flatCoordinates, ends[i - 1], ends[i], stride, x, y) 19167 ) { 19168 return false; 19169 } 19170 } 19171 return true; 19172} 19173 19174/** 19175 * @param {Array<number>} flatCoordinates Flat coordinates. 19176 * @param {number} offset Offset. 19177 * @param {Array<Array<number>>} endss Endss. 19178 * @param {number} stride Stride. 19179 * @param {number} x X. 19180 * @param {number} y Y. 19181 * @return {boolean} Contains (x, y). 19182 */ 19183function linearRingssContainsXY( 19184 flatCoordinates, 19185 offset, 19186 endss, 19187 stride, 19188 x, 19189 y 19190) { 19191 if (endss.length === 0) { 19192 return false; 19193 } 19194 for (let i = 0, ii = endss.length; i < ii; ++i) { 19195 const ends = endss[i]; 19196 if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) { 19197 return true; 19198 } 19199 offset = ends[ends.length - 1]; 19200 } 19201 return false; 19202} 19203 19204;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/interiorpoint.js 19205/** 19206 * @module ol/geom/flat/interiorpoint 19207 */ 19208 19209 19210 19211/** 19212 * Calculates a point that is likely to lie in the interior of the linear rings. 19213 * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint. 19214 * @param {Array<number>} flatCoordinates Flat coordinates. 19215 * @param {number} offset Offset. 19216 * @param {Array<number>} ends Ends. 19217 * @param {number} stride Stride. 19218 * @param {Array<number>} flatCenters Flat centers. 19219 * @param {number} flatCentersOffset Flat center offset. 19220 * @param {Array<number>} [dest] Destination. 19221 * @return {Array<number>} Destination point as XYM coordinate, where M is the 19222 * length of the horizontal intersection that the point belongs to. 19223 */ 19224function getInteriorPointOfArray( 19225 flatCoordinates, 19226 offset, 19227 ends, 19228 stride, 19229 flatCenters, 19230 flatCentersOffset, 19231 dest 19232) { 19233 let i, ii, x, x1, x2, y1, y2; 19234 const y = flatCenters[flatCentersOffset + 1]; 19235 /** @type {Array<number>} */ 19236 const intersections = []; 19237 // Calculate intersections with the horizontal line 19238 for (let r = 0, rr = ends.length; r < rr; ++r) { 19239 const end = ends[r]; 19240 x1 = flatCoordinates[end - stride]; 19241 y1 = flatCoordinates[end - stride + 1]; 19242 for (i = offset; i < end; i += stride) { 19243 x2 = flatCoordinates[i]; 19244 y2 = flatCoordinates[i + 1]; 19245 if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) { 19246 x = ((y - y1) / (y2 - y1)) * (x2 - x1) + x1; 19247 intersections.push(x); 19248 } 19249 x1 = x2; 19250 y1 = y2; 19251 } 19252 } 19253 // Find the longest segment of the horizontal line that has its center point 19254 // inside the linear ring. 19255 let pointX = NaN; 19256 let maxSegmentLength = -Infinity; 19257 intersections.sort(numberSafeCompareFunction); 19258 x1 = intersections[0]; 19259 for (i = 1, ii = intersections.length; i < ii; ++i) { 19260 x2 = intersections[i]; 19261 const segmentLength = Math.abs(x2 - x1); 19262 if (segmentLength > maxSegmentLength) { 19263 x = (x1 + x2) / 2; 19264 if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) { 19265 pointX = x; 19266 maxSegmentLength = segmentLength; 19267 } 19268 } 19269 x1 = x2; 19270 } 19271 if (isNaN(pointX)) { 19272 // There is no horizontal line that has its center point inside the linear 19273 // ring. Use the center of the the linear ring's extent. 19274 pointX = flatCenters[flatCentersOffset]; 19275 } 19276 if (dest) { 19277 dest.push(pointX, y, maxSegmentLength); 19278 return dest; 19279 } else { 19280 return [pointX, y, maxSegmentLength]; 19281 } 19282} 19283 19284/** 19285 * @param {Array<number>} flatCoordinates Flat coordinates. 19286 * @param {number} offset Offset. 19287 * @param {Array<Array<number>>} endss Endss. 19288 * @param {number} stride Stride. 19289 * @param {Array<number>} flatCenters Flat centers. 19290 * @return {Array<number>} Interior points as XYM coordinates, where M is the 19291 * length of the horizontal intersection that the point belongs to. 19292 */ 19293function getInteriorPointsOfMultiArray( 19294 flatCoordinates, 19295 offset, 19296 endss, 19297 stride, 19298 flatCenters 19299) { 19300 let interiorPoints = []; 19301 for (let i = 0, ii = endss.length; i < ii; ++i) { 19302 const ends = endss[i]; 19303 interiorPoints = getInteriorPointOfArray( 19304 flatCoordinates, 19305 offset, 19306 ends, 19307 stride, 19308 flatCenters, 19309 2 * i, 19310 interiorPoints 19311 ); 19312 offset = ends[ends.length - 1]; 19313 } 19314 return interiorPoints; 19315} 19316 19317;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/segments.js 19318/** 19319 * @module ol/geom/flat/segments 19320 */ 19321 19322/** 19323 * This function calls `callback` for each segment of the flat coordinates 19324 * array. If the callback returns a truthy value the function returns that 19325 * value immediately. Otherwise the function returns `false`. 19326 * @param {Array<number>} flatCoordinates Flat coordinates. 19327 * @param {number} offset Offset. 19328 * @param {number} end End. 19329 * @param {number} stride Stride. 19330 * @param {function(import("../../coordinate.js").Coordinate, import("../../coordinate.js").Coordinate): T} callback Function 19331 * called for each segment. 19332 * @return {T|boolean} Value. 19333 * @template T 19334 */ 19335function forEach(flatCoordinates, offset, end, stride, callback) { 19336 let ret; 19337 offset += stride; 19338 for (; offset < end; offset += stride) { 19339 ret = callback( 19340 flatCoordinates.slice(offset - stride, offset), 19341 flatCoordinates.slice(offset, offset + stride) 19342 ); 19343 if (ret) { 19344 return ret; 19345 } 19346 } 19347 return false; 19348} 19349 19350;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/intersectsextent.js 19351/** 19352 * @module ol/geom/flat/intersectsextent 19353 */ 19354 19355 19356 19357 19358/** 19359 * @param {Array<number>} flatCoordinates Flat coordinates. 19360 * @param {number} offset Offset. 19361 * @param {number} end End. 19362 * @param {number} stride Stride. 19363 * @param {import("../../extent.js").Extent} extent Extent. 19364 * @return {boolean} True if the geometry and the extent intersect. 19365 */ 19366function intersectsLineString( 19367 flatCoordinates, 19368 offset, 19369 end, 19370 stride, 19371 extent 19372) { 19373 const coordinatesExtent = extendFlatCoordinates( 19374 createEmpty(), 19375 flatCoordinates, 19376 offset, 19377 end, 19378 stride 19379 ); 19380 if (!intersects(extent, coordinatesExtent)) { 19381 return false; 19382 } 19383 if (containsExtent(extent, coordinatesExtent)) { 19384 return true; 19385 } 19386 if (coordinatesExtent[0] >= extent[0] && coordinatesExtent[2] <= extent[2]) { 19387 return true; 19388 } 19389 if (coordinatesExtent[1] >= extent[1] && coordinatesExtent[3] <= extent[3]) { 19390 return true; 19391 } 19392 return forEach( 19393 flatCoordinates, 19394 offset, 19395 end, 19396 stride, 19397 /** 19398 * @param {import("../../coordinate.js").Coordinate} point1 Start point. 19399 * @param {import("../../coordinate.js").Coordinate} point2 End point. 19400 * @return {boolean} `true` if the segment and the extent intersect, 19401 * `false` otherwise. 19402 */ 19403 function (point1, point2) { 19404 return intersectsSegment(extent, point1, point2); 19405 } 19406 ); 19407} 19408 19409/** 19410 * @param {Array<number>} flatCoordinates Flat coordinates. 19411 * @param {number} offset Offset. 19412 * @param {Array<number>} ends Ends. 19413 * @param {number} stride Stride. 19414 * @param {import("../../extent.js").Extent} extent Extent. 19415 * @return {boolean} True if the geometry and the extent intersect. 19416 */ 19417function intersectsLineStringArray( 19418 flatCoordinates, 19419 offset, 19420 ends, 19421 stride, 19422 extent 19423) { 19424 for (let i = 0, ii = ends.length; i < ii; ++i) { 19425 if ( 19426 intersectsLineString(flatCoordinates, offset, ends[i], stride, extent) 19427 ) { 19428 return true; 19429 } 19430 offset = ends[i]; 19431 } 19432 return false; 19433} 19434 19435/** 19436 * @param {Array<number>} flatCoordinates Flat coordinates. 19437 * @param {number} offset Offset. 19438 * @param {number} end End. 19439 * @param {number} stride Stride. 19440 * @param {import("../../extent.js").Extent} extent Extent. 19441 * @return {boolean} True if the geometry and the extent intersect. 19442 */ 19443function intersectsLinearRing( 19444 flatCoordinates, 19445 offset, 19446 end, 19447 stride, 19448 extent 19449) { 19450 if (intersectsLineString(flatCoordinates, offset, end, stride, extent)) { 19451 return true; 19452 } 19453 if ( 19454 linearRingContainsXY( 19455 flatCoordinates, 19456 offset, 19457 end, 19458 stride, 19459 extent[0], 19460 extent[1] 19461 ) 19462 ) { 19463 return true; 19464 } 19465 if ( 19466 linearRingContainsXY( 19467 flatCoordinates, 19468 offset, 19469 end, 19470 stride, 19471 extent[0], 19472 extent[3] 19473 ) 19474 ) { 19475 return true; 19476 } 19477 if ( 19478 linearRingContainsXY( 19479 flatCoordinates, 19480 offset, 19481 end, 19482 stride, 19483 extent[2], 19484 extent[1] 19485 ) 19486 ) { 19487 return true; 19488 } 19489 if ( 19490 linearRingContainsXY( 19491 flatCoordinates, 19492 offset, 19493 end, 19494 stride, 19495 extent[2], 19496 extent[3] 19497 ) 19498 ) { 19499 return true; 19500 } 19501 return false; 19502} 19503 19504/** 19505 * @param {Array<number>} flatCoordinates Flat coordinates. 19506 * @param {number} offset Offset. 19507 * @param {Array<number>} ends Ends. 19508 * @param {number} stride Stride. 19509 * @param {import("../../extent.js").Extent} extent Extent. 19510 * @return {boolean} True if the geometry and the extent intersect. 19511 */ 19512function intersectsLinearRingArray( 19513 flatCoordinates, 19514 offset, 19515 ends, 19516 stride, 19517 extent 19518) { 19519 if (!intersectsLinearRing(flatCoordinates, offset, ends[0], stride, extent)) { 19520 return false; 19521 } 19522 if (ends.length === 1) { 19523 return true; 19524 } 19525 for (let i = 1, ii = ends.length; i < ii; ++i) { 19526 if ( 19527 linearRingContainsExtent( 19528 flatCoordinates, 19529 ends[i - 1], 19530 ends[i], 19531 stride, 19532 extent 19533 ) 19534 ) { 19535 if ( 19536 !intersectsLineString( 19537 flatCoordinates, 19538 ends[i - 1], 19539 ends[i], 19540 stride, 19541 extent 19542 ) 19543 ) { 19544 return false; 19545 } 19546 } 19547 } 19548 return true; 19549} 19550 19551/** 19552 * @param {Array<number>} flatCoordinates Flat coordinates. 19553 * @param {number} offset Offset. 19554 * @param {Array<Array<number>>} endss Endss. 19555 * @param {number} stride Stride. 19556 * @param {import("../../extent.js").Extent} extent Extent. 19557 * @return {boolean} True if the geometry and the extent intersect. 19558 */ 19559function intersectsLinearRingMultiArray( 19560 flatCoordinates, 19561 offset, 19562 endss, 19563 stride, 19564 extent 19565) { 19566 for (let i = 0, ii = endss.length; i < ii; ++i) { 19567 const ends = endss[i]; 19568 if ( 19569 intersectsLinearRingArray(flatCoordinates, offset, ends, stride, extent) 19570 ) { 19571 return true; 19572 } 19573 offset = ends[ends.length - 1]; 19574 } 19575 return false; 19576} 19577 19578;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/reverse.js 19579/** 19580 * @module ol/geom/flat/reverse 19581 */ 19582 19583/** 19584 * @param {Array<number>} flatCoordinates Flat coordinates. 19585 * @param {number} offset Offset. 19586 * @param {number} end End. 19587 * @param {number} stride Stride. 19588 */ 19589function coordinates(flatCoordinates, offset, end, stride) { 19590 while (offset < end - stride) { 19591 for (let i = 0; i < stride; ++i) { 19592 const tmp = flatCoordinates[offset + i]; 19593 flatCoordinates[offset + i] = flatCoordinates[end - stride + i]; 19594 flatCoordinates[end - stride + i] = tmp; 19595 } 19596 offset += stride; 19597 end -= stride; 19598 } 19599} 19600 19601;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/orient.js 19602/** 19603 * @module ol/geom/flat/orient 19604 */ 19605 19606 19607/** 19608 * Is the linear ring oriented clockwise in a coordinate system with a bottom-left 19609 * coordinate origin? For a coordinate system with a top-left coordinate origin, 19610 * the ring's orientation is clockwise when this function returns false. 19611 * @param {Array<number>} flatCoordinates Flat coordinates. 19612 * @param {number} offset Offset. 19613 * @param {number} end End. 19614 * @param {number} stride Stride. 19615 * @return {boolean} Is clockwise. 19616 */ 19617function linearRingIsClockwise(flatCoordinates, offset, end, stride) { 19618 // https://stackoverflow.com/q/1165647/clockwise-method#1165943 19619 // https://github.com/OSGeo/gdal/blob/master/gdal/ogr/ogrlinearring.cpp 19620 let edge = 0; 19621 let x1 = flatCoordinates[end - stride]; 19622 let y1 = flatCoordinates[end - stride + 1]; 19623 for (; offset < end; offset += stride) { 19624 const x2 = flatCoordinates[offset]; 19625 const y2 = flatCoordinates[offset + 1]; 19626 edge += (x2 - x1) * (y2 + y1); 19627 x1 = x2; 19628 y1 = y2; 19629 } 19630 return edge === 0 ? undefined : edge > 0; 19631} 19632 19633/** 19634 * Determines if linear rings are oriented. By default, left-hand orientation 19635 * is tested (first ring must be clockwise, remaining rings counter-clockwise). 19636 * To test for right-hand orientation, use the `right` argument. 19637 * 19638 * @param {Array<number>} flatCoordinates Flat coordinates. 19639 * @param {number} offset Offset. 19640 * @param {Array<number>} ends Array of end indexes. 19641 * @param {number} stride Stride. 19642 * @param {boolean} [right] Test for right-hand orientation 19643 * (counter-clockwise exterior ring and clockwise interior rings). 19644 * @return {boolean} Rings are correctly oriented. 19645 */ 19646function linearRingsAreOriented( 19647 flatCoordinates, 19648 offset, 19649 ends, 19650 stride, 19651 right 19652) { 19653 right = right !== undefined ? right : false; 19654 for (let i = 0, ii = ends.length; i < ii; ++i) { 19655 const end = ends[i]; 19656 const isClockwise = linearRingIsClockwise( 19657 flatCoordinates, 19658 offset, 19659 end, 19660 stride 19661 ); 19662 if (i === 0) { 19663 if ((right && isClockwise) || (!right && !isClockwise)) { 19664 return false; 19665 } 19666 } else { 19667 if ((right && !isClockwise) || (!right && isClockwise)) { 19668 return false; 19669 } 19670 } 19671 offset = end; 19672 } 19673 return true; 19674} 19675 19676/** 19677 * Determines if linear rings are oriented. By default, left-hand orientation 19678 * is tested (first ring must be clockwise, remaining rings counter-clockwise). 19679 * To test for right-hand orientation, use the `right` argument. 19680 * 19681 * @param {Array<number>} flatCoordinates Flat coordinates. 19682 * @param {number} offset Offset. 19683 * @param {Array<Array<number>>} endss Array of array of end indexes. 19684 * @param {number} stride Stride. 19685 * @param {boolean} [right] Test for right-hand orientation 19686 * (counter-clockwise exterior ring and clockwise interior rings). 19687 * @return {boolean} Rings are correctly oriented. 19688 */ 19689function linearRingssAreOriented( 19690 flatCoordinates, 19691 offset, 19692 endss, 19693 stride, 19694 right 19695) { 19696 for (let i = 0, ii = endss.length; i < ii; ++i) { 19697 const ends = endss[i]; 19698 if (!linearRingsAreOriented(flatCoordinates, offset, ends, stride, right)) { 19699 return false; 19700 } 19701 if (ends.length) { 19702 offset = ends[ends.length - 1]; 19703 } 19704 } 19705 return true; 19706} 19707 19708/** 19709 * Orient coordinates in a flat array of linear rings. By default, rings 19710 * are oriented following the left-hand rule (clockwise for exterior and 19711 * counter-clockwise for interior rings). To orient according to the 19712 * right-hand rule, use the `right` argument. 19713 * 19714 * @param {Array<number>} flatCoordinates Flat coordinates. 19715 * @param {number} offset Offset. 19716 * @param {Array<number>} ends Ends. 19717 * @param {number} stride Stride. 19718 * @param {boolean} [right] Follow the right-hand rule for orientation. 19719 * @return {number} End. 19720 */ 19721function orientLinearRings( 19722 flatCoordinates, 19723 offset, 19724 ends, 19725 stride, 19726 right 19727) { 19728 right = right !== undefined ? right : false; 19729 for (let i = 0, ii = ends.length; i < ii; ++i) { 19730 const end = ends[i]; 19731 const isClockwise = linearRingIsClockwise( 19732 flatCoordinates, 19733 offset, 19734 end, 19735 stride 19736 ); 19737 const reverse = 19738 i === 0 19739 ? (right && isClockwise) || (!right && !isClockwise) 19740 : (right && !isClockwise) || (!right && isClockwise); 19741 if (reverse) { 19742 coordinates(flatCoordinates, offset, end, stride); 19743 } 19744 offset = end; 19745 } 19746 return offset; 19747} 19748 19749/** 19750 * Orient coordinates in a flat array of linear rings. By default, rings 19751 * are oriented following the left-hand rule (clockwise for exterior and 19752 * counter-clockwise for interior rings). To orient according to the 19753 * right-hand rule, use the `right` argument. 19754 * 19755 * @param {Array<number>} flatCoordinates Flat coordinates. 19756 * @param {number} offset Offset. 19757 * @param {Array<Array<number>>} endss Array of array of end indexes. 19758 * @param {number} stride Stride. 19759 * @param {boolean} [right] Follow the right-hand rule for orientation. 19760 * @return {number} End. 19761 */ 19762function orientLinearRingsArray( 19763 flatCoordinates, 19764 offset, 19765 endss, 19766 stride, 19767 right 19768) { 19769 for (let i = 0, ii = endss.length; i < ii; ++i) { 19770 offset = orientLinearRings( 19771 flatCoordinates, 19772 offset, 19773 endss[i], 19774 stride, 19775 right 19776 ); 19777 } 19778 return offset; 19779} 19780 19781/** 19782 * Return a two-dimensional endss 19783 * @param {Array<number>} flatCoordinates Flat coordinates 19784 * @param {Array<number>} ends Linear ring end indexes 19785 * @return {Array<Array<number>>} Two dimensional endss array that can 19786 * be used to contruct a MultiPolygon 19787 */ 19788function inflateEnds(flatCoordinates, ends) { 19789 const endss = []; 19790 let offset = 0; 19791 let prevEndIndex = 0; 19792 for (let i = 0, ii = ends.length; i < ii; ++i) { 19793 const end = ends[i]; 19794 // classifies an array of rings into polygons with outer rings and holes 19795 if (!linearRingIsClockwise(flatCoordinates, offset, end, 2)) { 19796 endss.push(ends.slice(prevEndIndex, i + 1)); 19797 } else { 19798 if (endss.length === 0) { 19799 continue; 19800 } 19801 endss[endss.length - 1].push(ends[prevEndIndex]); 19802 } 19803 prevEndIndex = i + 1; 19804 offset = end; 19805 } 19806 return endss; 19807} 19808 19809;// CONCATENATED MODULE: ./node_modules/ol/geom/Polygon.js 19810/** 19811 * @module ol/geom/Polygon 19812 */ 19813 19814 19815 19816 19817 19818 19819 19820 19821 19822 19823 19824 19825 19826 19827 19828 19829 19830/** 19831 * @classdesc 19832 * Polygon geometry. 19833 * 19834 * @api 19835 */ 19836class Polygon extends geom_SimpleGeometry { 19837 /** 19838 * @param {!Array<Array<import("../coordinate.js").Coordinate>>|!Array<number>} coordinates 19839 * Array of linear rings that define the polygon. The first linear ring of the 19840 * array defines the outer-boundary or surface of the polygon. Each subsequent 19841 * linear ring defines a hole in the surface of the polygon. A linear ring is 19842 * an array of vertices' coordinates where the first coordinate and the last are 19843 * equivalent. (For internal use, flat coordinates in combination with 19844 * `layout` and `ends` are also accepted.) 19845 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 19846 * @param {Array<number>} [ends] Ends (for internal use with flat coordinates). 19847 */ 19848 constructor(coordinates, layout, ends) { 19849 super(); 19850 19851 /** 19852 * @type {Array<number>} 19853 * @private 19854 */ 19855 this.ends_ = []; 19856 19857 /** 19858 * @private 19859 * @type {number} 19860 */ 19861 this.flatInteriorPointRevision_ = -1; 19862 19863 /** 19864 * @private 19865 * @type {import("../coordinate.js").Coordinate} 19866 */ 19867 this.flatInteriorPoint_ = null; 19868 19869 /** 19870 * @private 19871 * @type {number} 19872 */ 19873 this.maxDelta_ = -1; 19874 19875 /** 19876 * @private 19877 * @type {number} 19878 */ 19879 this.maxDeltaRevision_ = -1; 19880 19881 /** 19882 * @private 19883 * @type {number} 19884 */ 19885 this.orientedRevision_ = -1; 19886 19887 /** 19888 * @private 19889 * @type {Array<number>} 19890 */ 19891 this.orientedFlatCoordinates_ = null; 19892 19893 if (layout !== undefined && ends) { 19894 this.setFlatCoordinates( 19895 layout, 19896 /** @type {Array<number>} */ (coordinates) 19897 ); 19898 this.ends_ = ends; 19899 } else { 19900 this.setCoordinates( 19901 /** @type {Array<Array<import("../coordinate.js").Coordinate>>} */ ( 19902 coordinates 19903 ), 19904 layout 19905 ); 19906 } 19907 } 19908 19909 /** 19910 * Append the passed linear ring to this polygon. 19911 * @param {LinearRing} linearRing Linear ring. 19912 * @api 19913 */ 19914 appendLinearRing(linearRing) { 19915 if (!this.flatCoordinates) { 19916 this.flatCoordinates = linearRing.getFlatCoordinates().slice(); 19917 } else { 19918 array_extend(this.flatCoordinates, linearRing.getFlatCoordinates()); 19919 } 19920 this.ends_.push(this.flatCoordinates.length); 19921 this.changed(); 19922 } 19923 19924 /** 19925 * Make a complete copy of the geometry. 19926 * @return {!Polygon} Clone. 19927 * @api 19928 */ 19929 clone() { 19930 const polygon = new Polygon( 19931 this.flatCoordinates.slice(), 19932 this.layout, 19933 this.ends_.slice() 19934 ); 19935 polygon.applyProperties(this); 19936 return polygon; 19937 } 19938 19939 /** 19940 * @param {number} x X. 19941 * @param {number} y Y. 19942 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 19943 * @param {number} minSquaredDistance Minimum squared distance. 19944 * @return {number} Minimum squared distance. 19945 */ 19946 closestPointXY(x, y, closestPoint, minSquaredDistance) { 19947 if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) { 19948 return minSquaredDistance; 19949 } 19950 if (this.maxDeltaRevision_ != this.getRevision()) { 19951 this.maxDelta_ = Math.sqrt( 19952 arrayMaxSquaredDelta( 19953 this.flatCoordinates, 19954 0, 19955 this.ends_, 19956 this.stride, 19957 0 19958 ) 19959 ); 19960 this.maxDeltaRevision_ = this.getRevision(); 19961 } 19962 return assignClosestArrayPoint( 19963 this.flatCoordinates, 19964 0, 19965 this.ends_, 19966 this.stride, 19967 this.maxDelta_, 19968 true, 19969 x, 19970 y, 19971 closestPoint, 19972 minSquaredDistance 19973 ); 19974 } 19975 19976 /** 19977 * @param {number} x X. 19978 * @param {number} y Y. 19979 * @return {boolean} Contains (x, y). 19980 */ 19981 containsXY(x, y) { 19982 return linearRingsContainsXY( 19983 this.getOrientedFlatCoordinates(), 19984 0, 19985 this.ends_, 19986 this.stride, 19987 x, 19988 y 19989 ); 19990 } 19991 19992 /** 19993 * Return the area of the polygon on projected plane. 19994 * @return {number} Area (on projected plane). 19995 * @api 19996 */ 19997 getArea() { 19998 return linearRings( 19999 this.getOrientedFlatCoordinates(), 20000 0, 20001 this.ends_, 20002 this.stride 20003 ); 20004 } 20005 20006 /** 20007 * Get the coordinate array for this geometry. This array has the structure 20008 * of a GeoJSON coordinate array for polygons. 20009 * 20010 * @param {boolean} [right] Orient coordinates according to the right-hand 20011 * rule (counter-clockwise for exterior and clockwise for interior rings). 20012 * If `false`, coordinates will be oriented according to the left-hand rule 20013 * (clockwise for exterior and counter-clockwise for interior rings). 20014 * By default, coordinate orientation will depend on how the geometry was 20015 * constructed. 20016 * @return {Array<Array<import("../coordinate.js").Coordinate>>} Coordinates. 20017 * @api 20018 */ 20019 getCoordinates(right) { 20020 let flatCoordinates; 20021 if (right !== undefined) { 20022 flatCoordinates = this.getOrientedFlatCoordinates().slice(); 20023 orientLinearRings(flatCoordinates, 0, this.ends_, this.stride, right); 20024 } else { 20025 flatCoordinates = this.flatCoordinates; 20026 } 20027 20028 return inflateCoordinatesArray(flatCoordinates, 0, this.ends_, this.stride); 20029 } 20030 20031 /** 20032 * @return {Array<number>} Ends. 20033 */ 20034 getEnds() { 20035 return this.ends_; 20036 } 20037 20038 /** 20039 * @return {Array<number>} Interior point. 20040 */ 20041 getFlatInteriorPoint() { 20042 if (this.flatInteriorPointRevision_ != this.getRevision()) { 20043 const flatCenter = getCenter(this.getExtent()); 20044 this.flatInteriorPoint_ = getInteriorPointOfArray( 20045 this.getOrientedFlatCoordinates(), 20046 0, 20047 this.ends_, 20048 this.stride, 20049 flatCenter, 20050 0 20051 ); 20052 this.flatInteriorPointRevision_ = this.getRevision(); 20053 } 20054 return this.flatInteriorPoint_; 20055 } 20056 20057 /** 20058 * Return an interior point of the polygon. 20059 * @return {Point} Interior point as XYM coordinate, where M is the 20060 * length of the horizontal intersection that the point belongs to. 20061 * @api 20062 */ 20063 getInteriorPoint() { 20064 return new geom_Point(this.getFlatInteriorPoint(), 'XYM'); 20065 } 20066 20067 /** 20068 * Return the number of rings of the polygon, this includes the exterior 20069 * ring and any interior rings. 20070 * 20071 * @return {number} Number of rings. 20072 * @api 20073 */ 20074 getLinearRingCount() { 20075 return this.ends_.length; 20076 } 20077 20078 /** 20079 * Return the Nth linear ring of the polygon geometry. Return `null` if the 20080 * given index is out of range. 20081 * The exterior linear ring is available at index `0` and the interior rings 20082 * at index `1` and beyond. 20083 * 20084 * @param {number} index Index. 20085 * @return {LinearRing|null} Linear ring. 20086 * @api 20087 */ 20088 getLinearRing(index) { 20089 if (index < 0 || this.ends_.length <= index) { 20090 return null; 20091 } 20092 return new geom_LinearRing( 20093 this.flatCoordinates.slice( 20094 index === 0 ? 0 : this.ends_[index - 1], 20095 this.ends_[index] 20096 ), 20097 this.layout 20098 ); 20099 } 20100 20101 /** 20102 * Return the linear rings of the polygon. 20103 * @return {Array<LinearRing>} Linear rings. 20104 * @api 20105 */ 20106 getLinearRings() { 20107 const layout = this.layout; 20108 const flatCoordinates = this.flatCoordinates; 20109 const ends = this.ends_; 20110 const linearRings = []; 20111 let offset = 0; 20112 for (let i = 0, ii = ends.length; i < ii; ++i) { 20113 const end = ends[i]; 20114 const linearRing = new geom_LinearRing( 20115 flatCoordinates.slice(offset, end), 20116 layout 20117 ); 20118 linearRings.push(linearRing); 20119 offset = end; 20120 } 20121 return linearRings; 20122 } 20123 20124 /** 20125 * @return {Array<number>} Oriented flat coordinates. 20126 */ 20127 getOrientedFlatCoordinates() { 20128 if (this.orientedRevision_ != this.getRevision()) { 20129 const flatCoordinates = this.flatCoordinates; 20130 if (linearRingsAreOriented(flatCoordinates, 0, this.ends_, this.stride)) { 20131 this.orientedFlatCoordinates_ = flatCoordinates; 20132 } else { 20133 this.orientedFlatCoordinates_ = flatCoordinates.slice(); 20134 this.orientedFlatCoordinates_.length = orientLinearRings( 20135 this.orientedFlatCoordinates_, 20136 0, 20137 this.ends_, 20138 this.stride 20139 ); 20140 } 20141 this.orientedRevision_ = this.getRevision(); 20142 } 20143 return this.orientedFlatCoordinates_; 20144 } 20145 20146 /** 20147 * @param {number} squaredTolerance Squared tolerance. 20148 * @return {Polygon} Simplified Polygon. 20149 * @protected 20150 */ 20151 getSimplifiedGeometryInternal(squaredTolerance) { 20152 const simplifiedFlatCoordinates = []; 20153 const simplifiedEnds = []; 20154 simplifiedFlatCoordinates.length = quantizeArray( 20155 this.flatCoordinates, 20156 0, 20157 this.ends_, 20158 this.stride, 20159 Math.sqrt(squaredTolerance), 20160 simplifiedFlatCoordinates, 20161 0, 20162 simplifiedEnds 20163 ); 20164 return new Polygon(simplifiedFlatCoordinates, 'XY', simplifiedEnds); 20165 } 20166 20167 /** 20168 * Get the type of this geometry. 20169 * @return {import("./Geometry.js").Type} Geometry type. 20170 * @api 20171 */ 20172 getType() { 20173 return 'Polygon'; 20174 } 20175 20176 /** 20177 * Test if the geometry and the passed extent intersect. 20178 * @param {import("../extent.js").Extent} extent Extent. 20179 * @return {boolean} `true` if the geometry and the extent intersect. 20180 * @api 20181 */ 20182 intersectsExtent(extent) { 20183 return intersectsLinearRingArray( 20184 this.getOrientedFlatCoordinates(), 20185 0, 20186 this.ends_, 20187 this.stride, 20188 extent 20189 ); 20190 } 20191 20192 /** 20193 * Set the coordinates of the polygon. 20194 * @param {!Array<Array<import("../coordinate.js").Coordinate>>} coordinates Coordinates. 20195 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 20196 * @api 20197 */ 20198 setCoordinates(coordinates, layout) { 20199 this.setLayout(layout, coordinates, 2); 20200 if (!this.flatCoordinates) { 20201 this.flatCoordinates = []; 20202 } 20203 const ends = deflateCoordinatesArray( 20204 this.flatCoordinates, 20205 0, 20206 coordinates, 20207 this.stride, 20208 this.ends_ 20209 ); 20210 this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; 20211 this.changed(); 20212 } 20213} 20214 20215/* harmony default export */ const geom_Polygon = (Polygon); 20216 20217/** 20218 * Create an approximation of a circle on the surface of a sphere. 20219 * @param {import("../coordinate.js").Coordinate} center Center (`[lon, lat]` in degrees). 20220 * @param {number} radius The great-circle distance from the center to 20221 * the polygon vertices in meters. 20222 * @param {number} [n] Optional number of vertices for the resulting
20223 * polygon. Default is `32`. 20224 * @param {number} [sphereRadius] Optional radius for the sphere (defaults to 20225 * the Earth's mean radius using the WGS84 ellipsoid). 20226 * @return {Polygon} The "circular" polygon. 20227 * @api 20228 */ 20229function circular(center, radius, n, sphereRadius) { 20230 n = n ? n : 32; 20231 /** @type {Array<number>} */ 20232 const flatCoordinates = []; 20233 for (let i = 0; i < n; ++i) { 20234 extend( 20235 flatCoordinates, 20236 sphereOffset(center, radius, (2 * Math.PI * i) / n, sphereRadius) 20237 ); 20238 } 20239 flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]); 20240 return new Polygon(flatCoordinates, 'XY', [flatCoordinates.length]); 20241} 20242 20243/** 20244 * Create a polygon from an extent. The layout used is `XY`. 20245 * @param {import("../extent.js").Extent} extent The extent. 20246 * @return {Polygon} The polygon. 20247 * @api 20248 */ 20249function fromExtent(extent) { 20250 const minX = extent[0]; 20251 const minY = extent[1]; 20252 const maxX = extent[2]; 20253 const maxY = extent[3]; 20254 const flatCoordinates = [ 20255 minX, 20256 minY, 20257 minX, 20258 maxY, 20259 maxX, 20260 maxY, 20261 maxX, 20262 minY, 20263 minX, 20264 minY, 20265 ]; 20266 return new Polygon(flatCoordinates, 'XY', [flatCoordinates.length]); 20267} 20268 20269/** 20270 * Create a regular polygon from a circle. 20271 * @param {import("./Circle.js").default} circle Circle geometry. 20272 * @param {number} [sides] Number of sides of the polygon. Default is 32. 20273 * @param {number} [angle] Start angle for the first vertex of the polygon in 20274 * counter-clockwise radians. 0 means East. Default is 0. 20275 * @return {Polygon} Polygon geometry. 20276 * @api 20277 */ 20278function fromCircle(circle, sides, angle) { 20279 sides = sides ? sides : 32; 20280 const stride = circle.getStride(); 20281 const layout = circle.getLayout(); 20282 const center = circle.getCenter(); 20283 const arrayLength = stride * (sides + 1); 20284 const flatCoordinates = new Array(arrayLength); 20285 for (let i = 0; i < arrayLength; i += stride) { 20286 flatCoordinates[i] = 0; 20287 flatCoordinates[i + 1] = 0; 20288 for (let j = 2; j < stride; j++) { 20289 flatCoordinates[i + j] = center[j]; 20290 } 20291 } 20292 const ends = [flatCoordinates.length]; 20293 const polygon = new Polygon(flatCoordinates, layout, ends); 20294 makeRegular(polygon, center, circle.getRadius(), angle); 20295 return polygon; 20296} 20297 20298/** 20299 * Modify the coordinates of a polygon to make it a regular polygon. 20300 * @param {Polygon} polygon Polygon geometry. 20301 * @param {import("../coordinate.js").Coordinate} center Center of the regular polygon. 20302 * @param {number} radius Radius of the regular polygon. 20303 * @param {number} [angle] Start angle for the first vertex of the polygon in 20304 * counter-clockwise radians. 0 means East. Default is 0. 20305 */ 20306function makeRegular(polygon, center, radius, angle) { 20307 const flatCoordinates = polygon.getFlatCoordinates(); 20308 const stride = polygon.getStride(); 20309 const sides = flatCoordinates.length / stride - 1; 20310 const startAngle = angle ? angle : 0; 20311 for (let i = 0; i <= sides; ++i) { 20312 const offset = i * stride; 20313 const angle = startAngle + (modulo(i, sides) * 2 * Math.PI) / sides; 20314 flatCoordinates[offset] = center[0] + radius * Math.cos(angle); 20315 flatCoordinates[offset + 1] = center[1] + radius * Math.sin(angle); 20316 } 20317 polygon.changed(); 20318} 20319 20320;// CONCATENATED MODULE: ./node_modules/ol/View.js 20321/** 20322 * @module ol/View 20323 */ 20324 20325 20326 20327 20328 20329 20330 20331 20332 20333 20334 20335 20336 20337 20338 20339 20340 20341/** 20342 * An animation configuration 20343 * 20344 * @typedef {Object} Animation 20345 * @property {import("./coordinate.js").Coordinate} [sourceCenter] Source center. 20346 * @property {import("./coordinate.js").Coordinate} [targetCenter] Target center. 20347 * @property {number} [sourceResolution] Source resolution. 20348 * @property {number} [targetResolution] Target resolution. 20349 * @property {number} [sourceRotation] Source rotation. 20350 * @property {number} [targetRotation] Target rotation. 20351 * @property {import("./coordinate.js").Coordinate} [anchor] Anchor. 20352 * @property {number} start Start. 20353 * @property {number} duration Duration. 20354 * @property {boolean} complete Complete. 20355 * @property {function(number):number} easing Easing. 20356 * @property {function(boolean):void} callback Callback. 20357 */ 20358 20359/** 20360 * @typedef {Object} Constraints 20361 * @property {import("./centerconstraint.js").Type} center Center. 20362 * @property {import("./resolutionconstraint.js").Type} resolution Resolution. 20363 * @property {import("./rotationconstraint.js").Type} rotation Rotation. 20364 */ 20365 20366/** 20367 * @typedef {Object} FitOptions 20368 * @property {import("./size.js").Size} [size] The size in pixels of the box to fit 20369 * the extent into. Default is the current size of the first map in the DOM that 20370 * uses this view, or `[100, 100]` if no such map is found. 20371 * @property {!Array<number>} [padding=[0, 0, 0, 0]] Padding (in pixels) to be 20372 * cleared inside the view. Values in the array are top, right, bottom and left 20373 * padding. 20374 * @property {boolean} [nearest=false] If the view `constrainResolution` option is `true`, 20375 * get the nearest extent instead of the closest that actually fits the view. 20376 * @property {number} [minResolution=0] Minimum resolution that we zoom to. 20377 * @property {number} [maxZoom] Maximum zoom level that we zoom to. If 20378 * `minResolution` is given, this property is ignored. 20379 * @property {number} [duration] The duration of the animation in milliseconds. 20380 * By default, there is no animation to the target extent. 20381 * @property {function(number):number} [easing] The easing function used during 20382 * the animation (defaults to {@link module:ol/easing.inAndOut}). 20383 * The function will be called for each frame with a number representing a 20384 * fraction of the animation's duration. The function should return a number 20385 * between 0 and 1 representing the progress toward the destination state. 20386 * @property {function(boolean):void} [callback] Function called when the view is in 20387 * its final position. The callback will be called with `true` if the animation 20388 * series completed on its own or `false` if it was cancelled. 20389 */ 20390 20391/** 20392 * @typedef {Object} ViewOptions 20393 * @property {import("./coordinate.js").Coordinate} [center] The initial center for 20394 * the view. If a user projection is not set, the coordinate system for the center is 20395 * specified with the `projection` option. Layer sources will not be fetched if this 20396 * is not set, but the center can be set later with {@link #setCenter}. 20397 * @property {boolean|number} [constrainRotation=true] Rotation constraint. 20398 * `false` means no constraint. `true` means no constraint, but snap to zero 20399 * near zero. A number constrains the rotation to that number of values. For 20400 * example, `4` will constrain the rotation to 0, 90, 180, and 270 degrees. 20401 * @property {boolean} [enableRotation=true] Enable rotation. 20402 * If `false`, a rotation constraint that always sets the rotation to zero is 20403 * used. The `constrainRotation` option has no effect if `enableRotation` is 20404 * `false`. 20405 * @property {import("./extent.js").Extent} [extent] The extent that constrains the 20406 * view, in other words, nothing outside of this extent can be visible on the map. 20407 * @property {boolean} [constrainOnlyCenter=false] If true, the extent 20408 * constraint will only apply to the view center and not the whole extent. 20409 * @property {boolean} [smoothExtentConstraint=true] If true, the extent 20410 * constraint will be applied smoothly, i.e. allow the view to go slightly outside 20411 * of the given `extent`. 20412 * @property {number} [maxResolution] The maximum resolution used to determine 20413 * the resolution constraint. It is used together with `minResolution` (or 20414 * `maxZoom`) and `zoomFactor`. If unspecified it is calculated in such a way 20415 * that the projection's validity extent fits in a 256x256 px tile. If the 20416 * projection is Spherical Mercator (the default) then `maxResolution` defaults 20417 * to `40075016.68557849 / 256 = 156543.03392804097`. 20418 * @property {number} [minResolution] The minimum resolution used to determine 20419 * the resolution constraint. It is used together with `maxResolution` (or 20420 * `minZoom`) and `zoomFactor`. If unspecified it is calculated assuming 29 20421 * zoom levels (with a factor of 2). If the projection is Spherical Mercator 20422 * (the default) then `minResolution` defaults to 20423 * `40075016.68557849 / 256 / Math.pow(2, 28) = 0.0005831682455839253`. 20424 * @property {number} [maxZoom=28] The maximum zoom level used to determine the 20425 * resolution constraint. It is used together with `minZoom` (or 20426 * `maxResolution`) and `zoomFactor`. Note that if `minResolution` is also 20427 * provided, it is given precedence over `maxZoom`. 20428 * @property {number} [minZoom=0] The minimum zoom level used to determine the 20429 * resolution constraint. It is used together with `maxZoom` (or 20430 * `minResolution`) and `zoomFactor`. Note that if `maxResolution` is also 20431 * provided, it is given precedence over `minZoom`. 20432 * @property {boolean} [multiWorld=false] If `false` the view is constrained so 20433 * only one world is visible, and you cannot pan off the edge. If `true` the map 20434 * may show multiple worlds at low zoom levels. Only used if the `projection` is 20435 * global. Note that if `extent` is also provided it is given precedence. 20436 * @property {boolean} [constrainResolution=false] If true, the view will always 20437 * animate to the closest zoom level after an interaction; false means 20438 * intermediary zoom levels are allowed. 20439 * @property {boolean} [smoothResolutionConstraint=true] If true, the resolution 20440 * min/max values will be applied smoothly, i. e. allow the view to exceed slightly 20441 * the given resolution or zoom bounds. 20442 * @property {boolean} [showFullExtent=false] Allow the view to be zoomed out to 20443 * show the full configured extent. By default, when a view is configured with an 20444 * extent, users will not be able to zoom out so the viewport exceeds the extent in 20445 * either dimension. This means the full extent may not be visible if the viewport 20446 * is taller or wider than the aspect ratio of the configured extent. If 20447 * showFullExtent is true, the user will be able to zoom out so that the viewport 20448 * exceeds the height or width of the configured extent, but not both, allowing the 20449 * full extent to be shown. 20450 * @property {import("./proj.js").ProjectionLike} [projection='EPSG:3857'] The 20451 * projection. The default is Spherical Mercator. 20452 * @property {number} [resolution] The initial resolution for the view. The 20453 * units are `projection` units per pixel (e.g. meters per pixel). An 20454 * alternative to setting this is to set `zoom`. Layer sources will not be 20455 * fetched if neither this nor `zoom` are defined, but they can be set later 20456 * with {@link #setZoom} or {@link #setResolution}. 20457 * @property {Array<number>} [resolutions] Resolutions that determine the 20458 * zoom levels if specified. The index in the array corresponds to the zoom level, 20459 * therefore the resolution values have to be in descending order. It also constrains 20460 * the resolution by the minimum and maximum value. If set the `maxResolution`,
20461 * `minResolution`, `minZoom`, `maxZoom`, and `zoomFactor` options are ignored. 20462 * @property {number} [rotation=0] The initial rotation for the view in radians 20463 * (positive rotation clockwise, 0 means North). 20464 * @property {number} [zoom] Only used if `resolution` is not defined. Zoom 20465 * level used to calculate the initial resolution for the view. 20466 * @property {number} [zoomFactor=2] The zoom factor used to compute the 20467 * corresponding resolution. 20468 * @property {!Array<number>} [padding=[0, 0, 0, 0]] Padding (in css pixels). 20469 * If the map viewport is partially covered with other content (overlays) along 20470 * its edges, this setting allows to shift the center of the viewport away from 20471 * that content. The order of the values is top, right, bottom, left. 20472 */ 20473 20474/** 20475 * @typedef {Object} AnimationOptions 20476 * @property {import("./coordinate.js").Coordinate} [center] The center of the view at the end of 20477 * the animation. 20478 * @property {number} [zoom] The zoom level of the view at the end of the 20479 * animation. This takes precedence over `resolution`. 20480 * @property {number} [resolution] The resolution of the view at the end 20481 * of the animation. If `zoom` is also provided, this option will be ignored. 20482 * @property {number} [rotation] The rotation of the view at the end of 20483 * the animation. 20484 * @property {import("./coordinate.js").Coordinate} [anchor] Optional anchor to remain fixed 20485 * during a rotation or resolution animation. 20486 * @property {number} [duration=1000] The duration of the animation in milliseconds. 20487 * @property {function(number):number} [easing] The easing function used 20488 * during the animation (defaults to {@link module:ol/easing.inAndOut}). 20489 * The function will be called for each frame with a number representing a 20490 * fraction of the animation's duration. The function should return a number 20491 * between 0 and 1 representing the progress toward the destination state. 20492 */ 20493 20494/** 20495 * @typedef {Object} State 20496 * @property {import("./coordinate.js").Coordinate} center Center. 20497 * @property {import("./proj/Projection.js").default} projection Projection. 20498 * @property {number} resolution Resolution. 20499 * @property {import("./coordinate.js").Coordinate} [nextCenter] The next center during an animation series. 20500 * @property {number} [nextResolution] The next resolution during an animation series. 20501 * @property {number} [nextRotation] The next rotation during an animation series. 20502 * @property {number} rotation Rotation. 20503 * @property {number} zoom Zoom. 20504 */ 20505 20506/** 20507 * Default min zoom level for the map view. 20508 * @type {number} 20509 */ 20510const DEFAULT_MIN_ZOOM = 0; 20511 20512/** 20513 * @typedef {import("./ObjectEventType").Types|'change:center'|'change:resolution'|'change:rotation'} ViewObjectEventTypes 20514 */ 20515 20516/*** 20517 * @template Return 20518 * @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> & 20519 * import("./Observable").OnSignature<ViewObjectEventTypes, import("./Object").ObjectEvent, Return> & 20520 * import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|ViewObjectEventTypes, Return>} ViewOnSignature 20521 */ 20522 20523/** 20524 * @classdesc 20525 * A View object represents a simple 2D view of the map. 20526 * 20527 * This is the object to act upon to change the center, resolution, 20528 * and rotation of the map. 20529 * 20530 * A View has a `projection`. The projection determines the 20531 * coordinate system of the center, and its units determine the units of the 20532 * resolution (projection units per pixel). The default projection is 20533 * Web Mercator (EPSG:3857). 20534 * 20535 * ### The view states 20536 * 20537 * A View is determined by three states: `center`, `resolution`, 20538 * and `rotation`. Each state has a corresponding getter and setter, e.g. 20539 * `getCenter` and `setCenter` for the `center` state. 20540 * 20541 * The `zoom` state is actually not saved on the view: all computations 20542 * internally use the `resolution` state. Still, the `setZoom` and `getZoom` 20543 * methods are available, as well as `getResolutionForZoom` and 20544 * `getZoomForResolution` to switch from one system to the other. 20545 * 20546 * ### The constraints 20547 * 20548 * `setCenter`, `setResolution` and `setRotation` can be used to change the 20549 * states of the view, but any constraint defined in the constructor will 20550 * be applied along the way. 20551 * 20552 * A View object can have a *resolution constraint*, a *rotation constraint* 20553 * and a *center constraint*. 20554 * 20555 * The *resolution constraint* typically restricts min/max values and 20556 * snaps to specific resolutions. It is determined by the following 20557 * options: `resolutions`, `maxResolution`, `maxZoom` and `zoomFactor`. 20558 * If `resolutions` is set, the other three options are ignored. See 20559 * documentation for each option for more information. By default, the view 20560 * only has a min/max restriction and allow intermediary zoom levels when 20561 * pinch-zooming for example. 20562 * 20563 * The *rotation constraint* snaps to specific angles. It is determined 20564 * by the following options: `enableRotation` and `constrainRotation`. 20565 * By default rotation is allowed and its value is snapped to zero when approaching the 20566 * horizontal. 20567 * 20568 * The *center constraint* is determined by the `extent` option. By 20569 * default the view center is not constrained at all. 20570 * 20571 * ### Changing the view state 20572 * 20573 * It is important to note that `setZoom`, `setResolution`, `setCenter` and 20574 * `setRotation` are subject to the above mentioned constraints. As such, it 20575 * may sometimes not be possible to know in advance the resulting state of the
20576 * View. For example, calling `setResolution(10)` does not guarantee that 20577 * `getResolution()` will return `10`. 20578 * 20579 * A consequence of this is that, when applying a delta on the view state, one 20580 * should use `adjustCenter`, `adjustRotation`, `adjustZoom` and `adjustResolution` 20581 * rather than the corresponding setters. This will let view do its internal 20582 * computations. Besides, the `adjust*` methods also take an `anchor` 20583 * argument which allows specifying an origin for the transformation. 20584 * 20585 * ### Interacting with the view 20586 * 20587 * View constraints are usually only applied when the view is *at rest*, meaning that 20588 * no interaction or animation is ongoing. As such, if the user puts the view in a 20589 * state that is not equivalent to a constrained one (e.g. rotating the view when 20590 * the snap angle is 0), an animation will be triggered at the interaction end to 20591 * put back the view to a stable state; 20592 * 20593 * @api 20594 */ 20595class View extends ol_Object { 20596 /** 20597 * @param {ViewOptions} [options] View options. 20598 */ 20599 constructor(options) { 20600 super(); 20601 20602 /*** 20603 * @type {ViewOnSignature<import("./events").EventsKey>} 20604 */ 20605 this.on; 20606 20607 /*** 20608 * @type {ViewOnSignature<import("./events").EventsKey>} 20609 */ 20610 this.once; 20611 20612 /*** 20613 * @type {ViewOnSignature<void>} 20614 */ 20615 this.un; 20616 20617 options = Object.assign({}, options); 20618 20619 /** 20620 * @private 20621 * @type {Array<number>} 20622 */ 20623 this.hints_ = [0, 0]; 20624 20625 /** 20626 * @private 20627 * @type {Array<Array<Animation>>} 20628 */ 20629 this.animations_ = []; 20630 20631 /** 20632 * @private 20633 * @type {number|undefined} 20634 */ 20635 this.updateAnimationKey_; 20636 20637 /** 20638 * @private 20639 * @const 20640 * @type {import("./proj/Projection.js").default} 20641 */ 20642 this.projection_ = createProjection(options.projection, 'EPSG:3857'); 20643 20644 /** 20645 * @private 20646 * @type {import("./size.js").Size} 20647 */ 20648 this.viewportSize_ = [100, 100]; 20649 20650 /** 20651 * @private 20652 * @type {import("./coordinate.js").Coordinate|undefined} 20653 */ 20654 this.targetCenter_ = null; 20655 20656 /** 20657 * @private 20658 * @type {number|undefined} 20659 */ 20660 this.targetResolution_; 20661 20662 /** 20663 * @private 20664 * @type {number|undefined} 20665 */ 20666 this.targetRotation_; 20667 20668 /** 20669 * @private 20670 * @type {import("./coordinate.js").Coordinate} 20671 */ 20672 this.nextCenter_ = null; 20673 20674 /** 20675 * @private 20676 * @type {number} 20677 */ 20678 this.nextResolution_; 20679 20680 /** 20681 * @private 20682 * @type {number} 20683 */ 20684 this.nextRotation_; 20685 20686 /** 20687 * @private 20688 * @type {import("./coordinate.js").Coordinate|undefined} 20689 */ 20690 this.cancelAnchor_ = undefined; 20691 20692 if (options.projection) { 20693 disableCoordinateWarning(); 20694 } 20695 if (options.center) { 20696 options.center = fromUserCoordinate(options.center, this.projection_); 20697 } 20698 if (options.extent) { 20699 options.extent = proj_fromUserExtent(options.extent, this.projection_); 20700 } 20701 20702 this.applyOptions_(options); 20703 } 20704 20705 /** 20706 * Set up the view with the given options. 20707 * @param {ViewOptions} options View options. 20708 */ 20709 applyOptions_(options) { 20710 const properties = Object.assign({}, options); 20711 for (const key in ViewProperty) { 20712 delete properties[key]; 20713 } 20714 this.setProperties(properties, true); 20715 20716 const resolutionConstraintInfo = createResolutionConstraint(options); 20717 20718 /** 20719 * @private 20720 * @type {number} 20721 */ 20722 this.maxResolution_ = resolutionConstraintInfo.maxResolution; 20723 20724 /** 20725 * @private 20726 * @type {number} 20727 */ 20728 this.minResolution_ = resolutionConstraintInfo.minResolution; 20729 20730 /** 20731 * @private 20732 * @type {number} 20733 */ 20734 this.zoomFactor_ = resolutionConstraintInfo.zoomFactor; 20735 20736 /** 20737 * @private 20738 * @type {Array<number>|undefined} 20739 */ 20740 this.resolutions_ = options.resolutions; 20741 20742 /** 20743 * @type {Array<number>|undefined} 20744 * @private 20745 */ 20746 this.padding_ = options.padding; 20747 20748 /** 20749 * @private 20750 * @type {number} 20751 */ 20752 this.minZoom_ = resolutionConstraintInfo.minZoom; 20753 20754 const centerConstraint = createCenterConstraint(options); 20755 const resolutionConstraint = resolutionConstraintInfo.constraint; 20756 const rotationConstraint = createRotationConstraint(options); 20757 20758 /** 20759 * @private 20760 * @type {Constraints} 20761 */ 20762 this.constraints_ = { 20763 center: centerConstraint, 20764 resolution: resolutionConstraint, 20765 rotation: rotationConstraint, 20766 }; 20767 20768 this.setRotation(options.rotation !== undefined ? options.rotation : 0); 20769 this.setCenterInternal( 20770 options.center !== undefined ? options.center : null 20771 ); 20772 if (options.resolution !== undefined) { 20773 this.setResolution(options.resolution); 20774 } else if (options.zoom !== undefined) { 20775 this.setZoom(options.zoom); 20776 } 20777 } 20778 20779 /** 20780 * Padding (in css pixels). 20781 * If the map viewport is partially covered with other content (overlays) along 20782 * its edges, this setting allows to shift the center of the viewport away from that 20783 * content. The order of the values in the array is top, right, bottom, left. 20784 * The default is no padding, which is equivalent to `[0, 0, 0, 0]`. 20785 * @type {Array<number>|undefined} 20786 * @api 20787 */ 20788 get padding() { 20789 return this.padding_; 20790 } 20791 set padding(padding) { 20792 let oldPadding = this.padding_; 20793 this.padding_ = padding; 20794 const center = this.getCenter(); 20795 if (center) { 20796 const newPadding = padding || [0, 0, 0, 0]; 20797 oldPadding = oldPadding || [0, 0, 0, 0]; 20798 const resolution = this.getResolution(); 20799 const offsetX = 20800 (resolution / 2) * 20801 (newPadding[3] - oldPadding[3] + oldPadding[1] - newPadding[1]); 20802 const offsetY = 20803 (resolution / 2) * 20804 (newPadding[0] - oldPadding[0] + oldPadding[2] - newPadding[2]); 20805 this.setCenterInternal([center[0] + offsetX, center[1] - offsetY]); 20806 } 20807 } 20808 20809 /** 20810 * Get an updated version of the view options used to construct the view. The 20811 * current resolution (or zoom), center, and rotation are applied to any stored 20812 * options. The provided options can be used to apply new min/max zoom or 20813 * resolution limits. 20814 * @param {ViewOptions} newOptions New options to be applied. 20815 * @return {ViewOptions} New options updated with the current view state. 20816 */ 20817 getUpdatedOptions_(newOptions) { 20818 const options = this.getProperties(); 20819 20820 // preserve resolution (or zoom) 20821 if (options.resolution !== undefined) { 20822 options.resolution = this.getResolution(); 20823 } else { 20824 options.zoom = this.getZoom(); 20825 } 20826 20827 // preserve center 20828 options.center = this.getCenterInternal(); 20829 20830 // preserve rotation 20831 options.rotation = this.getRotation(); 20832 20833 return Object.assign({}, options, newOptions); 20834 } 20835 20836 /** 20837 * Animate the view. The view's center, zoom (or resolution), and rotation 20838 * can be animated for smooth transitions between view states. For example, 20839 * to animate the view to a new zoom level: 20840 * 20841 * view.animate({zoom: view.getZoom() + 1}); 20842 * 20843 * By default, the animation lasts one second and uses in-and-out easing. You
20844 * can customize this behavior by including `duration` (in milliseconds) and 20845 * `easing` options (see {@link module:ol/easing}). 20846 * 20847 * To chain together multiple animations, call the method with multiple 20848 * animation objects. For example, to first zoom and then pan: 20849 * 20850 * view.animate({zoom: 10}, {center: [0, 0]}); 20851 * 20852 * If you provide a function as the last argument to the animate method, it 20853 * will get called at the end of an animation series. The callback will be 20854 * called with `true` if the animation series completed on its own or `false` 20855 * if it was cancelled. 20856 * 20857 * Animations are cancelled by user interactions (e.g. dragging the map) or by 20858 * calling `view.setCenter()`, `view.setResolution()`, or `view.setRotation()` 20859 * (or another method that calls one of these). 20860 * 20861 * @param {...(AnimationOptions|function(boolean): void)} var_args Animation 20862 * options. Multiple animations can be run in series by passing multiple 20863 * options objects. To run multiple animations in parallel, call the method 20864 * multiple times. An optional callback can be provided as a final 20865 * argument. The callback will be called with a boolean indicating whether 20866 * the animation completed without being cancelled. 20867 * @api 20868 */ 20869 animate(var_args) { 20870 if (this.isDef() && !this.getAnimating()) { 20871 this.resolveConstraints(0); 20872 } 20873 const args = new Array(arguments.length); 20874 for (let i = 0; i < args.length; ++i) { 20875 let options = arguments[i]; 20876 if (options.center) { 20877 options = Object.assign({}, options); 20878 options.center = fromUserCoordinate( 20879 options.center, 20880 this.getProjection() 20881 ); 20882 } 20883 if (options.anchor) { 20884 options = Object.assign({}, options); 20885 options.anchor = fromUserCoordinate( 20886 options.anchor, 20887 this.getProjection() 20888 ); 20889 } 20890 args[i] = options; 20891 } 20892 this.animateInternal.apply(this, args); 20893 } 20894 20895 /** 20896 * @param {...(AnimationOptions|function(boolean): void)} var_args Animation options. 20897 */ 20898 animateInternal(var_args) { 20899 let animationCount = arguments.length; 20900 let callback; 20901 if ( 20902 animationCount > 1 && 20903 typeof arguments[animationCount - 1] === 'function' 20904 ) { 20905 callback = arguments[animationCount - 1]; 20906 --animationCount; 20907 } 20908 20909 let i = 0; 20910 for (; i < animationCount && !this.isDef(); ++i) { 20911 // if view properties are not yet set, shortcut to the final state 20912 const state = arguments[i]; 20913 if (state.center) { 20914 this.setCenterInternal(state.center); 20915 } 20916 if (state.zoom !== undefined) { 20917 this.setZoom(state.zoom); 20918 } else if (state.resolution) { 20919 this.setResolution(state.resolution); 20920 } 20921 if (state.rotation !== undefined) { 20922 this.setRotation(state.rotation); 20923 } 20924 } 20925 if (i === animationCount) { 20926 if (callback) { 20927 animationCallback(callback, true); 20928 } 20929 return; 20930 } 20931 20932 let start = Date.now(); 20933 let center = this.targetCenter_.slice(); 20934 let resolution = this.targetResolution_; 20935 let rotation = this.targetRotation_; 20936 const series = []; 20937 for (; i < animationCount; ++i) { 20938 const options = /** @type {AnimationOptions} */ (arguments[i]); 20939 20940 const animation = { 20941 start: start, 20942 complete: false, 20943 anchor: options.anchor, 20944 duration: options.duration !== undefined ? options.duration : 1000, 20945 easing: options.easing || inAndOut, 20946 callback: callback, 20947 }; 20948 20949 if (options.center) { 20950 animation.sourceCenter = center; 20951 animation.targetCenter = options.center.slice(); 20952 center = animation.targetCenter; 20953 } 20954 20955 if (options.zoom !== undefined) { 20956 animation.sourceResolution = resolution; 20957 animation.targetResolution = this.getResolutionForZoom(options.zoom); 20958 resolution = animation.targetResolution; 20959 } else if (options.resolution) { 20960 animation.sourceResolution = resolution; 20961 animation.targetResolution = options.resolution; 20962 resolution = animation.targetResolution; 20963 } 20964 20965 if (options.rotation !== undefined) { 20966 animation.sourceRotation = rotation; 20967 const delta = 20968 math_modulo(options.rotation - rotation + Math.PI, 2 * Math.PI) - Math.PI; 20969 animation.targetRotation = rotation + delta; 20970 rotation = animation.targetRotation; 20971 } 20972 20973 // check if animation is a no-op 20974 if (isNoopAnimation(animation)) { 20975 animation.complete = true; 20976 // we still push it onto the series for callback handling 20977 } else { 20978 start += animation.duration; 20979 } 20980 series.push(animation); 20981 }
vendor: 31,292 bytes, lines 20982-21982
20982 this.animations_.push(series); 20983 this.setHint(ViewHint.ANIMATING, 1); 20984 this.updateAnimations_(); 20985 } 20986 20987 /** 20988 * Determine if the view is being animated. 20989 * @return {boolean} The view is being animated. 20990 * @api 20991 */ 20992 getAnimating() { 20993 return this.hints_[ViewHint.ANIMATING] > 0; 20994 } 20995 20996 /** 20997 * Determine if the user is interacting with the view, such as panning or zooming. 20998 * @return {boolean} The view is being interacted with. 20999 * @api 21000 */ 21001 getInteracting() { 21002 return this.hints_[ViewHint.INTERACTING] > 0; 21003 } 21004 21005 /** 21006 * Cancel any ongoing animations. 21007 * @api 21008 */ 21009 cancelAnimations() { 21010 this.setHint(ViewHint.ANIMATING, -this.hints_[ViewHint.ANIMATING]); 21011 let anchor; 21012 for (let i = 0, ii = this.animations_.length; i < ii; ++i) { 21013 const series = this.animations_[i]; 21014 if (series[0].callback) { 21015 animationCallback(series[0].callback, false); 21016 } 21017 if (!anchor) { 21018 for (let j = 0, jj = series.length; j < jj; ++j) { 21019 const animation = series[j]; 21020 if (!animation.complete) { 21021 anchor = animation.anchor; 21022 break; 21023 } 21024 } 21025 } 21026 } 21027 this.animations_.length = 0; 21028 this.cancelAnchor_ = anchor; 21029 this.nextCenter_ = null; 21030 this.nextResolution_ = NaN; 21031 this.nextRotation_ = NaN; 21032 } 21033 21034 /** 21035 * Update all animations. 21036 */ 21037 updateAnimations_() { 21038 if (this.updateAnimationKey_ !== undefined) { 21039 cancelAnimationFrame(this.updateAnimationKey_); 21040 this.updateAnimationKey_ = undefined; 21041 } 21042 if (!this.getAnimating()) { 21043 return; 21044 } 21045 const now = Date.now(); 21046 let more = false; 21047 for (let i = this.animations_.length - 1; i >= 0; --i) { 21048 const series = this.animations_[i]; 21049 let seriesComplete = true; 21050 for (let j = 0, jj = series.length; j < jj; ++j) { 21051 const animation = series[j]; 21052 if (animation.complete) { 21053 continue; 21054 } 21055 const elapsed = now - animation.start; 21056 let fraction = 21057 animation.duration > 0 ? elapsed / animation.duration : 1; 21058 if (fraction >= 1) { 21059 animation.complete = true; 21060 fraction = 1; 21061 } else { 21062 seriesComplete = false; 21063 } 21064 const progress = animation.easing(fraction); 21065 if (animation.sourceCenter) { 21066 const x0 = animation.sourceCenter[0]; 21067 const y0 = animation.sourceCenter[1]; 21068 const x1 = animation.targetCenter[0]; 21069 const y1 = animation.targetCenter[1]; 21070 this.nextCenter_ = animation.targetCenter; 21071 const x = x0 + progress * (x1 - x0); 21072 const y = y0 + progress * (y1 - y0); 21073 this.targetCenter_ = [x, y]; 21074 } 21075 if (animation.sourceResolution && animation.targetResolution) { 21076 const resolution = 21077 progress === 1 21078 ? animation.targetResolution 21079 : animation.sourceResolution + 21080 progress * 21081 (animation.targetResolution - animation.sourceResolution); 21082 if (animation.anchor) { 21083 const size = this.getViewportSize_(this.getRotation()); 21084 const constrainedResolution = this.constraints_.resolution( 21085 resolution, 21086 0, 21087 size, 21088 true 21089 ); 21090 this.targetCenter_ = this.calculateCenterZoom( 21091 constrainedResolution, 21092 animation.anchor 21093 ); 21094 } 21095 this.nextResolution_ = animation.targetResolution; 21096 this.targetResolution_ = resolution; 21097 this.applyTargetState_(true); 21098 } 21099 if ( 21100 animation.sourceRotation !== undefined && 21101 animation.targetRotation !== undefined 21102 ) { 21103 const rotation = 21104 progress === 1 21105 ? math_modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - 21106 Math.PI 21107 : animation.sourceRotation + 21108 progress * 21109 (animation.targetRotation - animation.sourceRotation); 21110 if (animation.anchor) { 21111 const constrainedRotation = this.constraints_.rotation( 21112 rotation, 21113 true 21114 ); 21115 this.targetCenter_ = this.calculateCenterRotate( 21116 constrainedRotation, 21117 animation.anchor 21118 ); 21119 } 21120 this.nextRotation_ = animation.targetRotation; 21121 this.targetRotation_ = rotation; 21122 } 21123 this.applyTargetState_(true); 21124 more = true; 21125 if (!animation.complete) { 21126 break; 21127 } 21128 } 21129 if (seriesComplete) { 21130 this.animations_[i] = null; 21131 this.setHint(ViewHint.ANIMATING, -1); 21132 this.nextCenter_ = null; 21133 this.nextResolution_ = NaN; 21134 this.nextRotation_ = NaN; 21135 const callback = series[0].callback; 21136 if (callback) { 21137 animationCallback(callback, true); 21138 } 21139 } 21140 } 21141 // prune completed series 21142 this.animations_ = this.animations_.filter(Boolean); 21143 if (more && this.updateAnimationKey_ === undefined) { 21144 this.updateAnimationKey_ = requestAnimationFrame( 21145 this.updateAnimations_.bind(this) 21146 ); 21147 } 21148 } 21149 21150 /** 21151 * @param {number} rotation Target rotation. 21152 * @param {import("./coordinate.js").Coordinate} anchor Rotation anchor. 21153 * @return {import("./coordinate.js").Coordinate|undefined} Center for rotation and anchor. 21154 */ 21155 calculateCenterRotate(rotation, anchor) { 21156 let center; 21157 const currentCenter = this.getCenterInternal(); 21158 if (currentCenter !== undefined) { 21159 center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]]; 21160 rotate(center, rotation - this.getRotation()); 21161 coordinate_add(center, anchor); 21162 } 21163 return center; 21164 } 21165 21166 /** 21167 * @param {number} resolution Target resolution. 21168 * @param {import("./coordinate.js").Coordinate} anchor Zoom anchor. 21169 * @return {import("./coordinate.js").Coordinate|undefined} Center for resolution and anchor. 21170 */ 21171 calculateCenterZoom(resolution, anchor) { 21172 let center; 21173 const currentCenter = this.getCenterInternal(); 21174 const currentResolution = this.getResolution(); 21175 if (currentCenter !== undefined && currentResolution !== undefined) { 21176 const x = 21177 anchor[0] - 21178 (resolution * (anchor[0] - currentCenter[0])) / currentResolution; 21179 const y = 21180 anchor[1] - 21181 (resolution * (anchor[1] - currentCenter[1])) / currentResolution; 21182 center = [x, y]; 21183 } 21184 return center; 21185 } 21186 21187 /** 21188 * Returns the current viewport size. 21189 * @private 21190 * @param {number} [rotation] Take into account the rotation of the viewport when giving the size 21191 * @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found. 21192 */ 21193 getViewportSize_(rotation) { 21194 const size = this.viewportSize_; 21195 if (rotation) { 21196 const w = size[0]; 21197 const h = size[1]; 21198 return [ 21199 Math.abs(w * Math.cos(rotation)) + Math.abs(h * Math.sin(rotation)), 21200 Math.abs(w * Math.sin(rotation)) + Math.abs(h * Math.cos(rotation)), 21201 ]; 21202 } else { 21203 return size; 21204 } 21205 } 21206 21207 /** 21208 * Stores the viewport size on the view. The viewport size is not read every time from the DOM 21209 * to avoid performance hit and layout reflow. 21210 * This should be done on map size change. 21211 * Note: the constraints are not resolved during an animation to avoid stopping it 21212 * @param {import("./size.js").Size} [size] Viewport size; if undefined, [100, 100] is assumed 21213 */ 21214 setViewportSize(size) { 21215 this.viewportSize_ = Array.isArray(size) ? size.slice() : [100, 100]; 21216 if (!this.getAnimating()) { 21217 this.resolveConstraints(0); 21218 } 21219 } 21220 21221 /** 21222 * Get the view center. 21223 * @return {import("./coordinate.js").Coordinate|undefined} The center of the view. 21224 * @observable 21225 * @api 21226 */ 21227 getCenter() { 21228 const center = this.getCenterInternal(); 21229 if (!center) { 21230 return center; 21231 } 21232 return toUserCoordinate(center, this.getProjection()); 21233 } 21234 21235 /** 21236 * Get the view center without transforming to user projection. 21237 * @return {import("./coordinate.js").Coordinate|undefined} The center of the view. 21238 */ 21239 getCenterInternal() { 21240 return /** @type {import("./coordinate.js").Coordinate|undefined} */ ( 21241 this.get(ViewProperty.CENTER) 21242 ); 21243 } 21244 21245 /** 21246 * @return {Constraints} Constraints. 21247 */ 21248 getConstraints() { 21249 return this.constraints_; 21250 } 21251 21252 /** 21253 * @return {boolean} Resolution constraint is set 21254 */ 21255 getConstrainResolution() { 21256 return this.get('constrainResolution'); 21257 } 21258 21259 /** 21260 * @param {Array<number>} [hints] Destination array. 21261 * @return {Array<number>} Hint. 21262 */ 21263 getHints(hints) { 21264 if (hints !== undefined) { 21265 hints[0] = this.hints_[0]; 21266 hints[1] = this.hints_[1]; 21267 return hints; 21268 } else { 21269 return this.hints_.slice(); 21270 } 21271 } 21272 21273 /** 21274 * Calculate the extent for the current view state and the passed size. 21275 * The size is the pixel dimensions of the box into which the calculated extent 21276 * should fit. In most cases you want to get the extent of the entire map, 21277 * that is `map.getSize()`. 21278 * @param {import("./size.js").Size} [size] Box pixel size. If not provided, the size 21279 * of the map that uses this view will be used. 21280 * @return {import("./extent.js").Extent} Extent. 21281 * @api 21282 */ 21283 calculateExtent(size) { 21284 const extent = this.calculateExtentInternal(size); 21285 return proj_toUserExtent(extent, this.getProjection()); 21286 } 21287 21288 /** 21289 * @param {import("./size.js").Size} [size] Box pixel size. If not provided, 21290 * the map's last known viewport size will be used. 21291 * @return {import("./extent.js").Extent} Extent. 21292 */ 21293 calculateExtentInternal(size) { 21294 size = size || this.getViewportSizeMinusPadding_(); 21295 const center = /** @type {!import("./coordinate.js").Coordinate} */ ( 21296 this.getCenterInternal() 21297 ); 21298 asserts_assert(center, 1); // The view center is not defined 21299 const resolution = /** @type {!number} */ (this.getResolution()); 21300 asserts_assert(resolution !== undefined, 2); // The view resolution is not defined 21301 const rotation = /** @type {!number} */ (this.getRotation()); 21302 asserts_assert(rotation !== undefined, 3); // The view rotation is not defined 21303 21304 return getForViewAndSize(center, resolution, rotation, size); 21305 } 21306 21307 /** 21308 * Get the maximum resolution of the view. 21309 * @return {number} The maximum resolution of the view. 21310 * @api 21311 */ 21312 getMaxResolution() { 21313 return this.maxResolution_; 21314 } 21315 21316 /** 21317 * Get the minimum resolution of the view. 21318 * @return {number} The minimum resolution of the view. 21319 * @api 21320 */ 21321 getMinResolution() { 21322 return this.minResolution_; 21323 } 21324 21325 /** 21326 * Get the maximum zoom level for the view. 21327 * @return {number} The maximum zoom level. 21328 * @api 21329 */ 21330 getMaxZoom() { 21331 return /** @type {number} */ ( 21332 this.getZoomForResolution(this.minResolution_) 21333 ); 21334 } 21335 21336 /** 21337 * Set a new maximum zoom level for the view. 21338 * @param {number} zoom The maximum zoom level. 21339 * @api 21340 */ 21341 setMaxZoom(zoom) { 21342 this.applyOptions_(this.getUpdatedOptions_({maxZoom: zoom})); 21343 } 21344 21345 /** 21346 * Get the minimum zoom level for the view. 21347 * @return {number} The minimum zoom level. 21348 * @api 21349 */ 21350 getMinZoom() { 21351 return /** @type {number} */ ( 21352 this.getZoomForResolution(this.maxResolution_) 21353 ); 21354 } 21355 21356 /** 21357 * Set a new minimum zoom level for the view. 21358 * @param {number} zoom The minimum zoom level. 21359 * @api 21360 */ 21361 setMinZoom(zoom) { 21362 this.applyOptions_(this.getUpdatedOptions_({minZoom: zoom})); 21363 } 21364 21365 /** 21366 * Set whether the view should allow intermediary zoom levels. 21367 * @param {boolean} enabled Whether the resolution is constrained. 21368 * @api 21369 */ 21370 setConstrainResolution(enabled) { 21371 this.applyOptions_(this.getUpdatedOptions_({constrainResolution: enabled})); 21372 } 21373 21374 /** 21375 * Get the view projection. 21376 * @return {import("./proj/Projection.js").default} The projection of the view. 21377 * @api 21378 */ 21379 getProjection() { 21380 return this.projection_; 21381 } 21382 21383 /** 21384 * Get the view resolution. 21385 * @return {number|undefined} The resolution of the view. 21386 * @observable 21387 * @api 21388 */ 21389 getResolution() { 21390 return /** @type {number|undefined} */ (this.get(ViewProperty.RESOLUTION)); 21391 } 21392 21393 /** 21394 * Get the resolutions for the view. This returns the array of resolutions 21395 * passed to the constructor of the View, or undefined if none were given. 21396 * @return {Array<number>|undefined} The resolutions of the view. 21397 * @api 21398 */ 21399 getResolutions() { 21400 return this.resolutions_; 21401 } 21402 21403 /** 21404 * Get the resolution for a provided extent (in map units) and size (in pixels). 21405 * @param {import("./extent.js").Extent} extent Extent. 21406 * @param {import("./size.js").Size} [size] Box pixel size. 21407 * @return {number} The resolution at which the provided extent will render at 21408 * the given size. 21409 * @api 21410 */ 21411 getResolutionForExtent(extent, size) { 21412 return this.getResolutionForExtentInternal( 21413 proj_fromUserExtent(extent, this.getProjection()), 21414 size 21415 ); 21416 } 21417 21418 /** 21419 * Get the resolution for a provided extent (in map units) and size (in pixels). 21420 * @param {import("./extent.js").Extent} extent Extent. 21421 * @param {import("./size.js").Size} [size] Box pixel size. 21422 * @return {number} The resolution at which the provided extent will render at 21423 * the given size. 21424 */ 21425 getResolutionForExtentInternal(extent, size) { 21426 size = size || this.getViewportSizeMinusPadding_(); 21427 const xResolution = extent_getWidth(extent) / size[0]; 21428 const yResolution = extent_getHeight(extent) / size[1]; 21429 return Math.max(xResolution, yResolution); 21430 } 21431 21432 /** 21433 * Return a function that returns a value between 0 and 1 for a 21434 * resolution. Exponential scaling is assumed. 21435 * @param {number} [power] Power. 21436 * @return {function(number): number} Resolution for value function. 21437 */ 21438 getResolutionForValueFunction(power) { 21439 power = power || 2; 21440 const maxResolution = this.getConstrainedResolution(this.maxResolution_); 21441 const minResolution = this.minResolution_; 21442 const max = Math.log(maxResolution / minResolution) / Math.log(power); 21443 return ( 21444 /** 21445 * @param {number} value Value. 21446 * @return {number} Resolution. 21447 */ 21448 function (value) { 21449 const resolution = maxResolution / Math.pow(power, value * max); 21450 return resolution; 21451 } 21452 ); 21453 } 21454 21455 /** 21456 * Get the view rotation. 21457 * @return {number} The rotation of the view in radians. 21458 * @observable 21459 * @api 21460 */ 21461 getRotation() { 21462 return /** @type {number} */ (this.get(ViewProperty.ROTATION)); 21463 } 21464 21465 /** 21466 * Return a function that returns a resolution for a value between 21467 * 0 and 1. Exponential scaling is assumed. 21468 * @param {number} [power] Power. 21469 * @return {function(number): number} Value for resolution function. 21470 */ 21471 getValueForResolutionFunction(power) { 21472 const logPower = Math.log(power || 2); 21473 const maxResolution = this.getConstrainedResolution(this.maxResolution_); 21474 const minResolution = this.minResolution_; 21475 const max = Math.log(maxResolution / minResolution) / logPower; 21476 return ( 21477 /** 21478 * @param {number} resolution Resolution. 21479 * @return {number} Value. 21480 */ 21481 function (resolution) { 21482 const value = Math.log(maxResolution / resolution) / logPower / max; 21483 return value; 21484 } 21485 ); 21486 } 21487 21488 /** 21489 * Returns the size of the viewport minus padding. 21490 * @private 21491 * @param {number} [rotation] Take into account the rotation of the viewport when giving the size 21492 * @return {import("./size.js").Size} Viewport size reduced by the padding. 21493 */ 21494 getViewportSizeMinusPadding_(rotation) { 21495 let size = this.getViewportSize_(rotation); 21496 const padding = this.padding_; 21497 if (padding) { 21498 size = [ 21499 size[0] - padding[1] - padding[3], 21500 size[1] - padding[0] - padding[2], 21501 ]; 21502 } 21503 return size; 21504 } 21505 21506 /** 21507 * @return {State} View state. 21508 */ 21509 getState() { 21510 const projection = this.getProjection(); 21511 const resolution = this.getResolution(); 21512 const rotation = this.getRotation(); 21513 let center = /** @type {import("./coordinate.js").Coordinate} */ ( 21514 this.getCenterInternal() 21515 ); 21516 const padding = this.padding_; 21517 if (padding) { 21518 const reducedSize = this.getViewportSizeMinusPadding_(); 21519 center = calculateCenterOn( 21520 center, 21521 this.getViewportSize_(), 21522 [reducedSize[0] / 2 + padding[3], reducedSize[1] / 2 + padding[0]], 21523 resolution, 21524 rotation 21525 ); 21526 } 21527 return { 21528 center: center.slice(0), 21529 projection: projection !== undefined ? projection : null, 21530 resolution: resolution, 21531 nextCenter: this.nextCenter_, 21532 nextResolution: this.nextResolution_, 21533 nextRotation: this.nextRotation_, 21534 rotation: rotation, 21535 zoom: this.getZoom(), 21536 }; 21537 } 21538 21539 /** 21540 * Get the current zoom level. This method may return non-integer zoom levels 21541 * if the view does not constrain the resolution, or if an interaction or 21542 * animation is underway. 21543 * @return {number|undefined} Zoom. 21544 * @api 21545 */ 21546 getZoom() { 21547 let zoom; 21548 const resolution = this.getResolution(); 21549 if (resolution !== undefined) { 21550 zoom = this.getZoomForResolution(resolution); 21551 } 21552 return zoom; 21553 } 21554 21555 /** 21556 * Get the zoom level for a resolution. 21557 * @param {number} resolution The resolution. 21558 * @return {number|undefined} The zoom level for the provided resolution. 21559 * @api 21560 */ 21561 getZoomForResolution(resolution) { 21562 let offset = this.minZoom_ || 0; 21563 let max, zoomFactor; 21564 if (this.resolutions_) { 21565 const nearest = linearFindNearest(this.resolutions_, resolution, 1); 21566 offset = nearest; 21567 max = this.resolutions_[nearest]; 21568 if (nearest == this.resolutions_.length - 1) { 21569 zoomFactor = 2; 21570 } else { 21571 zoomFactor = max / this.resolutions_[nearest + 1]; 21572 } 21573 } else { 21574 max = this.maxResolution_; 21575 zoomFactor = this.zoomFactor_; 21576 } 21577 return offset + Math.log(max / resolution) / Math.log(zoomFactor); 21578 } 21579 21580 /** 21581 * Get the resolution for a zoom level. 21582 * @param {number} zoom Zoom level. 21583 * @return {number} The view resolution for the provided zoom level. 21584 * @api 21585 */ 21586 getResolutionForZoom(zoom) { 21587 if (this.resolutions_) { 21588 if (this.resolutions_.length <= 1) { 21589 return 0; 21590 } 21591 const baseLevel = math_clamp( 21592 Math.floor(zoom), 21593 0, 21594 this.resolutions_.length - 2 21595 ); 21596 const zoomFactor = 21597 this.resolutions_[baseLevel] / this.resolutions_[baseLevel + 1]; 21598 return ( 21599 this.resolutions_[baseLevel] / 21600 Math.pow(zoomFactor, math_clamp(zoom - baseLevel, 0, 1)) 21601 ); 21602 } else { 21603 return ( 21604 this.maxResolution_ / Math.pow(this.zoomFactor_, zoom - this.minZoom_) 21605 ); 21606 } 21607 } 21608 21609 /** 21610 * Fit the given geometry or extent based on the given map size and border. 21611 * The size is pixel dimensions of the box to fit the extent into. 21612 * In most cases you will want to use the map size, that is `map.getSize()`. 21613 * Takes care of the map angle. 21614 * @param {import("./geom/SimpleGeometry.js").default|import("./extent.js").Extent} geometryOrExtent The geometry or 21615 * extent to fit the view to. 21616 * @param {FitOptions} [options] Options. 21617 * @api 21618 */ 21619 fit(geometryOrExtent, options) { 21620 /** @type {import("./geom/SimpleGeometry.js").default} */ 21621 let geometry; 21622 asserts_assert( 21623 Array.isArray(geometryOrExtent) || 21624 typeof (/** @type {?} */ (geometryOrExtent).getSimplifiedGeometry) === 21625 'function', 21626 24 21627 ); // Invalid extent or geometry provided as `geometry` 21628 if (Array.isArray(geometryOrExtent)) { 21629 asserts_assert(!extent_isEmpty(geometryOrExtent), 25); // Cannot fit empty extent provided as `geometry` 21630 const extent = proj_fromUserExtent(geometryOrExtent, this.getProjection()); 21631 geometry = fromExtent(extent); 21632 } else if (geometryOrExtent.getType() === 'Circle') { 21633 const extent = proj_fromUserExtent( 21634 geometryOrExtent.getExtent(), 21635 this.getProjection() 21636 ); 21637 geometry = fromExtent(extent); 21638 geometry.rotate(this.getRotation(), getCenter(extent)); 21639 } else { 21640 const userProjection = getUserProjection(); 21641 if (userProjection) { 21642 geometry = /** @type {import("./geom/SimpleGeometry.js").default} */ ( 21643 geometryOrExtent 21644 .clone() 21645 .transform(userProjection, this.getProjection()) 21646 ); 21647 } else { 21648 geometry = geometryOrExtent; 21649 } 21650 } 21651 21652 this.fitInternal(geometry, options); 21653 } 21654 21655 /** 21656 * Calculate rotated extent 21657 * @param {import("./geom/SimpleGeometry.js").default} geometry The geometry. 21658 * @return {import("./extent").Extent} The rotated extent for the geometry. 21659 */ 21660 rotatedExtentForGeometry(geometry) { 21661 const rotation = this.getRotation(); 21662 const cosAngle = Math.cos(rotation); 21663 const sinAngle = Math.sin(-rotation); 21664 const coords = geometry.getFlatCoordinates(); 21665 const stride = geometry.getStride(); 21666 let minRotX = +Infinity; 21667 let minRotY = +Infinity; 21668 let maxRotX = -Infinity; 21669 let maxRotY = -Infinity; 21670 for (let i = 0, ii = coords.length; i < ii; i += stride) { 21671 const rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle; 21672 const rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle; 21673 minRotX = Math.min(minRotX, rotX); 21674 minRotY = Math.min(minRotY, rotY); 21675 maxRotX = Math.max(maxRotX, rotX); 21676 maxRotY = Math.max(maxRotY, rotY); 21677 } 21678 return [minRotX, minRotY, maxRotX, maxRotY]; 21679 } 21680 21681 /** 21682 * @param {import("./geom/SimpleGeometry.js").default} geometry The geometry. 21683 * @param {FitOptions} [options] Options. 21684 */ 21685 fitInternal(geometry, options) { 21686 options = options || {}; 21687 let size = options.size; 21688 if (!size) { 21689 size = this.getViewportSizeMinusPadding_(); 21690 } 21691 const padding = 21692 options.padding !== undefined ? options.padding : [0, 0, 0, 0]; 21693 const nearest = options.nearest !== undefined ? options.nearest : false; 21694 let minResolution; 21695 if (options.minResolution !== undefined) { 21696 minResolution = options.minResolution; 21697 } else if (options.maxZoom !== undefined) { 21698 minResolution = this.getResolutionForZoom(options.maxZoom); 21699 } else { 21700 minResolution = 0; 21701 } 21702 21703 const rotatedExtent = this.rotatedExtentForGeometry(geometry); 21704 21705 // calculate resolution 21706 let resolution = this.getResolutionForExtentInternal(rotatedExtent, [ 21707 size[0] - padding[1] - padding[3], 21708 size[1] - padding[0] - padding[2], 21709 ]); 21710 resolution = isNaN(resolution) 21711 ? minResolution 21712 : Math.max(resolution, minResolution); 21713 resolution = this.getConstrainedResolution(resolution, nearest ? 0 : 1); 21714 21715 // calculate center 21716 const rotation = this.getRotation(); 21717 const sinAngle = Math.sin(rotation); 21718 const cosAngle = Math.cos(rotation); 21719 const centerRot = getCenter(rotatedExtent); 21720 centerRot[0] += ((padding[1] - padding[3]) / 2) * resolution; 21721 centerRot[1] += ((padding[0] - padding[2]) / 2) * resolution; 21722 const centerX = centerRot[0] * cosAngle - centerRot[1] * sinAngle; 21723 const centerY = centerRot[1] * cosAngle + centerRot[0] * sinAngle; 21724 const center = this.getConstrainedCenter([centerX, centerY], resolution); 21725 const callback = options.callback ? options.callback : VOID; 21726 21727 if (options.duration !== undefined) { 21728 this.animateInternal( 21729 { 21730 resolution: resolution, 21731 center: center, 21732 duration: options.duration, 21733 easing: options.easing, 21734 }, 21735 callback 21736 ); 21737 } else { 21738 this.targetResolution_ = resolution; 21739 this.targetCenter_ = center; 21740 this.applyTargetState_(false, true); 21741 animationCallback(callback, true); 21742 } 21743 } 21744 21745 /** 21746 * Center on coordinate and view position. 21747 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. 21748 * @param {import("./size.js").Size} size Box pixel size. 21749 * @param {import("./pixel.js").Pixel} position Position on the view to center on. 21750 * @api 21751 */ 21752 centerOn(coordinate, size, position) { 21753 this.centerOnInternal( 21754 fromUserCoordinate(coordinate, this.getProjection()), 21755 size, 21756 position 21757 ); 21758 } 21759 21760 /** 21761 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. 21762 * @param {import("./size.js").Size} size Box pixel size. 21763 * @param {import("./pixel.js").Pixel} position Position on the view to center on. 21764 */ 21765 centerOnInternal(coordinate, size, position) { 21766 this.setCenterInternal( 21767 calculateCenterOn( 21768 coordinate, 21769 size, 21770 position, 21771 this.getResolution(), 21772 this.getRotation() 21773 ) 21774 ); 21775 } 21776 21777 /** 21778 * Calculates the shift between map and viewport center. 21779 * @param {import("./coordinate.js").Coordinate} center Center. 21780 * @param {number} resolution Resolution. 21781 * @param {number} rotation Rotation. 21782 * @param {import("./size.js").Size} size Size. 21783 * @return {Array<number>|undefined} Center shift. 21784 */ 21785 calculateCenterShift(center, resolution, rotation, size) { 21786 let centerShift; 21787 const padding = this.padding_; 21788 if (padding && center) { 21789 const reducedSize = this.getViewportSizeMinusPadding_(-rotation); 21790 const shiftedCenter = calculateCenterOn( 21791 center, 21792 size, 21793 [reducedSize[0] / 2 + padding[3], reducedSize[1] / 2 + padding[0]], 21794 resolution, 21795 rotation 21796 ); 21797 centerShift = [ 21798 center[0] - shiftedCenter[0], 21799 center[1] - shiftedCenter[1], 21800 ]; 21801 } 21802 return centerShift; 21803 } 21804 21805 /** 21806 * @return {boolean} Is defined. 21807 */ 21808 isDef() { 21809 return !!this.getCenterInternal() && this.getResolution() !== undefined; 21810 } 21811 21812 /** 21813 * Adds relative coordinates to the center of the view. Any extent constraint will apply. 21814 * @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add. 21815 * @api 21816 */ 21817 adjustCenter(deltaCoordinates) { 21818 const center = toUserCoordinate(this.targetCenter_, this.getProjection()); 21819 this.setCenter([ 21820 center[0] + deltaCoordinates[0], 21821 center[1] + deltaCoordinates[1], 21822 ]); 21823 } 21824 21825 /** 21826 * Adds relative coordinates to the center of the view. Any extent constraint will apply. 21827 * @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add. 21828 */ 21829 adjustCenterInternal(deltaCoordinates) { 21830 const center = this.targetCenter_; 21831 this.setCenterInternal([ 21832 center[0] + deltaCoordinates[0], 21833 center[1] + deltaCoordinates[1], 21834 ]); 21835 } 21836 21837 /** 21838 * Multiply the view resolution by a ratio, optionally using an anchor. Any resolution 21839 * constraint will apply. 21840 * @param {number} ratio The ratio to apply on the view resolution. 21841 * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. 21842 * @api 21843 */ 21844 adjustResolution(ratio, anchor) { 21845 anchor = anchor && fromUserCoordinate(anchor, this.getProjection()); 21846 this.adjustResolutionInternal(ratio, anchor); 21847 } 21848 21849 /** 21850 * Multiply the view resolution by a ratio, optionally using an anchor. Any resolution 21851 * constraint will apply. 21852 * @param {number} ratio The ratio to apply on the view resolution. 21853 * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. 21854 */ 21855 adjustResolutionInternal(ratio, anchor) { 21856 const isMoving = this.getAnimating() || this.getInteracting(); 21857 const size = this.getViewportSize_(this.getRotation()); 21858 const newResolution = this.constraints_.resolution( 21859 this.targetResolution_ * ratio, 21860 0, 21861 size, 21862 isMoving 21863 ); 21864 21865 if (anchor) { 21866 this.targetCenter_ = this.calculateCenterZoom(newResolution, anchor); 21867 } 21868 21869 this.targetResolution_ *= ratio; 21870 this.applyTargetState_(); 21871 } 21872 21873 /** 21874 * Adds a value to the view zoom level, optionally using an anchor. Any resolution 21875 * constraint will apply. 21876 * @param {number} delta Relative value to add to the zoom level. 21877 * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. 21878 * @api 21879 */ 21880 adjustZoom(delta, anchor) { 21881 this.adjustResolution(Math.pow(this.zoomFactor_, -delta), anchor); 21882 } 21883 21884 /** 21885 * Adds a value to the view rotation, optionally using an anchor. Any rotation 21886 * constraint will apply. 21887 * @param {number} delta Relative value to add to the zoom rotation, in radians. 21888 * @param {import("./coordinate.js").Coordinate} [anchor] The rotation center. 21889 * @api 21890 */ 21891 adjustRotation(delta, anchor) { 21892 if (anchor) { 21893 anchor = fromUserCoordinate(anchor, this.getProjection()); 21894 } 21895 this.adjustRotationInternal(delta, anchor); 21896 } 21897 21898 /** 21899 * @param {number} delta Relative value to add to the zoom rotation, in radians. 21900 * @param {import("./coordinate.js").Coordinate} [anchor] The rotation center. 21901 */ 21902 adjustRotationInternal(delta, anchor) { 21903 const isMoving = this.getAnimating() || this.getInteracting(); 21904 const newRotation = this.constraints_.rotation( 21905 this.targetRotation_ + delta, 21906 isMoving 21907 ); 21908 if (anchor) { 21909 this.targetCenter_ = this.calculateCenterRotate(newRotation, anchor); 21910 } 21911 this.targetRotation_ += delta; 21912 this.applyTargetState_(); 21913 } 21914 21915 /** 21916 * Set the center of the current view. Any extent constraint will apply. 21917 * @param {import("./coordinate.js").Coordinate|undefined} center The center of the view. 21918 * @observable 21919 * @api 21920 */ 21921 setCenter(center) { 21922 this.setCenterInternal( 21923 center ? fromUserCoordinate(center, this.getProjection()) : center 21924 ); 21925 } 21926 21927 /** 21928 * Set the center using the view projection (not the user projection). 21929 * @param {import("./coordinate.js").Coordinate|undefined} center The center of the view. 21930 */ 21931 setCenterInternal(center) { 21932 this.targetCenter_ = center; 21933 this.applyTargetState_(); 21934 } 21935 21936 /** 21937 * @param {import("./ViewHint.js").default} hint Hint. 21938 * @param {number} delta Delta. 21939 * @return {number} New value. 21940 */ 21941 setHint(hint, delta) { 21942 this.hints_[hint] += delta; 21943 this.changed(); 21944 return this.hints_[hint]; 21945 } 21946 21947 /** 21948 * Set the resolution for this view. Any resolution constraint will apply. 21949 * @param {number|undefined} resolution The resolution of the view. 21950 * @observable 21951 * @api 21952 */ 21953 setResolution(resolution) { 21954 this.targetResolution_ = resolution; 21955 this.applyTargetState_(); 21956 } 21957 21958 /** 21959 * Set the rotation for this view. Any rotation constraint will apply. 21960 * @param {number} rotation The rotation of the view in radians. 21961 * @observable 21962 * @api 21963 */ 21964 setRotation(rotation) { 21965 this.targetRotation_ = rotation; 21966 this.applyTargetState_(); 21967 } 21968 21969 /** 21970 * Zoom to a specific zoom level. Any resolution constrain will apply. 21971 * @param {number} zoom Zoom level. 21972 * @api 21973 */ 21974 setZoom(zoom) { 21975 this.setResolution(this.getResolutionForZoom(zoom)); 21976 } 21977 21978 /** 21979 * Recompute rotation/resolution/center based on target values. 21980 * Note: we have to compute rotation first, then resolution and center considering that 21981 * parameters can influence one another in case a view extent constraint is present. 21982 * @param {boolean}
21982 [doNotCancelAnims] Do not cancel animations. 21983 * @param {boolean} [forceMoving] Apply constraints as if the view is moving. 21984 * @private 21985 */ 21986 applyTargetState_(doNotCancelAnims, forceMoving) { 21987 const isMoving = 21988 this.getAnimating() || this.getInteracting() || forceMoving; 21989 21990 // compute rotation 21991 const newRotation = this.constraints_.rotation( 21992 this.targetRotation_, 21993 isMoving 21994 ); 21995 const size = this.getViewportSize_(newRotation); 21996 const newResolution = this.constraints_.resolution( 21997 this.targetResolution_, 21998 0, 21999 size, 22000 isMoving 22001 ); 22002 const newCenter = this.constraints_.center( 22003 this.targetCenter_, 22004 newResolution, 22005 size, 22006 isMoving, 22007 this.calculateCenterShift( 22008 this.targetCenter_, 22009 newResolution, 22010 newRotation, 22011 size 22012 ) 22013 ); 22014 22015 if (this.get(ViewProperty.ROTATION) !== newRotation) { 22016 this.set(ViewProperty.ROTATION, newRotation); 22017 } 22018 if (this.get(ViewProperty.RESOLUTION) !== newResolution) { 22019 this.set(ViewProperty.RESOLUTION, newResolution); 22020 this.set('zoom', this.getZoom(), true); 22021 } 22022 if ( 22023 !newCenter || 22024 !this.get(ViewProperty.CENTER) || 22025 !coordinate_equals(this.get(ViewProperty.CENTER), newCenter) 22026 ) { 22027 this.set(ViewProperty.CENTER, newCenter); 22028 } 22029 22030 if (this.getAnimating() && !doNotCancelAnims) { 22031 this.cancelAnimations(); 22032 } 22033 this.cancelAnchor_ = undefined; 22034 } 22035 22036 /** 22037 * If any constraints need to be applied, an animation will be triggered. 22038 * This is typically done on interaction end. 22039 * Note: calling this with a duration of 0 will apply the constrained values straight away, 22040 * without animation. 22041 * @param {number} [duration] The animation duration in ms. 22042 * @param {number} [resolutionDirection] Which direction to zoom. 22043 * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. 22044 */ 22045 resolveConstraints(duration, resolutionDirection, anchor) { 22046 duration = duration !== undefined ? duration : 200; 22047 const direction = resolutionDirection || 0; 22048 22049 const newRotation = this.constraints_.rotation(this.targetRotation_); 22050 const size = this.getViewportSize_(newRotation); 22051 const newResolution = this.constraints_.resolution( 22052 this.targetResolution_, 22053 direction, 22054 size 22055 ); 22056 const newCenter = this.constraints_.center( 22057 this.targetCenter_, 22058 newResolution, 22059 size, 22060 false, 22061 this.calculateCenterShift( 22062 this.targetCenter_, 22063 newResolution, 22064 newRotation, 22065 size 22066 ) 22067 ); 22068 22069 if (duration === 0 && !this.cancelAnchor_) { 22070 this.targetResolution_ = newResolution; 22071 this.targetRotation_ = newRotation; 22072 this.targetCenter_ = newCenter; 22073 this.applyTargetState_(); 22074 return; 22075 } 22076 22077 anchor = anchor || (duration === 0 ? this.cancelAnchor_ : undefined); 22078 this.cancelAnchor_ = undefined; 22079 22080 if ( 22081 this.getResolution() !== newResolution || 22082 this.getRotation() !== newRotation || 22083 !this.getCenterInternal() || 22084 !coordinate_equals(this.getCenterInternal(), newCenter) 22085 ) { 22086 if (this.getAnimating()) { 22087 this.cancelAnimations(); 22088 } 22089 22090 this.animateInternal({ 22091 rotation: newRotation, 22092 center: newCenter, 22093 resolution: newResolution, 22094 duration: duration, 22095 easing: easeOut, 22096 anchor: anchor, 22097 }); 22098 } 22099 } 22100 22101 /** 22102 * Notify the View that an interaction has started. 22103 * The view state will be resolved to a stable one if needed 22104 * (depending on its constraints). 22105 * @api 22106 */ 22107 beginInteraction() { 22108 this.resolveConstraints(0); 22109 22110 this.setHint(ViewHint.INTERACTING, 1); 22111 } 22112 22113 /** 22114 * Notify the View that an interaction has ended. The view state will be resolved 22115 * to a stable one if needed (depending on its constraints). 22116 * @param {number} [duration] Animation duration in ms. 22117 * @param {number} [resolutionDirection] Which direction to zoom. 22118 * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. 22119 * @api 22120 */ 22121 endInteraction(duration, resolutionDirection, anchor) { 22122 anchor = anchor && fromUserCoordinate(anchor, this.getProjection()); 22123 this.endInteractionInternal(duration, resolutionDirection, anchor); 22124 } 22125 22126 /** 22127 * Notify the View that an interaction has ended. The view state will be resolved 22128 * to a stable one if needed (depending on its constraints). 22129 * @param {number} [duration] Animation duration in ms. 22130 * @param {number} [resolutionDirection] Which direction to zoom. 22131 * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. 22132 */ 22133 endInteractionInternal(duration, resolutionDirection, anchor) { 22134 this.setHint(ViewHint.INTERACTING, -1); 22135 22136 this.resolveConstraints(duration, resolutionDirection, anchor); 22137 } 22138 22139 /** 22140 * Get a valid position for the view center according to the current constraints. 22141 * @param {import("./coordinate.js").Coordinate|undefined} targetCenter Target center position. 22142 * @param {number} [targetResolution] Target resolution. If not supplied, the current one will be used. 22143 * This is useful to guess a valid center position at a different zoom level. 22144 * @return {import("./coordinate.js").Coordinate|undefined} Valid center position. 22145 */ 22146 getConstrainedCenter(targetCenter, targetResolution) { 22147 const size = this.getViewportSize_(this.getRotation()); 22148 return this.constraints_.center( 22149 targetCenter, 22150 targetResolution || this.getResolution(), 22151 size 22152 ); 22153 } 22154 22155 /** 22156 * Get a valid zoom level according to the current view constraints. 22157 * @param {number|undefined} targetZoom Target zoom. 22158 * @param {number} [direction=0] Indicate which resolution should be used 22159 * by a renderer if the view resolution does not match any resolution of the tile source. 22160 * If 0, the nearest resolution will be used. If 1, the nearest lower resolution 22161 * will be used. If -1, the nearest higher resolution will be used. 22162 * @return {number|undefined} Valid zoom level. 22163 */ 22164 getConstrainedZoom(targetZoom, direction) { 22165 const targetRes = this.getResolutionForZoom(targetZoom); 22166 return this.getZoomForResolution( 22167 this.getConstrainedResolution(targetRes, direction) 22168 ); 22169 } 22170 22171 /** 22172 * Get a valid resolution according to the current view constraints. 22173 * @param {number|undefined} targetResolution Target resolution. 22174 * @param {number} [direction=0] Indicate which resolution should be used 22175 * by a renderer if the view resolution does not match any resolution of the tile source. 22176 * If 0, the nearest resolution will be used. If 1, the nearest lower resolution 22177 * will be used. If -1, the nearest higher resolution will be used. 22178 * @return {number|undefined} Valid resolution. 22179 */ 22180 getConstrainedResolution(targetResolution, direction) { 22181 direction = direction || 0; 22182 const size = this.getViewportSize_(this.getRotation()); 22183 22184 return this.constraints_.resolution(targetResolution, direction, size); 22185 } 22186} 22187 22188/** 22189 * @param {Function} callback Callback. 22190 * @param {*} returnValue Return value. 22191 */ 22192function animationCallback(callback, returnValue) { 22193 setTimeout(function () { 22194 callback(returnValue); 22195 }, 0); 22196} 22197 22198/** 22199 * @param {ViewOptions} options View options. 22200 * @return {import("./centerconstraint.js").Type} The constraint. 22201 */ 22202function createCenterConstraint(options) { 22203 if (options.extent !== undefined) { 22204 const smooth = 22205 options.smoothExtentConstraint !== undefined 22206 ? options.smoothExtentConstraint 22207 : true; 22208 return createExtent(options.extent, options.constrainOnlyCenter, smooth); 22209 } 22210 22211 const projection = createProjection(options.projection, 'EPSG:3857'); 22212 if (options.multiWorld !== true && projection.isGlobal()) { 22213 const extent = projection.getExtent().slice();
22214 extent[0] = -Infinity; 22215 extent[2] = Infinity; 22216 return createExtent(extent, false, false); 22217 } 22218 22219 return none; 22220} 22221 22222/** 22223 * @param {ViewOptions} options View options. 22224 * @return {{constraint: import("./resolutionconstraint.js").Type, maxResolution: number, 22225 * minResolution: number, minZoom: number, zoomFactor: number}} The constraint. 22226 */ 22227function createResolutionConstraint(options) { 22228 let resolutionConstraint; 22229 let maxResolution; 22230 let minResolution; 22231 22232 // TODO: move these to be ol constants 22233 // see https://github.com/openlayers/openlayers/issues/2076 22234 const defaultMaxZoom = 28; 22235 const defaultZoomFactor = 2; 22236 22237 let minZoom = 22238 options.minZoom !== undefined ? options.minZoom : DEFAULT_MIN_ZOOM; 22239 22240 let maxZoom = 22241 options.maxZoom !== undefined ? options.maxZoom : defaultMaxZoom; 22242 22243 const zoomFactor = 22244 options.zoomFactor !== undefined ? options.zoomFactor : defaultZoomFactor; 22245 22246 const multiWorld = 22247 options.multiWorld !== undefined ? options.multiWorld : false; 22248 22249 const smooth = 22250 options.smoothResolutionConstraint !== undefined 22251 ? options.smoothResolutionConstraint 22252 : true; 22253 22254 const showFullExtent = 22255 options.showFullExtent !== undefined ? options.showFullExtent : false; 22256 22257 const projection = createProjection(options.projection, 'EPSG:3857'); 22258 const projExtent = projection.getExtent(); 22259 let constrainOnlyCenter = options.constrainOnlyCenter; 22260 let extent = options.extent; 22261 if (!multiWorld && !extent && projection.isGlobal()) { 22262 constrainOnlyCenter = false; 22263 extent = projExtent; 22264 } 22265 22266 if (options.resolutions !== undefined) { 22267 const resolutions = options.resolutions; 22268 maxResolution = resolutions[minZoom]; 22269 minResolution = 22270 resolutions[maxZoom] !== undefined 22271 ? resolutions[maxZoom] 22272 : resolutions[resolutions.length - 1]; 22273 22274 if (options.constrainResolution) { 22275 resolutionConstraint = createSnapToResolutions( 22276 resolutions, 22277 smooth, 22278 !constrainOnlyCenter && extent, 22279 showFullExtent 22280 ); 22281 } else { 22282 resolutionConstraint = createMinMaxResolution( 22283 maxResolution, 22284 minResolution, 22285 smooth, 22286 !constrainOnlyCenter && extent, 22287 showFullExtent 22288 ); 22289 } 22290 } else { 22291 // calculate the default min and max resolution 22292 const size = !projExtent 22293 ? // use an extent that can fit the whole world if need be 22294 (360 * Units_METERS_PER_UNIT.degrees) / projection.getMetersPerUnit() 22295 : Math.max(extent_getWidth(projExtent), extent_getHeight(projExtent)); 22296 22297 const defaultMaxResolution = 22298 size / DEFAULT_TILE_SIZE / Math.pow(defaultZoomFactor, DEFAULT_MIN_ZOOM); 22299 22300 const defaultMinResolution = 22301 defaultMaxResolution / 22302 Math.pow(defaultZoomFactor, defaultMaxZoom - DEFAULT_MIN_ZOOM); 22303 22304 // user provided maxResolution takes precedence 22305 maxResolution = options.maxResolution; 22306 if (maxResolution !== undefined) { 22307 minZoom = 0; 22308 } else { 22309 maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom); 22310 } 22311 22312 // user provided minResolution takes precedence 22313 minResolution = options.minResolution; 22314 if (minResolution === undefined) { 22315 if (options.maxZoom !== undefined) { 22316 if (options.maxResolution !== undefined) { 22317 minResolution = maxResolution / Math.pow(zoomFactor, maxZoom); 22318 } else { 22319 minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom); 22320 } 22321 } else { 22322 minResolution = defaultMinResolution; 22323 } 22324 } 22325 22326 // given discrete zoom levels, minResolution may be different than provided 22327 maxZoom = 22328 minZoom + 22329 Math.floor( 22330 Math.log(maxResolution / minResolution) / Math.log(zoomFactor) 22331 ); 22332 minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom); 22333 22334 if (options.constrainResolution) { 22335 resolutionConstraint = createSnapToPower( 22336 zoomFactor, 22337 maxResolution, 22338 minResolution, 22339 smooth, 22340 !constrainOnlyCenter && extent, 22341 showFullExtent 22342 ); 22343 } else { 22344 resolutionConstraint = createMinMaxResolution( 22345 maxResolution, 22346 minResolution, 22347 smooth, 22348 !constrainOnlyCenter && extent, 22349 showFullExtent 22350 ); 22351 } 22352 } 22353 return { 22354 constraint: resolutionConstraint, 22355 maxResolution: maxResolution, 22356 minResolution: minResolution, 22357 minZoom: minZoom, 22358 zoomFactor: zoomFactor, 22359 }; 22360} 22361 22362/** 22363 * @param {ViewOptions} options View options. 22364 * @return {import("./rotationconstraint.js").Type} Rotation constraint. 22365 */ 22366function createRotationConstraint(options) { 22367 const enableRotation = 22368 options.enableRotation !== undefined ? options.enableRotation : true; 22369 if (enableRotation) { 22370 const constrainRotation = options.constrainRotation; 22371 if (constrainRotation === undefined || constrainRotation === true) { 22372 return createSnapToZero(); 22373 } else if (constrainRotation === false) { 22374 return rotationconstraint_none; 22375 } else if (typeof constrainRotation === 'number') { 22376 return createSnapToN(constrainRotation); 22377 } else { 22378 return rotationconstraint_none; 22379 } 22380 } else { 22381 return disable; 22382 } 22383} 22384 22385/** 22386 * Determine if an animation involves no view change. 22387 * @param {Animation} animation The animation. 22388 * @return {boolean} The animation involves no view change. 22389 */ 22390function isNoopAnimation(animation) { 22391 if (animation.sourceCenter && animation.targetCenter) { 22392 if (!coordinate_equals(animation.sourceCenter, animation.targetCenter)) { 22393 return false;
22394 } 22395 } 22396 if (animation.sourceResolution !== animation.targetResolution) { 22397 return false; 22398 } 22399 if (animation.sourceRotation !== animation.targetRotation) { 22400 return false; 22401 } 22402 return true; 22403} 22404 22405/** 22406 * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. 22407 * @param {import("./size.js").Size} size Box pixel size. 22408 * @param {import("./pixel.js").Pixel} position Position on the view to center on. 22409 * @param {number} resolution Resolution. 22410 * @param {number} rotation Rotation. 22411 * @return {import("./coordinate.js").Coordinate} Shifted center. 22412 */ 22413function calculateCenterOn(coordinate, size, position, resolution, rotation) { 22414 // calculate rotated position 22415 const cosAngle = Math.cos(-rotation); 22416 let sinAngle = Math.sin(-rotation); 22417 let rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle; 22418 let rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle; 22419 rotX += (size[0] / 2 - position[0]) * resolution; 22420 rotY += (position[1] - size[1] / 2) * resolution; 22421 22422 // go back to original angle 22423 sinAngle = -sinAngle; // go back to original rotation 22424 const centerX = rotX * cosAngle - rotY * sinAngle; 22425 const centerY = rotY * cosAngle + rotX * sinAngle; 22426 22427 return [centerX, centerY]; 22428} 22429 22430/* harmony default export */ const ol_View = (View); 22431 22432;// CONCATENATED MODULE: ./node_modules/ol/CollectionEventType.js 22433/** 22434 * @module ol/CollectionEventType 22435 */ 22436 22437/** 22438 * @enum {string} 22439 */ 22440/* harmony default export */ const CollectionEventType = ({ 22441 /** 22442 * Triggered when an item is added to the collection. 22443 * @event module:ol/Collection.CollectionEvent#add 22444 * @api 22445 */ 22446 ADD: 'add', 22447 /** 22448 * Triggered when an item is removed from the collection. 22449 * @event module:ol/Collection.CollectionEvent#remove 22450 * @api 22451 */ 22452 REMOVE: 'remove', 22453}); 22454 22455;// CONCATENATED MODULE: ./node_modules/ol/Collection.js 22456/** 22457 * @module ol/Collection 22458 */ 22459 22460 22461 22462 22463 22464/** 22465 * @enum {string} 22466 * @private 22467 */ 22468const Property = { 22469 LENGTH: 'length', 22470}; 22471 22472/** 22473 * @classdesc 22474 * Events emitted by {@link module:ol/Collection~Collection} instances are instances of this 22475 * type. 22476 * @template T 22477 */ 22478class CollectionEvent extends Event { 22479 /** 22480 * @param {import("./CollectionEventType.js").default} type Type. 22481 * @param {T} element Element. 22482 * @param {number} index The index of the added or removed element. 22483 */ 22484 constructor(type, element, index) { 22485 super(type); 22486 22487 /** 22488 * The element that is added to or removed from the collection. 22489 * @type {T} 22490 * @api 22491 */ 22492 this.element = element; 22493 22494 /** 22495 * The index of the added or removed element. 22496 * @type {number} 22497 * @api 22498 */ 22499 this.index = index; 22500 } 22501} 22502 22503/*** 22504 * @template T 22505 * @template Return 22506 * @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> & 22507 * import("./Observable").OnSignature<import("./ObjectEventType").Types|'change:length', import("./Object").ObjectEvent, Return> & 22508 * import("./Observable").OnSignature<'add'|'remove', CollectionEvent<T>, Return> & 22509 * import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|import("./ObjectEventType").Types| 22510 * 'change:length'|'add'|'remove',Return>} CollectionOnSignature 22511 */ 22512 22513/** 22514 * @typedef {Object} Options 22515 * @property {boolean} [unique=false] Disallow the same item from being added to 22516 * the collection twice. 22517 */ 22518 22519/** 22520 * @classdesc 22521 * An expanded version of standard JS Array, adding convenience methods for 22522 * manipulation. Add and remove changes to the Collection trigger a Collection 22523 * event. Note that this does not cover changes to the objects _within_ the 22524 * Collection; they trigger events on the appropriate object, not on the 22525 * Collection as a whole. 22526 * 22527 * @fires CollectionEvent 22528 * 22529 * @template T 22530 * @api 22531 */ 22532class Collection extends ol_Object { 22533 /** 22534 * @param {Array<T>} [array] Array. 22535 * @param {Options} [options] Collection options. 22536 */ 22537 constructor(array, options) { 22538 super(); 22539 22540 /*** 22541 * @type {CollectionOnSignature<T, import("./events").EventsKey>} 22542 */ 22543 this.on; 22544 22545 /*** 22546 * @type {CollectionOnSignature<T, import("./events").EventsKey>} 22547 */ 22548 this.once; 22549 22550 /*** 22551 * @type {CollectionOnSignature<T, void>} 22552 */ 22553 this.un; 22554 22555 options = options || {}; 22556 22557 /** 22558 * @private 22559 * @type {boolean} 22560 */ 22561 this.unique_ = !!options.unique; 22562 22563 /** 22564 * @private
22565 * @type {!Array<T>} 22566 */ 22567 this.array_ = array ? array : []; 22568 22569 if (this.unique_) { 22570 for (let i = 0, ii = this.array_.length; i < ii; ++i) { 22571 this.assertUnique_(this.array_[i], i); 22572 } 22573 } 22574 22575 this.updateLength_(); 22576 } 22577 22578 /** 22579 * Remove all elements from the collection. 22580 * @api 22581 */ 22582 clear() { 22583 while (this.getLength() > 0) { 22584 this.pop(); 22585 } 22586 } 22587 22588 /** 22589 * Add elements to the collection. This pushes each item in the provided array 22590 * to the end of the collection. 22591 * @param {!Array<T>} arr Array. 22592 * @return {Collection<T>} This collection. 22593 * @api 22594 */ 22595 extend(arr) { 22596 for (let i = 0, ii = arr.length; i < ii; ++i) { 22597 this.push(arr[i]); 22598 } 22599 return this; 22600 } 22601 22602 /** 22603 * Iterate over each element, calling the provided callback. 22604 * @param {function(T, number, Array<T>): *} f The function to call 22605 * for every element. This function takes 3 arguments (the element, the 22606 * index and the array). The return value is ignored. 22607 * @api 22608 */ 22609 forEach(f) { 22610 const array = this.array_; 22611 for (let i = 0, ii = array.length; i < ii; ++i) { 22612 f(array[i], i, array); 22613 } 22614 } 22615 22616 /** 22617 * Get a reference to the underlying Array object. Warning: if the array 22618 * is mutated, no events will be dispatched by the collection, and the 22619 * collection's "length" property won't be in sync with the actual length 22620 * of the array. 22621 * @return {!Array<T>} Array. 22622 * @api 22623 */ 22624 getArray() { 22625 return this.array_; 22626 } 22627 22628 /** 22629 * Get the element at the provided index. 22630 * @param {number} index Index. 22631 * @return {T} Element. 22632 * @api 22633 */ 22634 item(index) { 22635 return this.array_[index]; 22636 } 22637 22638 /** 22639 * Get the length of this collection. 22640 * @return {number} The length of the array. 22641 * @observable 22642 * @api 22643 */ 22644 getLength() { 22645 return this.get(Property.LENGTH); 22646 } 22647 22648 /** 22649 * Insert an element at the provided index. 22650 * @param {number} index Index. 22651 * @param {T} elem Element. 22652 * @api 22653 */ 22654 insertAt(index, elem) { 22655 if (index < 0 || index > this.getLength()) { 22656 throw new Error('Index out of bounds: ' + index); 22657 } 22658 if (this.unique_) { 22659 this.assertUnique_(elem); 22660 } 22661 this.array_.splice(index, 0, elem); 22662 this.updateLength_(); 22663 this.dispatchEvent( 22664 new CollectionEvent(CollectionEventType.ADD, elem, index) 22665 ); 22666 } 22667 22668 /** 22669 * Remove the last element of the collection and return it. 22670 * Return `undefined` if the collection is empty. 22671 * @return {T|undefined} Element. 22672 * @api 22673 */ 22674 pop() { 22675 return this.removeAt(this.getLength() - 1); 22676 } 22677 22678 /** 22679 * Insert the provided element at the end of the collection. 22680 * @param {T} elem Element. 22681 * @return {number} New length of the collection. 22682 * @api 22683 */ 22684 push(elem) { 22685 if (this.unique_) { 22686 this.assertUnique_(elem); 22687 } 22688 const n = this.getLength(); 22689 this.insertAt(n, elem); 22690 return this.getLength(); 22691 } 22692 22693 /** 22694 * Remove the first occurrence of an element from the collection. 22695 * @param {T} elem Element. 22696 * @return {T|undefined} The removed element or undefined if none found. 22697 * @api 22698 */ 22699 remove(elem) { 22700 const arr = this.array_; 22701 for (let i = 0, ii = arr.length; i < ii; ++i) { 22702 if (arr[i] === elem) { 22703 return this.removeAt(i); 22704 } 22705 } 22706 return undefined; 22707 } 22708 22709 /** 22710 * Remove the element at the provided index and return it. 22711 * Return `undefined` if the collection does not contain this index. 22712 * @param {number} index Index. 22713 * @return {T|undefined} Value. 22714 * @api 22715 */ 22716 removeAt(index) { 22717 if (index < 0 || index >= this.getLength()) { 22718 return undefined; 22719 } 22720 const prev = this.array_[index]; 22721 this.array_.splice(index, 1); 22722 this.updateLength_(); 22723 this.dispatchEvent( 22724 /** @type {CollectionEvent<T>} */ ( 22725 new CollectionEvent(CollectionEventType.REMOVE, prev, index) 22726 ) 22727 ); 22728 return prev; 22729 } 22730 22731 /** 22732 * Set the element at the provided index. 22733 * @param {number} index Index. 22734 * @param {T} elem Element. 22735 * @api 22736 */ 22737 setAt(index, elem) { 22738 const n = this.getLength(); 22739 if (index >= n) { 22740 this.insertAt(index, elem); 22741 return; 22742 } 22743 if (index < 0) { 22744 throw new Error('Index out of bounds: ' + index); 22745 } 22746 if (this.unique_) { 22747 this.assertUnique_(elem, index); 22748 } 22749 const prev = this.array_[index]; 22750 this.array_[index] = elem; 22751 this.dispatchEvent( 22752 /** @type {CollectionEvent<T>} */ ( 22753 new CollectionEvent(CollectionEventType.REMOVE, prev, index) 22754 ) 22755 ); 22756 this.dispatchEvent( 22757 /** @type {CollectionEvent<T>} */ ( 22758 new CollectionEvent(CollectionEventType.ADD, elem, index) 22759 ) 22760 ); 22761 } 22762 22763 /** 22764 * @private 22765 */ 22766 updateLength_() { 22767 this.set(Property.LENGTH, this.array_.length); 22768 } 22769 22770 /** 22771 * @private 22772 * @param {T} elem Element. 22773 * @param {number} [except] Optional index to ignore. 22774 */ 22775 assertUnique_(elem, except) { 22776 for (let i = 0, ii = this.array_.length; i < ii; ++i) { 22777 if (this.array_[i] === elem && i !== except) { 22778 throw new ol_AssertionError(58); 22779 } 22780 } 22781 } 22782} 22783 22784/* harmony default export */ const ol_Collection = (Collection); 22785 22786;// CONCATENATED MODULE: ./node_modules/ol/color.js 22787/** 22788 * @module ol/color 22789 */ 22790 22791 22792 22793/** 22794 * A color represented as a short array [red, green, blue, alpha]. 22795 * red, green, and blue should be integers in the range 0..255 inclusive. 22796 * alpha should be a float in the range 0..1 inclusive. If no alpha value is 22797 * given then `1` will be used. 22798 * @typedef {Array<number>} Color 22799 * @api 22800 */ 22801 22802/** 22803 * This RegExp matches # followed by 3, 4, 6, or 8 hex digits. 22804 * @const 22805 * @type {RegExp} 22806 * @private 22807 */ 22808const HEX_COLOR_RE_ = /^#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})$/i; 22809 22810/** 22811 * Regular expression for matching potential named color style strings. 22812 * @const 22813 * @type {RegExp} 22814 * @private 22815 */ 22816const NAMED_COLOR_RE_ = /^([a-z]*)$|^hsla?\(.*\)$/i; 22817 22818/** 22819 * Return the color as an rgba string. 22820 * @param {Color|string} color Color. 22821 * @return {string} Rgba string. 22822 * @api 22823 */ 22824function asString(color) { 22825 if (typeof color === 'string') { 22826 return color; 22827 } else { 22828 return color_toString(color); 22829 } 22830} 22831 22832/** 22833 * Return named color as an rgba string. 22834 * @param {string} color Named color. 22835 * @return {string} Rgb string. 22836 */ 22837function fromNamed(color) { 22838 const el = document.createElement('div'); 22839 el.style.color = color; 22840 if (el.style.color !== '') { 22841 document.body.appendChild(el); 22842 const rgb = getComputedStyle(el).color; 22843 document.body.removeChild(el); 22844 return rgb; 22845 } else { 22846 return ''; 22847 } 22848} 22849 22850/** 22851 * @param {string} s String. 22852 * @return {Color} Color. 22853 */ 22854const fromString = (function () { 22855 // We maintain a small cache of parsed strings. To provide cheap LRU-like 22856 // semantics, whenever the cache grows too large we simply delete an 22857 // arbitrary 25% of the entries. 22858 22859 /** 22860 * @const 22861 * @type {number} 22862 */ 22863 const MAX_CACHE_SIZE = 1024; 22864 22865 /** 22866 * @type {Object<string, Color>} 22867 */ 22868 const cache = {}; 22869 22870 /** 22871 * @type {number} 22872 */ 22873 let cacheSize = 0; 22874 22875 return ( 22876 /** 22877 * @param {string} s String. 22878 * @return {Color} Color. 22879 */ 22880 function (s) { 22881 let color; 22882 if (cache.hasOwnProperty(s)) { 22883 color = cache[s]; 22884 } else { 22885 if (cacheSize >= MAX_CACHE_SIZE) { 22886 let i = 0; 22887 for (const key in cache) { 22888 if ((i++ & 3) === 0) { 22889 delete cache[key]; 22890 --cacheSize; 22891 } 22892 } 22893 } 22894 color = fromStringInternal_(s); 22895 cache[s] = color; 22896 ++cacheSize; 22897 } 22898 return color; 22899 } 22900 ); 22901})(); 22902 22903/** 22904 * Return the color as an array. This function maintains a cache of calculated 22905 * arrays which means the result should not be modified. 22906 * @param {Color|string} color Color. 22907 * @return {Color} Color. 22908 * @api 22909 */ 22910function asArray(color) { 22911 if (Array.isArray(color)) { 22912 return color; 22913 } else { 22914 return fromString(color); 22915 } 22916} 22917 22918/** 22919 * @param {string} s String. 22920 * @private 22921 * @return {Color} Color. 22922 */ 22923function fromStringInternal_(s) { 22924 let r, g, b, a, color; 22925 22926 if (NAMED_COLOR_RE_.exec(s)) { 22927 s = fromNamed(s); 22928 } 22929 22930 if (HEX_COLOR_RE_.exec(s)) { 22931 // hex 22932 const n = s.length - 1; // number of hex digits 22933 let d; // number of digits per channel 22934 if (n <= 4) { 22935 d = 1; 22936 } else { 22937 d = 2; 22938 } 22939 const hasAlpha = n === 4 || n === 8; 22940 r = parseInt(s.substr(1 + 0 * d, d), 16); 22941 g = parseInt(s.substr(1 + 1 * d, d), 16); 22942 b = parseInt(s.substr(1 + 2 * d, d), 16); 22943 if (hasAlpha) { 22944 a = parseInt(s.substr(1 + 3 * d, d), 16); 22945 } else { 22946 a = 255; 22947 } 22948 if (d == 1) { 22949 r = (r << 4) + r; 22950 g = (g << 4) + g; 22951 b = (b << 4) + b; 22952 if (hasAlpha) { 22953 a = (a << 4) + a; 22954 } 22955 } 22956 color = [r, g, b, a / 255]; 22957 } else if (s.startsWith('rgba(')) { 22958 // rgba() 22959 color = s.slice(5, -1).split(',').map(Number); 22960 normalize(color); 22961 } else if (s.startsWith('rgb(')) { 22962 // rgb() 22963 color = s.slice(4, -1).split(',').map(Number); 22964 color.push(1); 22965 normalize(color); 22966 } else { 22967 asserts_assert(false, 14); // Invalid color 22968 } 22969 return color; 22970} 22971
22972/** 22973 * TODO this function is only used in the test, we probably shouldn't export it 22974 * @param {Color} color Color. 22975 * @return {Color} Clamped color. 22976 */ 22977function normalize(color) { 22978 color[0] = math_clamp((color[0] + 0.5) | 0, 0, 255); 22979 color[1] = math_clamp((color[1] + 0.5) | 0, 0, 255); 22980 color[2] = math_clamp((color[2] + 0.5) | 0, 0, 255); 22981 color[3] = math_clamp(color[3], 0, 1); 22982 return color; 22983} 22984 22985/** 22986 * @param {Color} color Color. 22987 * @return {string} String. 22988 */ 22989function color_toString(color) { 22990 let r = color[0]; 22991 if (r != (r | 0)) { 22992 r = (r + 0.5) | 0; 22993 } 22994 let g = color[1]; 22995 if (g != (g | 0)) { 22996 g = (g + 0.5) | 0; 22997 } 22998 let b = color[2]; 22999 if (b != (b | 0)) { 23000 b = (b + 0.5) | 0; 23001 } 23002 const a = color[3] === undefined ? 1 : Math.round(color[3] * 100) / 100; 23003 return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; 23004} 23005 23006/** 23007 * @param {string} s String. 23008 * @return {boolean} Whether the string is actually a valid color 23009 */ 23010function isStringColor(s) { 23011 if (NAMED_COLOR_RE_.test(s)) { 23012 s = fromNamed(s); 23013 } 23014 return HEX_COLOR_RE_.test(s) || s.startsWith('rgba(') || s.startsWith('rgb('); 23015} 23016 23017;// CONCATENATED MODULE: ./node_modules/ol/style/IconImageCache.js 23018/** 23019 * @module ol/style/IconImageCache 23020 */ 23021 23022 23023/** 23024 * @classdesc 23025 * Singleton class. Available through {@link module:ol/style/IconImageCache.shared}. 23026 */ 23027class IconImageCache { 23028 constructor() { 23029 /** 23030 * @type {!Object<string, import("./IconImage.js").default>} 23031 * @private 23032 */ 23033 this.cache_ = {}; 23034 23035 /** 23036 * @type {number} 23037 * @private 23038 */ 23039 this.cacheSize_ = 0; 23040 23041 /** 23042 * @type {number} 23043 * @private 23044 */ 23045 this.maxCacheSize_ = 32; 23046 } 23047 23048 /** 23049 * FIXME empty description for jsdoc 23050 */ 23051 clear() { 23052 this.cache_ = {}; 23053 this.cacheSize_ = 0; 23054 } 23055 23056 /** 23057 * @return {boolean} Can expire cache. 23058 */ 23059 canExpireCache() { 23060 return this.cacheSize_ > this.maxCacheSize_; 23061 } 23062 23063 /** 23064 * FIXME empty description for jsdoc 23065 */ 23066 expire() { 23067 if (this.canExpireCache()) { 23068 let i = 0; 23069 for (const key in this.cache_) { 23070 const iconImage = this.cache_[key]; 23071 if ((i++ & 3) === 0 && !iconImage.hasListener()) { 23072 delete this.cache_[key]; 23073 --this.cacheSize_; 23074 } 23075 } 23076 } 23077 } 23078 23079 /** 23080 * @param {string} src Src. 23081 * @param {?string} crossOrigin Cross origin. 23082 * @param {import("../color.js").Color} color Color. 23083 * @return {import("./IconImage.js").default} Icon image. 23084 */ 23085 get(src, crossOrigin, color) { 23086 const key = getKey(src, crossOrigin, color); 23087 return key in this.cache_ ? this.cache_[key] : null; 23088 } 23089 23090 /** 23091 * @param {string} src Src. 23092 * @param {?string} crossOrigin Cross origin. 23093 * @param {import("../color.js").Color} color Color. 23094 * @param {import("./IconImage.js").default} iconImage Icon image. 23095 */ 23096 set(src, crossOrigin, color, iconImage) { 23097 const key = getKey(src, crossOrigin, color); 23098 this.cache_[key] = iconImage; 23099 ++this.cacheSize_; 23100 } 23101 23102 /** 23103 * Set the cache size of the icon cache. Default is `32`. Change this value when 23104 * your map uses more than 32 different icon images and you are not caching icon 23105 * styles on the application level. 23106 * @param {number} maxCacheSize Cache max size. 23107 * @api 23108 */ 23109 setSize(maxCacheSize) { 23110 this.maxCacheSize_ = maxCacheSize; 23111 this.expire(); 23112 } 23113} 23114 23115/** 23116 * @param {string} src Src. 23117 * @param {?string} crossOrigin Cross origin. 23118 * @param {import("../color.js").Color} color Color. 23119 * @return {string} Cache key. 23120 */ 23121function getKey(src, crossOrigin, color) { 23122 const colorString = color ? asString(color) : 'null'; 23123 return crossOrigin + ':' + src + ':' + colorString; 23124} 23125 23126/* harmony default export */ const style_IconImageCache = ((/* unused pure expression or super */ null && (IconImageCache))); 23127 23128/** 23129 * The {@link module:ol/style/IconImageCache~IconImageCache} for 23130 * {@link module:ol/style/Icon~Icon} images. 23131 * @api 23132 */ 23133const shared = new IconImageCache(); 23134 23135;// CONCATENATED MODULE: ./node_modules/ol/layer/Property.js 23136/** 23137 * @module ol/layer/Property 23138 */ 23139 23140/** 23141 * @enum {string} 23142 */ 23143/* harmony default export */ const layer_Property = ({ 23144 OPACITY: 'opacity', 23145 VISIBLE: 'visible', 23146 EXTENT: 'extent', 23147 Z_INDEX: 'zIndex', 23148 MAX_RESOLUTION: 'maxResolution', 23149 MIN_RESOLUTION: 'minResolution', 23150 MAX_ZOOM: 'maxZoom', 23151 MIN_ZOOM: 'minZoom', 23152 SOURCE: 'source', 23153 MAP: 'map', 23154}); 23155 23156;// CONCATENATED MODULE: ./node_modules/ol/layer/Base.js 23157/** 23158 * @module ol/layer/Base 23159 */ 23160 23161 23162 23163 23164 23165 23166/** 23167 * A css color, or a function called with a view resolution returning a css color. 23168 * 23169 * @typedef {string|function(number):string}
23169 BackgroundColor 23170 * @api 23171 */ 23172 23173/** 23174 * @typedef {import("../ObjectEventType").Types|'change:extent'|'change:maxResolution'|'change:maxZoom'| 23175 * 'change:minResolution'|'change:minZoom'|'change:opacity'|'change:visible'|'change:zIndex'} BaseLayerObjectEventTypes 23176 */ 23177 23178/*** 23179 * @template Return 23180 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 23181 * import("../Observable").OnSignature<BaseLayerObjectEventTypes, import("../Object").ObjectEvent, Return> & 23182 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|BaseLayerObjectEventTypes, Return>} BaseLayerOnSignature 23183 */ 23184 23185/** 23186 * @typedef {Object} Options 23187 * @property {string} [className='ol-layer'] A CSS class name to set to the layer element. 23188 * @property {number} [opacity=1] Opacity (0, 1). 23189 * @property {boolean} [visible=true] Visibility. 23190 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be 23191 * rendered outside of this extent. 23192 * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers 23193 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed 23194 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()` 23195 * method was used. 23196 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be 23197 * visible. 23198 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will 23199 * be visible. 23200 * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be 23201 * visible. 23202 * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will 23203 * be visible.
23204 * @property {BackgroundColor} [background] Background color for the layer. If not specified, no background 23205 * will be rendered. 23206 * @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`. 23207 */ 23208 23209/** 23210 * @classdesc 23211 * Abstract base class; normally only used for creating subclasses and not 23212 * instantiated in apps. 23213 * Note that with {@link module:ol/layer/Base~BaseLayer} and all its subclasses, any property set in 23214 * the options is set as a {@link module:ol/Object~BaseObject} property on the layer object, so 23215 * is observable, and has get/set accessors. 23216 * 23217 * @api 23218 */ 23219class BaseLayer extends ol_Object { 23220 /** 23221 * @param {Options} options Layer options. 23222 */ 23223 constructor(options) { 23224 super(); 23225 23226 /*** 23227 * @type {BaseLayerOnSignature<import("../events").EventsKey>} 23228 */ 23229 this.on; 23230 23231 /*** 23232 * @type {BaseLayerOnSignature<import("../events").EventsKey>} 23233 */ 23234 this.once; 23235 23236 /*** 23237 * @type {BaseLayerOnSignature<void>} 23238 */ 23239 this.un; 23240 23241 /** 23242 * @type {BackgroundColor|false} 23243 * @private 23244 */ 23245 this.background_ = options.background; 23246 23247 /** 23248 * @type {Object<string, *>} 23249 */ 23250 const properties = Object.assign({}, options); 23251 if (typeof options.properties === 'object') { 23252 delete properties.properties; 23253 Object.assign(properties, options.properties); 23254 } 23255 23256 properties[layer_Property.OPACITY] = 23257 options.opacity !== undefined ? options.opacity : 1; 23258 asserts_assert(typeof properties[layer_Property.OPACITY] === 'number', 64); // Layer opacity must be a number 23259 23260 properties[layer_Property.VISIBLE] = 23261 options.visible !== undefined ? options.visible : true; 23262 properties[layer_Property.Z_INDEX] = options.zIndex; 23263 properties[layer_Property.MAX_RESOLUTION] = 23264 options.maxResolution !== undefined ? options.maxResolution : Infinity; 23265 properties[layer_Property.MIN_RESOLUTION] = 23266 options.minResolution !== undefined ? options.minResolution : 0; 23267 properties[layer_Property.MIN_ZOOM] = 23268 options.minZoom !== undefined ? options.minZoom : -Infinity; 23269 properties[layer_Property.MAX_ZOOM] = 23270 options.maxZoom !== undefined ? options.maxZoom : Infinity; 23271 23272 /** 23273 * @type {string} 23274 * @private 23275 */ 23276 this.className_ = 23277 properties.className !== undefined ? properties.className : 'ol-layer'; 23278 delete properties.className; 23279 23280 this.setProperties(properties); 23281 23282 /** 23283 * @type {import("./Layer.js").State} 23284 * @private 23285 */ 23286 this.state_ = null; 23287 } 23288 23289 /** 23290 * Get the background for this layer.
23291 * @return {BackgroundColor|false} Layer background. 23292 */ 23293 getBackground() { 23294 return this.background_; 23295 } 23296 23297 /** 23298 * @return {string} CSS class name. 23299 */ 23300 getClassName() { 23301 return this.className_; 23302 } 23303 23304 /** 23305 * This method is not meant to be called by layers or layer renderers because the state 23306 * is incorrect if the layer is included in a layer group. 23307 * 23308 * @param {boolean} [managed] Layer is managed. 23309 * @return {import("./Layer.js").State} Layer state. 23310 */ 23311 getLayerState(managed) { 23312 /** @type {import("./Layer.js").State} */ 23313 const state = 23314 this.state_ || 23315 /** @type {?} */ ({ 23316 layer: this, 23317 managed: managed === undefined ? true : managed, 23318 }); 23319 const zIndex = this.getZIndex(); 23320 state.opacity = math_clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1); 23321 state.visible = this.getVisible(); 23322 state.extent = this.getExtent(); 23323 state.zIndex = zIndex === undefined && !state.managed ? Infinity : zIndex; 23324 state.maxResolution = this.getMaxResolution(); 23325 state.minResolution = Math.max(this.getMinResolution(), 0); 23326 state.minZoom = this.getMinZoom(); 23327 state.maxZoom = this.getMaxZoom(); 23328 this.state_ = state; 23329 23330 return state; 23331 } 23332 23333 /** 23334 * @abstract 23335 * @param {Array<import("./Layer.js").default>} [array] Array of layers (to be 23336 * modified in place). 23337 * @return {Array<import("./Layer.js").default>} Array of layers. 23338 */ 23339 getLayersArray(array) { 23340 return util_abstract(); 23341 } 23342 23343 /** 23344 * @abstract 23345 * @param {Array<import("./Layer.js").State>} [states] Optional list of layer 23346 * states (to be modified in place). 23347 * @return {Array<import("./Layer.js").State>} List of layer states. 23348 */ 23349 getLayerStatesArray(states) { 23350 return util_abstract(); 23351 } 23352 23353 /** 23354 * Return the {@link module:ol/extent~Extent extent} of the layer or `undefined` if it 23355 * will be visible regardless of extent. 23356 * @return {import("../extent.js").Extent|undefined} The layer extent. 23357 * @observable 23358 * @api 23359 */ 23360 getExtent() { 23361 return /** @type {import("../extent.js").Extent|undefined} */ ( 23362 this.get(layer_Property.EXTENT) 23363 ); 23364 } 23365 23366 /** 23367 * Return the maximum resolution of the layer. 23368 * @return {number} The maximum resolution of the layer. 23369 * @observable 23370 * @api 23371 */ 23372 getMaxResolution() { 23373 return /** @type {number} */ (this.get(layer_Property.MAX_RESOLUTION)); 23374 } 23375 23376 /** 23377 * Return the minimum resolution of the layer. 23378 * @return {number} The minimum resolution of the layer. 23379 * @observable 23380 * @api 23381 */ 23382 getMinResolution() { 23383 return /** @type {number} */ (this.get(layer_Property.MIN_RESOLUTION)); 23384 } 23385 23386 /** 23387 * Return the minimum zoom level of the layer. 23388 * @return {number} The minimum zoom level of the layer. 23389 * @observable 23390 * @api 23391 */ 23392 getMinZoom() { 23393 return /** @type {number} */ (this.get(layer_Property.MIN_ZOOM)); 23394 } 23395 23396 /** 23397 * Return the maximum zoom level of the layer. 23398 * @return {number} The maximum zoom level of the layer. 23399 * @observable 23400 * @api 23401 */ 23402 getMaxZoom() { 23403 return /** @type {number} */ (this.get(layer_Property.MAX_ZOOM)); 23404 } 23405 23406 /** 23407 * Return the opacity of the layer (between 0 and 1). 23408 * @return {number} The opacity of the layer. 23409 * @observable 23410 * @api 23411 */ 23412 getOpacity() { 23413 return /** @type {number} */ (this.get(layer_Property.OPACITY)); 23414 } 23415 23416 /** 23417 * @abstract 23418 * @return {import("../source/Source.js").State} Source state. 23419 */ 23420 getSourceState() { 23421 return util_abstract(); 23422 } 23423 23424 /** 23425 * Return the visibility of the layer (`true` or `false`). 23426 * @return {boolean} The visibility of the layer. 23427 * @observable 23428 * @api 23429 */ 23430 getVisible() { 23431 return /** @type {boolean} */ (this.get(layer_Property.VISIBLE)); 23432 } 23433 23434 /** 23435 * Return the Z-index of the layer, which is used to order layers before 23436 * rendering. The default Z-index is 0. 23437 * @return {number} The Z-index of the layer. 23438 * @observable 23439 * @api 23440 */ 23441 getZIndex() { 23442 return /** @type {number} */ (this.get(layer_Property.Z_INDEX)); 23443 } 23444 23445 /** 23446 * Sets the background color.
23447 * @param {BackgroundColor} [background] Background color. 23448 */ 23449 setBackground(background) { 23450 this.background_ = background; 23451 this.changed(); 23452 } 23453 23454 /** 23455 * Set the extent at which the layer is visible. If `undefined`, the layer 23456 * will be visible at all extents. 23457 * @param {import("../extent.js").Extent|undefined} extent The extent of the layer. 23458 * @observable 23459 * @api 23460 */ 23461 setExtent(extent) { 23462 this.set(layer_Property.EXTENT, extent); 23463 } 23464 23465 /** 23466 * Set the maximum resolution at which the layer is visible. 23467 * @param {number} maxResolution The maximum resolution of the layer. 23468 * @observable 23469 * @api 23470 */ 23471 setMaxResolution(maxResolution) { 23472 this.set(layer_Property.MAX_RESOLUTION, maxResolution); 23473 } 23474 23475 /** 23476 * Set the minimum resolution at which the layer is visible. 23477 * @param {number} minResolution The minimum resolution of the layer. 23478 * @observable 23479 * @api 23480 */ 23481 setMinResolution(minResolution) { 23482 this.set(layer_Property.MIN_RESOLUTION, minResolution); 23483 } 23484 23485 /** 23486 * Set the maximum zoom (exclusive) at which the layer is visible. 23487 * Note that the zoom levels for layer visibility are based on the 23488 * view zoom level, which may be different from a tile source zoom level. 23489 * @param {number} maxZoom The maximum zoom of the layer. 23490 * @observable 23491 * @api 23492 */ 23493 setMaxZoom(maxZoom) { 23494 this.set(layer_Property.MAX_ZOOM, maxZoom); 23495 } 23496 23497 /** 23498 * Set the minimum zoom (inclusive) at which the layer is visible. 23499 * Note that the zoom levels for layer visibility are based on the 23500 * view zoom level, which may be different from a tile source zoom level. 23501 * @param {number} minZoom The minimum zoom of the layer. 23502 * @observable 23503 * @api 23504 */ 23505 setMinZoom(minZoom) { 23506 this.set(layer_Property.MIN_ZOOM, minZoom); 23507 } 23508 23509 /** 23510 * Set the opacity of the layer, allowed values range from 0 to 1. 23511 * @param {number} opacity The opacity of the layer. 23512 * @observable 23513 * @api 23514 */ 23515 setOpacity(opacity) { 23516 asserts_assert(typeof opacity === 'number', 64); // Layer opacity must be a number 23517 this.set(layer_Property.OPACITY, opacity); 23518 } 23519 23520 /** 23521 * Set the visibility of the layer (`true` or `false`). 23522 * @param {boolean} visible The visibility of the layer. 23523 * @observable 23524 * @api 23525 */ 23526 setVisible(visible) { 23527 this.set(layer_Property.VISIBLE, visible); 23528 } 23529 23530 /** 23531 * Set Z-index of the layer, which is used to order layers before rendering. 23532 * The default Z-index is 0. 23533 * @param {number} zindex The z-index of the layer. 23534 * @observable 23535 * @api 23536 */ 23537 setZIndex(zindex) { 23538 this.set(layer_Property.Z_INDEX, zindex); 23539 } 23540 23541 /** 23542 * Clean up. 23543 */ 23544 disposeInternal() { 23545 if (this.state_) { 23546 this.state_.layer = null; 23547 this.state_ = null; 23548 } 23549 super.disposeInternal(); 23550 } 23551} 23552 23553/* harmony default export */ const Base = (BaseLayer); 23554 23555;// CONCATENATED MODULE: ./node_modules/ol/render/EventType.js 23556/** 23557 * @module ol/render/EventType 23558 */ 23559 23560/** 23561 * @enum {string} 23562 */ 23563/* harmony default export */ const render_EventType = ({ 23564 /** 23565 * Triggered before a layer is rendered. 23566 * @event module:ol/render/Event~RenderEvent#prerender 23567 * @api 23568 */ 23569 PRERENDER: 'prerender', 23570 23571 /** 23572 * Triggered after a layer is rendered. 23573 * @event module:ol/render/Event~RenderEvent#postrender 23574 * @api 23575 */ 23576 POSTRENDER: 'postrender', 23577 23578 /** 23579 * Triggered before layers are composed. When dispatched by the map, the event object will not have
23580 * a `context` set. When dispatched by a layer, the event object will have a `context` set. Only 23581 * WebGL layers currently dispatch this event. 23582 * @event module:ol/render/Event~RenderEvent#precompose 23583 * @api 23584 */ 23585 PRECOMPOSE: 'precompose', 23586 23587 /** 23588 * Triggered after layers are composed. When dispatched by the map, the event object will not have 23589 * a `context` set. When dispatched by a layer, the event object will have a `context` set. Only 23590 * WebGL layers currently dispatch this event. 23591 * @event module:ol/render/Event~RenderEvent#postcompose 23592 * @api 23593 */ 23594 POSTCOMPOSE: 'postcompose', 23595 23596 /** 23597 * Triggered when rendering is complete, i.e. all sources and tiles have 23598 * finished loading for the current viewport, and all tiles are faded in. 23599 * The event object will not have a `context` set. 23600 * @event module:ol/render/Event~RenderEvent#rendercomplete 23601 * @api 23602 */ 23603 RENDERCOMPLETE: 'rendercomplete', 23604}); 23605 23606/** 23607 * @typedef {'postrender'|'precompose'|'postcompose'|'rendercomplete'} MapRenderEventTypes 23608 */ 23609 23610/** 23611 * @typedef {'postrender'|'prerender'} LayerRenderEventTypes 23612 */ 23613 23614;// CONCATENATED MODULE: ./node_modules/ol/layer/Layer.js 23615/** 23616 * @module ol/layer/Layer 23617 */ 23618 23619 23620 23621 23622 23623 23624 23625/** 23626 * @typedef {function(import("../Map.js").FrameState):HTMLElement} RenderFunction 23627 */ 23628 23629/*** 23630 * @template Return 23631 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 23632 * import("../Observable").OnSignature<import("./Base").BaseLayerObjectEventTypes| 23633 * 'change:source', import("../Object").ObjectEvent, Return> & 23634 * import("../Observable").OnSignature<import("../render/EventType").LayerRenderEventTypes, import("../render/Event").default, Return> & 23635 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("./Base").BaseLayerObjectEventTypes|'change:source'| 23636 * import("../render/EventType").LayerRenderEventTypes, Return>} LayerOnSignature 23637 */ 23638 23639/** 23640 * @template {import("../source/Source.js").default} [SourceType=import("../source/Source.js").default] 23641 * @typedef {Object} Options 23642 * @property {string} [className='ol-layer'] A CSS class name to set to the layer element. 23643 * @property {number} [opacity=1] Opacity (0, 1). 23644 * @property {boolean} [visible=true] Visibility. 23645 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be 23646 * rendered outside of this extent. 23647 * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers 23648 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed 23649 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()` 23650 * method was used. 23651 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be 23652 * visible. 23653 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will 23654 * be visible. 23655 * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be 23656 * visible. 23657 * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will 23658 * be visible. 23659 * @property {SourceType} [source] Source for this layer. If not provided to the constructor, 23660 * the source can be set by calling {@link module:ol/layer/Layer~Layer#setSource layer.setSource(source)} after 23661 * construction. 23662 * @property {import("../Map.js").default|null} [map] Map. 23663 * @property {RenderFunction} [render] Render function. Takes the frame state as input and is expected to return an 23664 * HTML element. Will overwrite the default rendering for the layer. 23665 * @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`. 23666 */ 23667 23668/** 23669 * @typedef {Object} State 23670 * @property {import("./Layer.js").default} layer Layer. 23671 * @property {number} opacity Opacity, the value is rounded to two digits to appear after the decimal point. 23672 * @property {boolean} visible Visible. 23673 * @property {boolean} managed Managed. 23674 * @property {import("../extent.js").Extent} [extent] Extent. 23675 * @property {number} zIndex ZIndex. 23676 * @property {number} maxResolution Maximum resolution. 23677 * @property {number} minResolution Minimum resolution. 23678 * @property {number} minZoom Minimum zoom. 23679 * @property {number} maxZoom Maximum zoom. 23680 */ 23681 23682/** 23683 * @classdesc 23684 * Base class from which all layer types are derived. This should only be instantiated 23685 * in the case where a custom layer is added to the map with a custom `render` function. 23686 * Such a function can be specified in the `options` object, and is expected to return an HTML element. 23687 * 23688 * A visual representation of raster or vector map data. 23689 * Layers group together those properties that pertain to how the data is to be 23690 * displayed, irrespective of the source of that data. 23691 * 23692 * Layers are usually added to a map with [map.addLayer()]{@link import("../Map.js").default#addLayer}. 23693 * Components like {@link module:ol/interaction/Draw~Draw} use unmanaged layers 23694 * internally. These unmanaged layers are associated with the map using 23695 * [layer.setMap()]{@link module:ol/layer/Layer~Layer#setMap} instead. 23696 *
23697 * A generic `change` event is fired when the state of the source changes. 23698 * 23699 * @fires import("../render/Event.js").RenderEvent#prerender 23700 * @fires import("../render/Event.js").RenderEvent#postrender 23701 * 23702 * @template {import("../source/Source.js").default} [SourceType=import("../source/Source.js").default] 23703 * @template {import("../renderer/Layer.js").default} [RendererType=import("../renderer/Layer.js").default] 23704 * @api 23705 */ 23706class Layer extends Base { 23707 /** 23708 * @param {Options<SourceType>} options Layer options. 23709 */ 23710 constructor(options) { 23711 const baseOptions = Object.assign({}, options); 23712 delete baseOptions.source; 23713 23714 super(baseOptions); 23715 23716 /*** 23717 * @type {LayerOnSignature<import("../events").EventsKey>} 23718 */ 23719 this.on; 23720 23721 /*** 23722 * @type {LayerOnSignature<import("../events").EventsKey>} 23723 */ 23724 this.once; 23725 23726 /*** 23727 * @type {LayerOnSignature<void>} 23728 */ 23729 this.un; 23730 23731 /** 23732 * @private 23733 * @type {?import("../events.js").EventsKey} 23734 */ 23735 this.mapPrecomposeKey_ = null; 23736 23737 /** 23738 * @private 23739 * @type {?import("../events.js").EventsKey} 23740 */ 23741 this.mapRenderKey_ = null; 23742 23743 /** 23744 * @private 23745 * @type {?import("../events.js").EventsKey} 23746 */ 23747 this.sourceChangeKey_ = null; 23748 23749 /** 23750 * @private 23751 * @type {RendererType} 23752 */ 23753 this.renderer_ = null; 23754 23755 /** 23756 * @protected 23757 * @type {boolean} 23758 */ 23759 this.rendered = false; 23760 23761 // Overwrite default render method with a custom one 23762 if (options.render) { 23763 this.render = options.render; 23764 } 23765 23766 if (options.map) { 23767 this.setMap(options.map); 23768 } 23769 23770 this.addChangeListener( 23771 layer_Property.SOURCE, 23772 this.handleSourcePropertyChange_ 23773 ); 23774 23775 const source = options.source 23776 ? /** @type {SourceType} */ (options.source) 23777 : null; 23778 this.setSource(source); 23779 } 23780 23781 /** 23782 * @param {Array<import("./Layer.js").default>} [array] Array of layers (to be modified in place). 23783 * @return {Array<import("./Layer.js").default>} Array of layers. 23784 */ 23785 getLayersArray(array) { 23786 array = array ? array : []; 23787 array.push(this); 23788 return array; 23789 } 23790 23791 /** 23792 * @param {Array<import("./Layer.js").State>} [states] Optional list of layer states (to be modified in place). 23793 * @return {Array<import("./Layer.js").State>} List of layer states. 23794 */ 23795 getLayerStatesArray(states) { 23796 states = states ? states : []; 23797 states.push(this.getLayerState()); 23798 return states; 23799 } 23800 23801 /** 23802 * Get the layer source. 23803 * @return {SourceType|null} The layer source (or `null` if not yet set). 23804 * @observable 23805 * @api 23806 */ 23807 getSource() { 23808 return /** @type {SourceType} */ (this.get(layer_Property.SOURCE)) || null; 23809 } 23810 23811 /** 23812 * @return {SourceType|null} The source being rendered. 23813 */ 23814 getRenderSource() { 23815 return this.getSource(); 23816 } 23817 23818 /** 23819 * @return {import("../source/Source.js").State} Source state. 23820 */ 23821 getSourceState() { 23822 const source = this.getSource(); 23823 return !source ? 'undefined' : source.getState(); 23824 } 23825 23826 /** 23827 * @private 23828 */ 23829 handleSourceChange_() { 23830 this.changed(); 23831 } 23832 23833 /** 23834 * @private 23835 */ 23836 handleSourcePropertyChange_() { 23837 if (this.sourceChangeKey_) { 23838 unlistenByKey(this.sourceChangeKey_); 23839 this.sourceChangeKey_ = null; 23840 } 23841 const source = this.getSource(); 23842 if (source) { 23843 this.sourceChangeKey_ = listen( 23844 source, 23845 EventType.CHANGE, 23846 this.handleSourceChange_, 23847 this 23848 ); 23849 } 23850 this.changed(); 23851 } 23852 23853 /** 23854 * @param {import("../pixel").Pixel} pixel Pixel. 23855 * @return {Promise<Array<import("../Feature").default>>} Promise that resolves with 23856 * an array of features. 23857 */ 23858 getFeatures(pixel) { 23859 if (!this.renderer_) { 23860 return new Promise((resolve) => resolve([])); 23861 } 23862 return this.renderer_.getFeatures(pixel); 23863 } 23864 23865 /** 23866 * @param {import("../pixel").Pixel} pixel Pixel. 23867 * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data. 23868 */ 23869 getData(pixel) { 23870 if (!this.renderer_ || !this.rendered) { 23871 return null; 23872 } 23873 return this.renderer_.getData(pixel); 23874 } 23875 23876 /** 23877 * In charge to manage the rendering of the layer. One layer type is 23878 * bounded with one layer renderer. 23879 * @param {?import("../Map.js").FrameState} frameState Frame state. 23880 * @param {HTMLElement} target Target which the renderer may (but need not) use 23881 * for rendering its content. 23882 * @return {HTMLElement} The rendered element. 23883 */ 23884 render(frameState, target) { 23885 const layerRenderer = this.getRenderer(); 23886 23887 if (layerRenderer.prepareFrame(frameState)) { 23888 this.rendered = true; 23889 return layerRenderer.renderFrame(frameState, target); 23890 } 23891 } 23892 23893 /** 23894 * Called when a layer is not visible during a map render. 23895 */ 23896 unrender() { 23897 this.rendered = false;
23898 } 23899 23900 /** 23901 * For use inside the library only. 23902 * @param {import("../Map.js").default|null} map Map. 23903 */ 23904 setMapInternal(map) { 23905 if (!map) { 23906 this.unrender(); 23907 } 23908 this.set(layer_Property.MAP, map); 23909 } 23910 23911 /** 23912 * For use inside the library only. 23913 * @return {import("../Map.js").default|null} Map. 23914 */ 23915 getMapInternal() { 23916 return this.get(layer_Property.MAP); 23917 } 23918 23919 /** 23920 * Sets the layer to be rendered on top of other layers on a map. The map will 23921 * not manage this layer in its layers collection. This 23922 * is useful for temporary layers. To remove an unmanaged layer from the map, 23923 * use `#setMap(null)`. 23924 * 23925 * To add the layer to a map and have it managed by the map, use 23926 * {@link module:ol/Map~Map#addLayer} instead. 23927 * @param {import("../Map.js").default|null} map Map. 23928 * @api 23929 */ 23930 setMap(map) { 23931 if (this.mapPrecomposeKey_) { 23932 unlistenByKey(this.mapPrecomposeKey_); 23933 this.mapPrecomposeKey_ = null; 23934 } 23935 if (!map) { 23936 this.changed(); 23937 } 23938 if (this.mapRenderKey_) { 23939 unlistenByKey(this.mapRenderKey_); 23940 this.mapRenderKey_ = null; 23941 } 23942 if (map) { 23943 this.mapPrecomposeKey_ = listen( 23944 map, 23945 render_EventType.PRECOMPOSE, 23946 function (evt) { 23947 const renderEvent = 23948 /** @type {import("../render/Event.js").default} */ (evt); 23949 const layerStatesArray = renderEvent.frameState.layerStatesArray; 23950 const layerState = this.getLayerState(false); 23951 // A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both. 23952 asserts_assert( 23953 !layerStatesArray.some(function (arrayLayerState) { 23954 return arrayLayerState.layer === layerState.layer; 23955 }), 23956 67 23957 ); 23958 layerStatesArray.push(layerState); 23959 }, 23960 this 23961 ); 23962 this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map); 23963 this.changed(); 23964 } 23965 } 23966 23967 /** 23968 * Set the layer source. 23969 * @param {SourceType|null} source The layer source. 23970 * @observable 23971 * @api 23972 */ 23973 setSource(source) { 23974 this.set(layer_Property.SOURCE, source); 23975 } 23976 23977 /** 23978 * Get the renderer for this layer. 23979 * @return {RendererType|null} The layer renderer. 23980 */ 23981 getRenderer() { 23982 if (!this.renderer_) { 23983 this.renderer_ = this.createRenderer(); 23984 } 23985 return this.renderer_; 23986 } 23987 23988 /** 23989 * @return {boolean} The layer has a renderer. 23990 */ 23991 hasRenderer() { 23992 return !!this.renderer_; 23993 } 23994 23995 /** 23996 * Create a renderer for this layer. 23997 * @return {RendererType} A layer renderer. 23998 * @protected 23999 */ 24000 createRenderer() { 24001 return null; 24002 } 24003 24004 /** 24005 * Clean up. 24006 */ 24007 disposeInternal() { 24008 if (this.renderer_) { 24009 this.renderer_.dispose(); 24010 delete this.renderer_; 24011 } 24012 24013 this.setSource(null); 24014 super.disposeInternal(); 24015 } 24016} 24017 24018/** 24019 * Return `true` if the layer is visible and if the provided view state 24020 * has resolution and zoom levels that are in range of the layer's min/max. 24021 * @param {State} layerState Layer state. 24022 * @param {import("../View.js").State} viewState View state. 24023 * @return {boolean} The layer is visible at the given view state. 24024 */ 24025function inView(layerState, viewState) { 24026 if (!layerState.visible) { 24027 return false; 24028 } 24029 const resolution = viewState.resolution; 24030 if ( 24031 resolution < layerState.minResolution || 24032 resolution >= layerState.maxResolution 24033 ) { 24034 return false; 24035 } 24036 const zoom = viewState.zoom; 24037 return zoom > layerState.minZoom && zoom <= layerState.maxZoom; 24038} 24039 24040/* harmony default export */ const layer_Layer = (Layer); 24041 24042;// CONCATENATED MODULE: ./node_modules/ol/renderer/Map.js 24043/** 24044 * @module ol/renderer/Map 24045 */ 24046 24047 24048 24049 24050 24051 24052 24053 24054 24055/** 24056 * @typedef HitMatch 24057 * @property {import("../Feature.js").FeatureLike} feature Feature. 24058 * @property {import("../layer/Layer.js").default} layer Layer. 24059 * @property {import("../geom/SimpleGeometry.js").default} geometry Geometry. 24060 * @property {number} distanceSq Squared distance. 24061 * @property {import("./vector.js").FeatureCallback<T>} callback Callback. 24062 * @template T 24063 */ 24064 24065/** 24066 * @abstract 24067 */ 24068class MapRenderer extends ol_Disposable { 24069 /** 24070 * @param {import("../Map.js").default} map Map. 24071 */ 24072 constructor(map) { 24073 super(); 24074 24075 /** 24076 * @private 24077 * @type {import("../Map.js").default} 24078 */ 24079 this.map_ = map; 24080 } 24081 24082 /** 24083 * @abstract 24084 * @param {import("../render/EventType.js").default} type Event type. 24085 * @param {import("../Map.js").FrameState} frameState Frame state. 24086 */ 24087 dispatchRenderEvent(type, frameState) { 24088 util_abstract(); 24089 } 24090 24091 /** 24092 * @param {import("../Map.js").FrameState} frameState FrameState. 24093 * @protected 24094 */ 24095 calculateMatrices2D(frameState) { 24096 const viewState = frameState.viewState; 24097 const coordinateToPixelTransform = frameState.coordinateToPixelTransform; 24098 const pixelToCoordinateTransform = frameState.pixelToCoordinateTransform; 24099 24100 compose( 24101 coordinateToPixelTransform, 24102 frameState.size[0] / 2, 24103 frameState.size[1] / 2, 24104 1 / viewState.resolution, 24105 -1 / viewState.resolution, 24106 -viewState.rotation, 24107 -viewState.center[0], 24108 -viewState.center[1] 24109 ); 24110 24111 makeInverse(pixelToCoordinateTransform, coordinateToPixelTransform); 24112 } 24113 24114 /** 24115 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 24116 * @param {import("../Map.js").FrameState} frameState FrameState. 24117 * @param {number} hitTolerance Hit tolerance in pixels. 24118 * @param {boolean} checkWrapped Check for wrapped geometries. 24119 * @param {import("./vector.js").FeatureCallback<T>}
24119 callback Feature callback. 24120 * @param {S} thisArg Value to use as `this` when executing `callback`. 24121 * @param {function(this: U, import("../layer/Layer.js").default): boolean} layerFilter Layer filter 24122 * function, only layers which are visible and for which this function 24123 * returns `true` will be tested for features. By default, all visible 24124 * layers will be tested. 24125 * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`. 24126 * @return {T|undefined} Callback result. 24127 * @template S,T,U 24128 */ 24129 forEachFeatureAtCoordinate( 24130 coordinate, 24131 frameState, 24132 hitTolerance, 24133 checkWrapped, 24134 callback, 24135 thisArg, 24136 layerFilter, 24137 thisArg2 24138 ) { 24139 let result; 24140 const viewState = frameState.viewState; 24141 24142 /** 24143 * @param {boolean} managed Managed layer. 24144 * @param {import("../Feature.js").FeatureLike} feature Feature. 24145 * @param {import("../layer/Layer.js").default} layer Layer. 24146 * @param {import("../geom/Geometry.js").default} geometry Geometry. 24147 * @return {T|undefined} Callback result. 24148 */ 24149 function forEachFeatureAtCoordinate(managed, feature, layer, geometry) { 24150 return callback.call(thisArg, feature, managed ? layer : null, geometry); 24151 } 24152 24153 const projection = viewState.projection; 24154 24155 const translatedCoordinate = coordinate_wrapX(coordinate.slice(), projection); 24156 const offsets = [[0, 0]]; 24157 if (projection.canWrapX() && checkWrapped) { 24158 const projectionExtent = projection.getExtent(); 24159 const worldWidth = extent_getWidth(projectionExtent); 24160 offsets.push([-worldWidth, 0], [worldWidth, 0]); 24161 } 24162 24163 const layerStates = frameState.layerStatesArray; 24164 const numLayers = layerStates.length; 24165 24166 const matches = /** @type {Array<HitMatch<T>>} */ ([]); 24167 const tmpCoord = []; 24168 for (let i = 0; i < offsets.length; i++) { 24169 for (let j = numLayers - 1; j >= 0; --j) { 24170 const layerState = layerStates[j]; 24171 const layer = layerState.layer; 24172 if ( 24173 layer.hasRenderer() && 24174 inView(layerState, viewState) && 24175 layerFilter.call(thisArg2, layer) 24176 ) { 24177 const layerRenderer = layer.getRenderer(); 24178 const source = layer.getSource(); 24179 if (layerRenderer && source) { 24180 const coordinates = source.getWrapX() 24181 ? translatedCoordinate 24182 : coordinate; 24183 const callback = forEachFeatureAtCoordinate.bind( 24184 null, 24185 layerState.managed 24186 ); 24187 tmpCoord[0] = coordinates[0] + offsets[i][0]; 24188 tmpCoord[1] = coordinates[1] + offsets[i][1]; 24189 result = layerRenderer.forEachFeatureAtCoordinate( 24190 tmpCoord, 24191 frameState, 24192 hitTolerance, 24193 callback, 24194 matches 24195 ); 24196 } 24197 if (result) { 24198 return result; 24199 } 24200 } 24201 } 24202 } 24203 if (matches.length === 0) { 24204 return undefined; 24205 } 24206 const order = 1 / matches.length; 24207 matches.forEach((m, i) => (m.distanceSq += i * order)); 24208 matches.sort((a, b) => a.distanceSq - b.distanceSq); 24209 matches.some((m) => { 24210 return (result = m.callback(m.feature, m.layer, m.geometry)); 24211 }); 24212 return result; 24213 } 24214 24215 /** 24216 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 24217 * @param {import("../Map.js").FrameState} frameState FrameState. 24218 * @param {number} hitTolerance Hit tolerance in pixels. 24219 * @param {boolean} checkWrapped Check for wrapped geometries. 24220 * @param {function(this: U, import("../layer/Layer.js").default): boolean} layerFilter Layer filter 24221 * function, only layers which are visible and for which this function 24222 * returns `true` will be tested for features. By default, all visible 24223 * layers will be tested. 24224 * @param {U} thisArg Value to use as `this` when executing `layerFilter`. 24225 * @return {boolean} Is there a feature at the given coordinate? 24226 * @template U 24227 */ 24228 hasFeatureAtCoordinate( 24229 coordinate, 24230 frameState, 24231 hitTolerance, 24232 checkWrapped, 24233 layerFilter, 24234 thisArg 24235 ) { 24236 const hasFeature = this.forEachFeatureAtCoordinate( 24237 coordinate, 24238 frameState, 24239 hitTolerance, 24240 checkWrapped, 24241 TRUE, 24242 this, 24243 layerFilter, 24244 thisArg 24245 ); 24246 24247 return hasFeature !== undefined; 24248 } 24249 24250 /** 24251 * @return {import("../Map.js").default} Map. 24252 */ 24253 getMap() { 24254 return this.map_; 24255 } 24256 24257 /** 24258 * Render. 24259 * @abstract 24260 * @param {?import("../Map.js").FrameState} frameState Frame state. 24261 */ 24262 renderFrame(frameState) { 24263 util_abstract(); 24264 } 24265 24266 /** 24267 * @param {import("../Map.js").FrameState} frameState Frame state. 24268 * @protected 24269 */ 24270 scheduleExpireIconCache(frameState) { 24271 if (shared.canExpireCache()) { 24272 frameState.postRenderFunctions.push(expireIconCache); 24273 } 24274 } 24275} 24276 24277/** 24278 * @param {import("../Map.js").default} map Map. 24279 * @param {import("../Map.js").FrameState} frameState Frame state. 24280 */ 24281function expireIconCache(map, frameState) { 24282 shared.expire(); 24283} 24284 24285/* harmony default export */ const Map = (MapRenderer); 24286 24287;// CONCATENATED MODULE: ./node_modules/ol/render/Event.js 24288/** 24289 * @module ol/render/Event 24290 */ 24291 24292 24293
24294class RenderEvent extends Event { 24295 /** 24296 * @param {import("./EventType.js").default} type Type. 24297 * @param {import("../transform.js").Transform} [inversePixelTransform] Transform for 24298 * CSS pixels to rendered pixels. 24299 * @param {import("../Map.js").FrameState} [frameState] Frame state. 24300 * @param {?(CanvasRenderingContext2D|WebGLRenderingContext)} [context] Context. 24301 */ 24302 constructor(type, inversePixelTransform, frameState, context) { 24303 super(type); 24304 24305 /** 24306 * Transform from CSS pixels (relative to the top-left corner of the map viewport) 24307 * to rendered pixels on this event's `context`. Only available when a Canvas renderer is used, null otherwise. 24308 * @type {import("../transform.js").Transform|undefined} 24309 * @api 24310 */ 24311 this.inversePixelTransform = inversePixelTransform; 24312 24313 /** 24314 * An object representing the current render frame state. 24315 * @type {import("../Map.js").FrameState|undefined} 24316 * @api 24317 */ 24318 this.frameState = frameState; 24319 24320 /** 24321 * Canvas context. Not available when the event is dispatched by the map. For Canvas 2D layers, 24322 * the context will be the 2D rendering context. For WebGL layers, the context will be the WebGL 24323 * context. 24324 * @type {CanvasRenderingContext2D|WebGLRenderingContext|undefined} 24325 * @api 24326 */ 24327 this.context = context; 24328 } 24329} 24330 24331/* harmony default export */ const render_Event = (RenderEvent); 24332 24333;// CONCATENATED MODULE: ./node_modules/ol/css.js 24334/** 24335 * @module ol/css 24336 */ 24337 24338/** 24339 * @typedef {Object} FontParameters 24340 * @property {string} style Style. 24341 * @property {string} variant Variant. 24342 * @property {string} weight Weight. 24343 * @property {string} size Size. 24344 * @property {string} lineHeight LineHeight. 24345 * @property {string} family Family. 24346 * @property {Array<string>} families Families. 24347 */ 24348 24349/** 24350 * The CSS class for hidden feature. 24351 * 24352 * @const 24353 * @type {string} 24354 */ 24355const CLASS_HIDDEN = 'ol-hidden'; 24356 24357/** 24358 * The CSS class that we'll give the DOM elements to have them selectable. 24359 * 24360 * @const 24361 * @type {string} 24362 */ 24363const CLASS_SELECTABLE = 'ol-selectable'; 24364 24365/** 24366 * The CSS class that we'll give the DOM elements to have them unselectable. 24367 * 24368 * @const 24369 * @type {string} 24370 */ 24371const CLASS_UNSELECTABLE = 'ol-unselectable'; 24372 24373/** 24374 * The CSS class for unsupported feature. 24375 * 24376 * @const 24377 * @type {string} 24378 */ 24379const CLASS_UNSUPPORTED = 'ol-unsupported'; 24380 24381/** 24382 * The CSS class for controls. 24383 * 24384 * @const 24385 * @type {string} 24386 */ 24387const CLASS_CONTROL = 'ol-control'; 24388 24389/** 24390 * The CSS class that we'll give the DOM elements that are collapsed, i.e. 24391 * to those elements which usually can be expanded. 24392 * 24393 * @const 24394 * @type {string} 24395 */ 24396const CLASS_COLLAPSED = 'ol-collapsed'; 24397 24398/** 24399 * From https://stackoverflow.com/questions/10135697/regex-to-parse-any-css-font 24400 * @type {RegExp} 24401 */ 24402const fontRegEx = new RegExp( 24403 [ 24404 '^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)', 24405 '(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)', 24406 '(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)', 24407 '(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?', 24408 '(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))', 24409 '(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))', 24410 '?\\s*([-,\\"\\\'\\sa-z]+?)\\s*$', 24411 ].join(''), 24412 'i' 24413); 24414const fontRegExMatchIndex = [ 24415 'style', 24416 'variant', 24417 'weight', 24418 'size', 24419 'lineHeight', 24420 'family', 24421]; 24422 24423/** 24424 * Get the list of font families from a font spec. Note that this doesn't work 24425 * for font families that have commas in them. 24426 * @param {string} fontSpec The CSS font property. 24427 * @return {FontParameters|null}
24427 The font parameters (or null if the input spec is invalid). 24428 */ 24429const getFontParameters = function (fontSpec) { 24430 const match = fontSpec.match(fontRegEx); 24431 if (!match) { 24432 return null; 24433 } 24434 const style = /** @type {FontParameters} */ ({ 24435 lineHeight: 'normal', 24436 size: '1.2em', 24437 style: 'normal', 24438 weight: 'normal', 24439 variant: 'normal', 24440 }); 24441 for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) { 24442 const value = match[i + 1]; 24443 if (value !== undefined) { 24444 style[fontRegExMatchIndex[i]] = value; 24445 } 24446 } 24447 style.families = style.family.split(/,\s?/); 24448 return style; 24449}; 24450 24451;// CONCATENATED MODULE: ./node_modules/ol/dom.js 24452 24453 24454/** 24455 * @module ol/dom 24456 */ 24457 24458//FIXME Move this function to the canvas module 24459/** 24460 * Create an html canvas element and returns its 2d context. 24461 * @param {number} [width] Canvas width. 24462 * @param {number} [height] Canvas height. 24463 * @param {Array<HTMLCanvasElement>} [canvasPool] Canvas pool to take existing canvas from. 24464 * @param {CanvasRenderingContext2DSettings} [settings] CanvasRenderingContext2DSettings 24465 * @return {CanvasRenderingContext2D} The context. 24466 */ 24467function createCanvasContext2D(width, height, canvasPool, settings) { 24468 /** @type {HTMLCanvasElement|OffscreenCanvas} */ 24469 let canvas; 24470 if (canvasPool && canvasPool.length) { 24471 canvas = canvasPool.shift(); 24472 } else if (WORKER_OFFSCREEN_CANVAS) { 24473 canvas = new OffscreenCanvas(width || 300, height || 300); 24474 } else { 24475 canvas = document.createElement('canvas'); 24476 } 24477 if (width) { 24478 canvas.width = width; 24479 } 24480 if (height) { 24481 canvas.height = height; 24482 } 24483 //FIXME Allow OffscreenCanvasRenderingContext2D as return type 24484 return /** @type {CanvasRenderingContext2D} */ ( 24485 canvas.getContext('2d', settings) 24486 ); 24487} 24488 24489/** 24490 * Releases canvas memory to avoid exceeding memory limits in Safari. 24491 * See https://pqina.nl/blog/total-canvas-memory-use-exceeds-the-maximum-limit/ 24492 * @param {CanvasRenderingContext2D} context Context. 24493 */ 24494function releaseCanvas(context) { 24495 const canvas = context.canvas; 24496 canvas.width = 1; 24497 canvas.height = 1; 24498 context.clearRect(0, 0, 1, 1); 24499} 24500 24501/** 24502 * Get the current computed width for the given element including margin, 24503 * padding and border. 24504 * Equivalent to jQuery's `$(el).outerWidth(true)`. 24505 * @param {!HTMLElement} element Element. 24506 * @return {number} The width. 24507 */ 24508function dom_outerWidth(element) { 24509 let width = element.offsetWidth; 24510 const style = getComputedStyle(element); 24511 width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); 24512 24513 return width; 24514} 24515 24516/** 24517 * Get the current computed height for the given element including margin, 24518 * padding and border. 24519 * Equivalent to jQuery's `$(el).outerHeight(true)`. 24520 * @param {!HTMLElement} element Element. 24521 * @return {number} The height. 24522 */ 24523function dom_outerHeight(element) { 24524 let height = element.offsetHeight; 24525 const style = getComputedStyle(element); 24526 height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10); 24527 24528 return height; 24529} 24530 24531/** 24532 * @param {Node} newNode Node to replace old node 24533 * @param {Node} oldNode The node to be replaced 24534 */ 24535function replaceNode(newNode, oldNode) { 24536 const parent = oldNode.parentNode; 24537 if (parent) { 24538 parent.replaceChild(newNode, oldNode); 24539 } 24540} 24541 24542/** 24543 * @param {Node} node The node to remove. 24544 * @return {Node|null} The node that was removed or null. 24545 */ 24546function removeNode(node) { 24547 return node && node.parentNode ? node.parentNode.removeChild(node) : null; 24548} 24549 24550/** 24551 * @param {Node} node The node to remove the children from. 24552 */ 24553function removeChildren(node) { 24554 while (node.lastChild) { 24555 node.removeChild(node.lastChild); 24556 } 24557} 24558 24559/** 24560 * Transform the children of a parent node so they match the 24561 * provided list of children. This function aims to efficiently 24562 * remove, add, and reorder child nodes while maintaining a simple 24563 * implementation (it is not guaranteed to minimize DOM operations). 24564 * @param {Node} node The parent node whose children need reworking. 24565 * @param {Array<Node>} children The desired children. 24566 */ 24567function replaceChildren(node, children) { 24568 const oldChildren = node.childNodes; 24569 24570 for (let i = 0; true; ++i) {
24571 const oldChild = oldChildren[i]; 24572 const newChild = children[i]; 24573 24574 // check if our work is done 24575 if (!oldChild && !newChild) { 24576 break; 24577 } 24578 24579 // check if children match 24580 if (oldChild === newChild) { 24581 continue; 24582 } 24583 24584 // check if a new child needs to be added 24585 if (!oldChild) { 24586 node.appendChild(newChild); 24587 continue; 24588 } 24589 24590 // check if an old child needs to be removed 24591 if (!newChild) { 24592 node.removeChild(oldChild); 24593 --i; 24594 continue; 24595 } 24596 24597 // reorder 24598 node.insertBefore(newChild, oldChild); 24599 } 24600} 24601 24602;// CONCATENATED MODULE: ./node_modules/ol/render/canvas.js 24603/** 24604 * @module ol/render/canvas 24605 */ 24606 24607 24608 24609 24610 24611 24612/** 24613 * @typedef {'Circle' | 'Image' | 'LineString' | 'Polygon' | 'Text' | 'Default'} BuilderType 24614 */ 24615 24616/** 24617 * @typedef {Object} FillState 24618 * @property {import("../colorlike.js").ColorLike} fillStyle FillStyle. 24619 */ 24620 24621/** 24622 * @typedef Label 24623 * @property {number} width Width. 24624 * @property {number} height Height. 24625 * @property {Array<string|number>} contextInstructions ContextInstructions. 24626 */ 24627 24628/** 24629 * @typedef {Object} FillStrokeState 24630 * @property {import("../colorlike.js").ColorLike} [currentFillStyle] Current FillStyle. 24631 * @property {import("../colorlike.js").ColorLike} [currentStrokeStyle] Current StrokeStyle. 24632 * @property {CanvasLineCap} [currentLineCap] Current LineCap. 24633 * @property {Array<number>} currentLineDash Current LineDash. 24634 * @property {number} [currentLineDashOffset] Current LineDashOffset. 24635 * @property {CanvasLineJoin} [currentLineJoin] Current LineJoin. 24636 * @property {number} [currentLineWidth] Current LineWidth. 24637 * @property {number} [currentMiterLimit] Current MiterLimit. 24638 * @property {number} [lastStroke] Last stroke. 24639 * @property {import("../colorlike.js").ColorLike} [fillStyle] FillStyle. 24640 * @property {import("../colorlike.js").ColorLike} [strokeStyle] StrokeStyle. 24641 * @property {CanvasLineCap} [lineCap] LineCap. 24642 * @property {Array<number>} lineDash LineDash. 24643 * @property {number} [lineDashOffset] LineDashOffset. 24644 * @property {CanvasLineJoin} [lineJoin] LineJoin. 24645 * @property {number} [lineWidth] LineWidth. 24646 * @property {number} [miterLimit] MiterLimit. 24647 */ 24648 24649/** 24650 * @typedef {Object} StrokeState 24651 * @property {CanvasLineCap} lineCap LineCap. 24652 * @property {Array<number>} lineDash LineDash. 24653 * @property {number} lineDashOffset LineDashOffset. 24654 * @property {CanvasLineJoin} lineJoin LineJoin. 24655 * @property {number} lineWidth LineWidth. 24656 * @property {number} miterLimit MiterLimit. 24657 * @property {import("../colorlike.js").ColorLike} strokeStyle StrokeStyle. 24658 */ 24659 24660/** 24661 * @typedef {Object} TextState 24662 * @property {string} font Font. 24663 * @property {CanvasTextAlign} [textAlign] TextAlign. 24664 * @property {import("../style/Text.js").TextJustify} [justify] Justify. 24665 * @property {CanvasTextBaseline} textBaseline TextBaseline. 24666 * @property {import("../style/Text.js").TextPlacement} [placement] Placement. 24667 * @property {number} [maxAngle] MaxAngle. 24668 * @property {boolean} [overflow] Overflow. 24669 * @property {import("../style/Fill.js").default} [backgroundFill] BackgroundFill. 24670 * @property {import("../style/Stroke.js").default} [backgroundStroke] BackgroundStroke. 24671 * @property {import("../size.js").Size} [scale] Scale. 24672 * @property {Array<number>} [padding] Padding. 24673 */ 24674 24675/** 24676 * @typedef {Object} SerializableInstructions 24677 * @property {Array<*>} instructions The rendering instructions. 24678 * @property {Array<*>} hitDetectionInstructions The rendering hit detection instructions. 24679 * @property {Array<number>} coordinates The array of all coordinates. 24680 * @property {!Object<string, TextState>} [textStates] The text states (decluttering). 24681 * @property {!Object<string, FillState>} [fillStates] The fill states (decluttering). 24682 * @property {!Object<string, StrokeState>} [strokeStates] The stroke states (decluttering). 24683 */ 24684 24685/** 24686 * @typedef {Object<number, import("./canvas/Executor.js").ReplayImageOrLabelArgs>} DeclutterImageWithText 24687 */ 24688 24689/** 24690 * @const 24691 * @type {string} 24692 */ 24693const defaultFont = '10px sans-serif'; 24694 24695/** 24696 * @const 24697 * @type {import("../colorlike.js").ColorLike} 24698 */ 24699const defaultFillStyle = '#000'; 24700 24701/** 24702 * @const 24703 * @type {CanvasLineCap} 24704 */ 24705const defaultLineCap = 'round'; 24706 24707/** 24708 * @const 24709 * @type {Array<number>} 24710 */ 24711const defaultLineDash = []; 24712 24713/** 24714 * @const 24715 * @type {number} 24716 */ 24717const defaultLineDashOffset = 0; 24718 24719/** 24720 * @const 24721 * @type {CanvasLineJoin} 24722 */ 24723const defaultLineJoin = 'round'; 24724 24725/** 24726 * @const 24727 * @type {number} 24728 */ 24729const defaultMiterLimit = 10; 24730 24731/** 24732 * @const 24733 * @type {import("../colorlike.js").ColorLike} 24734 */ 24735const defaultStrokeStyle = '#000'; 24736 24737/** 24738 * @const 24739 * @type {CanvasTextAlign} 24740 */ 24741const defaultTextAlign = 'center'; 24742 24743/** 24744 * @const 24745 * @type {CanvasTextBaseline} 24746 */ 24747const defaultTextBaseline = 'middle'; 24748 24749/** 24750 * @const 24751 * @type {Array<number>} 24752 */ 24753const defaultPadding = [0, 0, 0, 0]; 24754 24755/** 24756 * @const 24757 * @type {number} 24758 */ 24759const defaultLineWidth = 1; 24760 24761/** 24762 * @type {BaseObject} 24763 */ 24764const checkedFonts = new ol_Object(); 24765 24766/** 24767 * @type {CanvasRenderingContext2D} 24768 */ 24769let measureContext = null; 24770 24771/** 24772 * @type {string} 24773 */ 24774let measureFont; 24775 24776/**
24777 * @type {!Object<string, number>} 24778 */ 24779const textHeights = {}; 24780 24781/** 24782 * Clears the label cache when a font becomes available. 24783 * @param {string} fontSpec CSS font spec. 24784 */ 24785const registerFont = (function () { 24786 const retries = 100; 24787 const size = '32px '; 24788 const referenceFonts = ['monospace', 'serif']; 24789 const len = referenceFonts.length; 24790 const text = 'wmytzilWMYTZIL@#/&?$%10\uF013'; 24791 let interval, referenceWidth; 24792 24793 /** 24794 * @param {string} fontStyle Css font-style 24795 * @param {string} fontWeight Css font-weight 24796 * @param {*} fontFamily Css font-family 24797 * @return {boolean} Font with style and weight is available 24798 */ 24799 function isAvailable(fontStyle, fontWeight, fontFamily) { 24800 let available = true; 24801 for (let i = 0; i < len; ++i) { 24802 const referenceFont = referenceFonts[i]; 24803 referenceWidth = measureTextWidth( 24804 fontStyle + ' ' + fontWeight + ' ' + size + referenceFont, 24805 text 24806 ); 24807 if (fontFamily != referenceFont) { 24808 const width = measureTextWidth( 24809 fontStyle + 24810 ' ' + 24811 fontWeight + 24812 ' ' + 24813 size + 24814 fontFamily + 24815 ',' + 24816 referenceFont, 24817 text 24818 ); 24819 // If width and referenceWidth are the same, then the fallback was used 24820 // instead of the font we wanted, so the font is not available. 24821 available = available && width != referenceWidth; 24822 } 24823 } 24824 if (available) { 24825 return true; 24826 } 24827 return false; 24828 } 24829 24830 function check() { 24831 let done = true; 24832 const fonts = checkedFonts.getKeys(); 24833 for (let i = 0, ii = fonts.length; i < ii; ++i) { 24834 const font = fonts[i]; 24835 if (checkedFonts.get(font) < retries) { 24836 if (isAvailable.apply(this, font.split('\n'))) { 24837 clear(textHeights); 24838 // Make sure that loaded fonts are picked up by Safari 24839 measureContext = null; 24840 measureFont = undefined; 24841 checkedFonts.set(font, retries); 24842 } else { 24843 checkedFonts.set(font, checkedFonts.get(font) + 1, true); 24844 done = false; 24845 } 24846 } 24847 } 24848 if (done) { 24849 clearInterval(interval); 24850 interval = undefined; 24851 } 24852 } 24853 24854 return function (fontSpec) { 24855 const font = getFontParameters(fontSpec); 24856 if (!font) { 24857 return; 24858 } 24859 const families = font.families; 24860 for (let i = 0, ii = families.length; i < ii; ++i) { 24861 const family = families[i]; 24862 const key = font.style + '\n' + font.weight + '\n' + family; 24863 if (checkedFonts.get(key) === undefined) { 24864 checkedFonts.set(key, retries, true); 24865 if (!isAvailable(font.style, font.weight, family)) { 24866 checkedFonts.set(key, 0, true); 24867 if (interval === undefined) { 24868 interval = setInterval(check, 32); 24869 } 24870 } 24871 } 24872 } 24873 }; 24874})(); 24875 24876/** 24877 * @param {string} font Font to use for measuring. 24878 * @return {import("../size.js").Size} Measurement. 24879 */ 24880const measureTextHeight = (function () { 24881 /** 24882 * @type {HTMLDivElement} 24883 */ 24884 let measureElement; 24885 return function (fontSpec) { 24886 let height = textHeights[fontSpec]; 24887 if (height == undefined) { 24888 if (WORKER_OFFSCREEN_CANVAS) { 24889 const font = getFontParameters(fontSpec); 24890 const metrics = measureText(fontSpec, 'Žg'); 24891 const lineHeight = isNaN(Number(font.lineHeight)) 24892 ? 1.2 24893 : Number(font.lineHeight); 24894 height = 24895 lineHeight * 24896 (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent); 24897 } else { 24898 if (!measureElement) { 24899 measureElement = document.createElement('div'); 24900 measureElement.innerHTML = 'M'; 24901 measureElement.style.minHeight = '0'; 24902 measureElement.style.maxHeight = 'none'; 24903 measureElement.style.height = 'auto'; 24904 measureElement.style.padding = '0'; 24905 measureElement.style.border = 'none'; 24906 measureElement.style.position = 'absolute'; 24907 measureElement.style.display = 'block'; 24908 measureElement.style.left = '-99999px'; 24909 } 24910 measureElement.style.font = fontSpec; 24911 document.body.appendChild(measureElement); 24912 height = measureElement.offsetHeight; 24913 document.body.removeChild(measureElement); 24914 } 24915 textHeights[fontSpec] = height; 24916 } 24917 return height; 24918 }; 24919})(); 24920 24921/** 24922 * @param {string} font Font. 24923 * @param {string} text Text. 24924 * @return {TextMetrics} Text metrics. 24925 */ 24926function measureText(font, text) { 24927 if (!measureContext) { 24928 measureContext = createCanvasContext2D(1, 1); 24929 } 24930 if (font != measureFont) { 24931 measureContext.font = font; 24932 measureFont = measureContext.font; 24933 } 24934 return measureContext.measureText(text); 24935} 24936 24937/** 24938 * @param {string} font Font. 24939 * @param {string} text Text. 24940 * @return {number} Width. 24941 */ 24942function measureTextWidth(font, text) { 24943 return measureText(font, text).width; 24944} 24945 24946/** 24947 * Measure text width using a cache. 24948 * @param {string} font The font. 24949 * @param {string} text The text to measure. 24950 * @param {Object<string, number>}
24950 cache A lookup of cached widths by text. 24951 * @return {number} The text width. 24952 */ 24953function measureAndCacheTextWidth(font, text, cache) { 24954 if (text in cache) { 24955 return cache[text]; 24956 } 24957 const width = text 24958 .split('\n') 24959 .reduce((prev, curr) => Math.max(prev, measureTextWidth(font, curr)), 0); 24960 cache[text] = width; 24961 return width; 24962} 24963 24964/** 24965 * @param {TextState} baseStyle Base style. 24966 * @param {Array<string>} chunks Text chunks to measure. 24967 * @return {{width: number, height: number, widths: Array<number>, heights: Array<number>, lineWidths: Array<number>}}} Text metrics. 24968 */ 24969function getTextDimensions(baseStyle, chunks) { 24970 const widths = []; 24971 const heights = []; 24972 const lineWidths = []; 24973 let width = 0; 24974 let lineWidth = 0; 24975 let height = 0; 24976 let lineHeight = 0; 24977 for (let i = 0, ii = chunks.length; i <= ii; i += 2) { 24978 const text = chunks[i]; 24979 if (text === '\n' || i === ii) { 24980 width = Math.max(width, lineWidth); 24981 lineWidths.push(lineWidth); 24982 lineWidth = 0; 24983 height += lineHeight; 24984 continue; 24985 } 24986 const font = chunks[i + 1] || baseStyle.font; 24987 const currentWidth = measureTextWidth(font, text); 24988 widths.push(currentWidth); 24989 lineWidth += currentWidth; 24990 const currentHeight = measureTextHeight(font); 24991 heights.push(currentHeight); 24992 lineHeight = Math.max(lineHeight, currentHeight); 24993 } 24994 return {width, height, widths, heights, lineWidths}; 24995} 24996 24997/** 24998 * @param {CanvasRenderingContext2D} context Context. 24999 * @param {number} rotation Rotation. 25000 * @param {number} offsetX X offset. 25001 * @param {number} offsetY Y offset. 25002 */ 25003function rotateAtOffset(context, rotation, offsetX, offsetY) { 25004 if (rotation !== 0) { 25005 context.translate(offsetX, offsetY); 25006 context.rotate(rotation); 25007 context.translate(-offsetX, -offsetY); 25008 } 25009} 25010 25011/** 25012 * @param {CanvasRenderingContext2D} context Context. 25013 * @param {import("../transform.js").Transform|null} transform Transform. 25014 * @param {number} opacity Opacity. 25015 * @param {Label|HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} labelOrImage Label. 25016 * @param {number} originX Origin X. 25017 * @param {number} originY Origin Y. 25018 * @param {number} w Width. 25019 * @param {number} h Height. 25020 * @param {number} x X. 25021 * @param {number} y Y. 25022 * @param {import("../size.js").Size} scale Scale. 25023 */ 25024function drawImageOrLabel( 25025 context, 25026 transform, 25027 opacity, 25028 labelOrImage, 25029 originX, 25030 originY, 25031 w, 25032 h, 25033 x, 25034 y, 25035 scale 25036) { 25037 context.save(); 25038 25039 if (opacity !== 1) { 25040 context.globalAlpha *= opacity; 25041 } 25042 if (transform) { 25043 context.setTransform.apply(context, transform); 25044 } 25045 25046 if (/** @type {*} */ (labelOrImage).contextInstructions) { 25047 // label 25048 context.translate(x, y); 25049 context.scale(scale[0], scale[1]); 25050 executeLabelInstructions(/** @type {Label} */ (labelOrImage), context); 25051 } else if (scale[0] < 0 || scale[1] < 0) { 25052 // flipped image 25053 context.translate(x, y); 25054 context.scale(scale[0], scale[1]); 25055 context.drawImage( 25056 /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ ( 25057 labelOrImage 25058 ), 25059 originX, 25060 originY, 25061 w, 25062 h, 25063 0, 25064 0, 25065 w, 25066 h 25067 ); 25068 } else { 25069 // if image not flipped translate and scale can be avoided 25070 context.drawImage( 25071 /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ ( 25072 labelOrImage 25073 ), 25074 originX, 25075 originY, 25076 w, 25077 h, 25078 x, 25079 y, 25080 w * scale[0], 25081 h * scale[1] 25082 ); 25083 } 25084 25085 context.restore(); 25086} 25087 25088/** 25089 * @param {Label} label Label. 25090 * @param {CanvasRenderingContext2D} context Context. 25091 */ 25092function executeLabelInstructions(label, context) { 25093 const contextInstructions = label.contextInstructions; 25094 for (let i = 0, ii = contextInstructions.length; i < ii; i += 2) { 25095 if (Array.isArray(contextInstructions[i + 1])) { 25096 context[contextInstructions[i]].apply( 25097 context, 25098 contextInstructions[i + 1] 25099 ); 25100 } else { 25101 context[contextInstructions[i]] = contextInstructions[i + 1]; 25102 } 25103 } 25104} 25105 25106;// CONCATENATED MODULE: ./node_modules/ol/renderer/Composite.js 25107/** 25108 * @module ol/renderer/Composite 25109 */ 25110 25111 25112 25113 25114 25115 25116 25117 25118 25119 25120/** 25121 * @classdesc 25122 * Canvas map renderer. 25123 * @api 25124 */ 25125class CompositeMapRenderer extends Map { 25126 /** 25127 * @param {import("../Map.js").default} map Map. 25128 */ 25129 constructor(map) { 25130 super(map); 25131 25132 /** 25133 * @type {import("../events.js").EventsKey} 25134 */ 25135 this.fontChangeListenerKey_ = listen( 25136 checkedFonts, 25137 ObjectEventType.PROPERTYCHANGE, 25138 map.redrawText.bind(map) 25139 ); 25140 25141 /** 25142 * @private 25143 * @type {HTMLDivElement} 25144 */ 25145 this.element_ = document.createElement('div'); 25146 const style = this.element_.style; 25147 style.position = 'absolute'; 25148 style.width = '100%'; 25149 style.height = '100%'; 25150 style.zIndex = '0'; 25151 25152 this.element_.className = CLASS_UNSELECTABLE + ' ol-layers'; 25153 25154 const container = map.getViewport(); 25155 container.insertBefore(this.element_, container.firstChild || null); 25156 25157 /** 25158 * @private 25159 * @type {Array<HTMLElement>} 25160 */ 25161 this.children_ = []; 25162 25163 /** 25164 * @private 25165 * @type {boolean} 25166 */ 25167 this.renderedVisible_ = true; 25168 } 25169 25170 /** 25171 * @param {import("../render/EventType.js").default} type Event type. 25172 * @param {import("../Map.js").FrameState} frameState Frame state. 25173 */ 25174 dispatchRenderEvent(type, frameState) { 25175 const map = this.getMap(); 25176 if (map.hasListener(type)) { 25177 const event = new render_Event(type, undefined, frameState); 25178 map.dispatchEvent(event); 25179 } 25180 } 25181 25182 disposeInternal() { 25183 unlistenByKey(this.fontChangeListenerKey_); 25184 this.element_.parentNode.removeChild(this.element_); 25185 super.disposeInternal(); 25186 } 25187 25188 /** 25189 * Render. 25190 * @param {?import("../Map.js").FrameState} frameState Frame state. 25191 */ 25192 renderFrame(frameState) { 25193 if (!frameState) { 25194 if (this.renderedVisible_) { 25195 this.element_.style.display = 'none'; 25196 this.renderedVisible_ = false;
25197 } 25198 return; 25199 } 25200 25201 this.calculateMatrices2D(frameState); 25202 this.dispatchRenderEvent(render_EventType.PRECOMPOSE, frameState); 25203 25204 const layerStatesArray = frameState.layerStatesArray.sort(function (a, b) { 25205 return a.zIndex - b.zIndex; 25206 }); 25207 const viewState = frameState.viewState; 25208 25209 this.children_.length = 0; 25210 /** 25211 * @type {Array<import("../layer/BaseVector.js").default>} 25212 */ 25213 const declutterLayers = []; 25214 let previousElement = null; 25215 for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) { 25216 const layerState = layerStatesArray[i]; 25217 frameState.layerIndex = i; 25218 25219 const layer = layerState.layer; 25220 const sourceState = layer.getSourceState(); 25221 if ( 25222 !inView(layerState, viewState) || 25223 (sourceState != 'ready' && sourceState != 'undefined') 25224 ) { 25225 layer.unrender(); 25226 continue; 25227 } 25228 25229 const element = layer.render(frameState, previousElement); 25230 if (!element) { 25231 continue; 25232 } 25233 if (element !== previousElement) { 25234 this.children_.push(element); 25235 previousElement = element; 25236 } 25237 if ('getDeclutter' in layer) { 25238 declutterLayers.push( 25239 /** @type {import("../layer/BaseVector.js").default} */ (layer) 25240 ); 25241 } 25242 } 25243 for (let i = declutterLayers.length - 1; i >= 0; --i) { 25244 declutterLayers[i].renderDeclutter(frameState); 25245 } 25246 25247 replaceChildren(this.element_, this.children_); 25248 25249 this.dispatchRenderEvent(render_EventType.POSTCOMPOSE, frameState); 25250 25251 if (!this.renderedVisible_) { 25252 this.element_.style.display = ''; 25253 this.renderedVisible_ = true; 25254 } 25255 25256 this.scheduleExpireIconCache(frameState); 25257 } 25258} 25259 25260/* harmony default export */ const Composite = (CompositeMapRenderer); 25261 25262;// CONCATENATED MODULE: ./node_modules/ol/layer/Group.js 25263/** 25264 * @module ol/layer/Group 25265 */ 25266 25267 25268 25269 25270 25271 25272 25273 25274 25275 25276 25277 25278/** 25279 * @typedef {'addlayer'|'removelayer'} EventType 25280 */ 25281 25282/** 25283 * @classdesc 25284 * A layer group triggers 'addlayer' and 'removelayer' events when layers are added to or removed from 25285 * the group or one of its child groups. When a layer group is added to or removed from another layer group, 25286 * a single event will be triggered (instead of one per layer in the group added or removed). 25287 */ 25288class GroupEvent extends Event { 25289 /** 25290 * @param {EventType} type The event type. 25291 * @param {BaseLayer} layer The layer. 25292 */ 25293 constructor(type, layer) { 25294 super(type); 25295 25296 /** 25297 * The added or removed layer. 25298 * @type {BaseLayer} 25299 * @api 25300 */ 25301 this.layer = layer; 25302 } 25303} 25304 25305/*** 25306 * @template Return 25307 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 25308 * import("../Observable").OnSignature<import("./Base").BaseLayerObjectEventTypes| 25309 * 'change:layers', import("../Object").ObjectEvent, Return> & 25310 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("./Base").BaseLayerObjectEventTypes|'change:layers', Return>} GroupOnSignature 25311 */ 25312 25313/** 25314 * @typedef {Object} Options 25315 * @property {number} [opacity=1] Opacity (0, 1). 25316 * @property {boolean} [visible=true] Visibility. 25317 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be 25318 * rendered outside of this extent. 25319 * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers 25320 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed 25321 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()` 25322 * method was used. 25323 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be 25324 * visible. 25325 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will 25326 * be visible. 25327 * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be 25328 * visible. 25329 * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will 25330 * be visible. 25331 * @property {Array<import("./Base.js").default>|Collection<import("./Base.js").default>} [layers] Child layers. 25332 * @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`. 25333 */ 25334 25335/** 25336 * @enum {string} 25337 * @private 25338 */ 25339const Group_Property = { 25340 LAYERS: 'layers', 25341}; 25342 25343/** 25344 * @classdesc 25345 * A {@link module:ol/Collection~Collection} of layers that are handled together. 25346 * 25347 * A generic `change` event is triggered when the group/Collection changes. 25348 * 25349 * @api 25350 */ 25351class LayerGroup extends Base { 25352 /** 25353 * @param {Options} [options] Layer options. 25354 */ 25355 constructor(options) { 25356 options = options || {}; 25357 const baseOptions = /** @type {Options} */ (Object.assign({}, options)); 25358 delete baseOptions.layers; 25359 25360 let layers = options.layers; 25361 25362 super(baseOptions); 25363 25364 /*** 25365 * @type {GroupOnSignature<import("../events").EventsKey>} 25366 */ 25367 this.on; 25368 25369 /*** 25370 * @type {GroupOnSignature<import("../events").EventsKey>} 25371 */ 25372 this.once; 25373 25374 /*** 25375 * @type {GroupOnSignature<void>} 25376 */ 25377 this.un; 25378 25379 /** 25380 * @private 25381 * @type {Array<import("../events.js").EventsKey>} 25382 */ 25383 this.layersListenerKeys_ = []; 25384 25385 /** 25386 * @private 25387 * @type {Object<string, Array<import("../events.js").EventsKey>>} 25388 */ 25389 this.listenerKeys_ = {}; 25390 25391 this.addChangeListener(Group_Property.LAYERS, this.handleLayersChanged_); 25392 25393 if (layers) { 25394 if (Array.isArray(layers)) { 25395 layers = new ol_Collection(layers.slice(), {unique: true}); 25396 } else { 25397 asserts_assert(typeof (/** @type {?} */ (layers).getArray) === 'function', 43); // Expected `layers` to be an array or a `Collection` 25398 } 25399 } else { 25400 layers = new ol_Collection(undefined, {unique: true}); 25401 } 25402 25403 this.setLayers(layers); 25404 } 25405 25406 /** 25407 * @private 25408 */ 25409 handleLayerChange_() { 25410 this.changed(); 25411 } 25412 25413 /** 25414 * @private 25415 */ 25416 handleLayersChanged_() { 25417 this.layersListenerKeys_.forEach(unlistenByKey); 25418 this.layersListenerKeys_.length = 0; 25419 25420 const layers = this.getLayers(); 25421 this.layersListenerKeys_.push( 25422 listen(layers, CollectionEventType.ADD, this.handleLayersAdd_, this), 25423 listen(layers, CollectionEventType.REMOVE, this.handleLayersRemove_, this) 25424 ); 25425 25426 for (const id in this.listenerKeys_) {
25427 this.listenerKeys_[id].forEach(unlistenByKey); 25428 } 25429 clear(this.listenerKeys_); 25430 25431 const layersArray = layers.getArray(); 25432 for (let i = 0, ii = layersArray.length; i < ii; i++) { 25433 const layer = layersArray[i]; 25434 this.registerLayerListeners_(layer); 25435 this.dispatchEvent(new GroupEvent('addlayer', layer)); 25436 } 25437 this.changed(); 25438 } 25439 25440 /** 25441 * @param {BaseLayer} layer The layer. 25442 */ 25443 registerLayerListeners_(layer) { 25444 const listenerKeys = [ 25445 listen( 25446 layer, 25447 ObjectEventType.PROPERTYCHANGE, 25448 this.handleLayerChange_, 25449 this 25450 ), 25451 listen(layer, EventType.CHANGE, this.handleLayerChange_, this), 25452 ]; 25453 25454 if (layer instanceof LayerGroup) { 25455 listenerKeys.push( 25456 listen(layer, 'addlayer', this.handleLayerGroupAdd_, this), 25457 listen(layer, 'removelayer', this.handleLayerGroupRemove_, this) 25458 ); 25459 } 25460 25461 this.listenerKeys_[getUid(layer)] = listenerKeys; 25462 } 25463 25464 /** 25465 * @param {GroupEvent} event The layer group event. 25466 */ 25467 handleLayerGroupAdd_(event) { 25468 this.dispatchEvent(new GroupEvent('addlayer', event.layer)); 25469 } 25470 25471 /** 25472 * @param {GroupEvent} event The layer group event. 25473 */ 25474 handleLayerGroupRemove_(event) { 25475 this.dispatchEvent(new GroupEvent('removelayer', event.layer)); 25476 } 25477 25478 /** 25479 * @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent. 25480 * @private 25481 */ 25482 handleLayersAdd_(collectionEvent) { 25483 const layer = collectionEvent.element; 25484 this.registerLayerListeners_(layer); 25485 this.dispatchEvent(new GroupEvent('addlayer', layer)); 25486 this.changed(); 25487 } 25488 25489 /** 25490 * @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent. 25491 * @private 25492 */ 25493 handleLayersRemove_(collectionEvent) { 25494 const layer = collectionEvent.element; 25495 const key = getUid(layer); 25496 this.listenerKeys_[key].forEach(unlistenByKey); 25497 delete this.listenerKeys_[key]; 25498 this.dispatchEvent(new GroupEvent('removelayer', layer)); 25499 this.changed(); 25500 } 25501 25502 /** 25503 * Returns the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers} 25504 * in this group. 25505 * @return {!Collection<import("./Base.js").default>} Collection of 25506 * {@link module:ol/layer/Base~BaseLayer layers} that are part of this group. 25507 * @observable 25508 * @api 25509 */ 25510 getLayers() {
25511 return /** @type {!Collection<import("./Base.js").default>} */ ( 25512 this.get(Group_Property.LAYERS) 25513 ); 25514 } 25515 25516 /** 25517 * Set the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers} 25518 * in this group. 25519 * @param {!Collection<import("./Base.js").default>} layers Collection of 25520 * {@link module:ol/layer/Base~BaseLayer layers} that are part of this group. 25521 * @observable 25522 * @api 25523 */ 25524 setLayers(layers) { 25525 const collection = this.getLayers(); 25526 if (collection) { 25527 const currentLayers = collection.getArray(); 25528 for (let i = 0, ii = currentLayers.length; i < ii; ++i) { 25529 this.dispatchEvent(new GroupEvent('removelayer', currentLayers[i])); 25530 } 25531 } 25532 25533 this.set(Group_Property.LAYERS, layers); 25534 } 25535 25536 /** 25537 * @param {Array<import("./Layer.js").default>} [array] Array of layers (to be modified in place). 25538 * @return {Array<import("./Layer.js").default>} Array of layers. 25539 */ 25540 getLayersArray(array) { 25541 array = array !== undefined ? array : []; 25542 this.getLayers().forEach(function (layer) { 25543 layer.getLayersArray(array); 25544 }); 25545 return array; 25546 } 25547 25548 /** 25549 * Get the layer states list and use this groups z-index as the default 25550 * for all layers in this and nested groups, if it is unset at this point. 25551 * If dest is not provided and this group's z-index is undefined 25552 * 0 is used a the default z-index. 25553 * @param {Array<import("./Layer.js").State>} [dest] Optional list 25554 * of layer states (to be modified in place). 25555 * @return {Array<import("./Layer.js").State>} List of layer states. 25556 */ 25557 getLayerStatesArray(dest) { 25558 const states = dest !== undefined ? dest : []; 25559 const pos = states.length; 25560 25561 this.getLayers().forEach(function (layer) { 25562 layer.getLayerStatesArray(states); 25563 }); 25564 25565 const ownLayerState = this.getLayerState(); 25566 let defaultZIndex = ownLayerState.zIndex; 25567 if (!dest && ownLayerState.zIndex === undefined) { 25568 defaultZIndex = 0; 25569 } 25570 for (let i = pos, ii = states.length; i < ii; i++) { 25571 const layerState = states[i]; 25572 layerState.opacity *= ownLayerState.opacity; 25573 layerState.visible = layerState.visible && ownLayerState.visible; 25574 layerState.maxResolution = Math.min( 25575 layerState.maxResolution, 25576 ownLayerState.maxResolution 25577 ); 25578 layerState.minResolution = Math.max( 25579 layerState.minResolution, 25580 ownLayerState.minResolution 25581 ); 25582 layerState.minZoom = Math.max(layerState.minZoom, ownLayerState.minZoom); 25583 layerState.maxZoom = Math.min(layerState.maxZoom, ownLayerState.maxZoom); 25584 if (ownLayerState.extent !== undefined) { 25585 if (layerState.extent !== undefined) { 25586 layerState.extent = getIntersection( 25587 layerState.extent, 25588 ownLayerState.extent 25589 ); 25590 } else { 25591 layerState.extent = ownLayerState.extent; 25592 } 25593 } 25594 if (layerState.zIndex === undefined) { 25595 layerState.zIndex = defaultZIndex; 25596 } 25597 } 25598 25599 return states; 25600 } 25601 25602 /** 25603 * @return {import("../source/Source.js").State} Source state. 25604 */ 25605 getSourceState() { 25606 return 'ready'; 25607 } 25608} 25609 25610/* harmony default export */ const Group = (LayerGroup); 25611 25612;// CONCATENATED MODULE: ./node_modules/ol/MapEvent.js 25613/** 25614 * @module ol/MapEvent 25615 */ 25616 25617 25618/** 25619 * @classdesc 25620 * Events emitted as map events are instances of this type. 25621 * See {@link module:ol/Map~Map} for which events trigger a map event. 25622 */ 25623class MapEvent extends Event { 25624 /** 25625 * @param {string} type Event type. 25626 * @param {import("./Map.js").default} map Map. 25627 * @param {?import("./Map.js").FrameState} [frameState] Frame state. 25628 */ 25629 constructor(type, map, frameState) { 25630 super(type); 25631 25632 /** 25633 * The map where the event occurred. 25634 * @type {import("./Map.js").default} 25635 * @api 25636 */ 25637 this.map = map; 25638 25639 /** 25640 * The frame state at the time of the event. 25641 * @type {?import("./Map.js").FrameState} 25642 * @api 25643 */ 25644 this.frameState = frameState !== undefined ? frameState : null; 25645 } 25646} 25647 25648/* harmony default export */ const ol_MapEvent = (MapEvent); 25649 25650;// CONCATENATED MODULE: ./node_modules/ol/MapBrowserEvent.js 25651/** 25652 * @module ol/MapBrowserEvent 25653 */ 25654 25655 25656/** 25657 * @classdesc 25658 * Events emitted as map browser events are instances of this type. 25659 * See {@link module:ol/Map~Map} for which events trigger a map browser event.
25660 * @template {UIEvent} EVENT 25661 */ 25662class MapBrowserEvent extends ol_MapEvent { 25663 /** 25664 * @param {string} type Event type. 25665 * @param {import("./Map.js").default} map Map. 25666 * @param {EVENT} originalEvent Original event. 25667 * @param {boolean} [dragging] Is the map currently being dragged? 25668 * @param {import("./Map.js").FrameState} [frameState] Frame state. 25669 * @param {Array<PointerEvent>} [activePointers] Active pointers. 25670 */ 25671 constructor(type, map, originalEvent, dragging, frameState, activePointers) { 25672 super(type, map, frameState); 25673 25674 /** 25675 * The original browser event. 25676 * @const 25677 * @type {EVENT} 25678 * @api 25679 */ 25680 this.originalEvent = originalEvent; 25681 25682 /** 25683 * The map pixel relative to the viewport corresponding to the original browser event. 25684 * @type {?import("./pixel.js").Pixel} 25685 */ 25686 this.pixel_ = null; 25687 25688 /** 25689 * The coordinate in the user projection corresponding to the original browser event. 25690 * @type {?import("./coordinate.js").Coordinate} 25691 */ 25692 this.coordinate_ = null; 25693 25694 /** 25695 * Indicates if the map is currently being dragged. Only set for 25696 * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`. 25697 * 25698 * @type {boolean} 25699 * @api 25700 */ 25701 this.dragging = dragging !== undefined ? dragging : false; 25702 25703 /** 25704 * @type {Array<PointerEvent>|undefined} 25705 */ 25706 this.activePointers = activePointers; 25707 } 25708 25709 /** 25710 * The map pixel relative to the viewport corresponding to the original event. 25711 * @type {import("./pixel.js").Pixel} 25712 * @api 25713 */ 25714 get pixel() { 25715 if (!this.pixel_) { 25716 this.pixel_ = this.map.getEventPixel(this.originalEvent); 25717 } 25718 return this.pixel_; 25719 } 25720 set pixel(pixel) { 25721 this.pixel_ = pixel; 25722 } 25723 25724 /** 25725 * The coordinate corresponding to the original browser event. This will be in the user 25726 * projection if one is set. Otherwise it will be in the view projection. 25727 * @type {import("./coordinate.js").Coordinate} 25728 * @api 25729 */ 25730 get coordinate() { 25731 if (!this.coordinate_) { 25732 this.coordinate_ = this.map.getCoordinateFromPixel(this.pixel); 25733 } 25734 return this.coordinate_; 25735 } 25736 set coordinate(coordinate) { 25737 this.coordinate_ = coordinate; 25738 } 25739 25740 /** 25741 * Prevents the default browser action. 25742 * See https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault. 25743 * @api 25744 */ 25745 preventDefault() { 25746 super.preventDefault(); 25747 if ('preventDefault' in this.originalEvent) { 25748 /** @type {UIEvent} */ (this.originalEvent).preventDefault(); 25749 } 25750 } 25751 25752 /** 25753 * Prevents further propagation of the current event. 25754 * See https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation. 25755 * @api 25756 */ 25757 stopPropagation() { 25758 super.stopPropagation(); 25759 if ('stopPropagation' in this.originalEvent) { 25760 /** @type {UIEvent} */ (this.originalEvent).stopPropagation(); 25761 } 25762 } 25763} 25764 25765/* harmony default export */ const ol_MapBrowserEvent = (MapBrowserEvent); 25766 25767;// CONCATENATED MODULE: ./node_modules/ol/MapBrowserEventType.js 25768/** 25769 * @module ol/MapBrowserEventType 25770 */ 25771 25772 25773/** 25774 * Constants for event names. 25775 * @enum {string} 25776 */ 25777/* harmony default export */ const ol_MapBrowserEventType = ({ 25778 /** 25779 * A true single click with no dragging and no double click. Note that this 25780 * event is delayed by 250 ms to ensure that it is not a double click. 25781 * @event module:ol/MapBrowserEvent~MapBrowserEvent#singleclick 25782 * @api 25783 */ 25784 SINGLECLICK: 'singleclick', 25785 25786 /** 25787 * A click with no dragging. A double click will fire two of this. 25788 * @event module:ol/MapBrowserEvent~MapBrowserEvent#click 25789 * @api 25790 */ 25791 CLICK: EventType.CLICK, 25792 25793 /** 25794 * A true double click, with no dragging. 25795 * @event module:ol/MapBrowserEvent~MapBrowserEvent#dblclick 25796 * @api 25797 */ 25798 DBLCLICK: EventType.DBLCLICK, 25799 25800 /** 25801 * Triggered when a pointer is dragged. 25802 * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointerdrag 25803 * @api 25804 */ 25805 POINTERDRAG: 'pointerdrag', 25806 25807 /** 25808 * Triggered when a pointer is moved. Note that on touch devices this is 25809 * triggered when the map is panned, so is not the same as mousemove. 25810 * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointermove 25811 * @api 25812 */ 25813 POINTERMOVE: 'pointermove', 25814 25815 POINTERDOWN: 'pointerdown', 25816 POINTERUP: 'pointerup', 25817 POINTEROVER: 'pointerover', 25818 POINTEROUT: 'pointerout', 25819 POINTERENTER: 'pointerenter', 25820 POINTERLEAVE: 'pointerleave', 25821 POINTERCANCEL: 'pointercancel', 25822}); 25823 25824/*** 25825 * @typedef {'singleclick'|'click'|'dblclick'|'pointerdrag'|'pointermove'} Types 25826 */ 25827 25828;// CONCATENATED MODULE: ./node_modules/ol/pointer/EventType.js 25829/** 25830 * @module ol/pointer/EventType 25831 */ 25832 25833/** 25834 * Constants for event names. 25835 * @enum {string} 25836 */ 25837/* harmony default export */ const pointer_EventType = ({ 25838 POINTERMOVE: 'pointermove', 25839 POINTERDOWN: 'pointerdown', 25840 POINTERUP: 'pointerup', 25841 POINTEROVER: 'pointerover', 25842 POINTEROUT: 'pointerout', 25843 POINTERENTER: 'pointerenter', 25844 POINTERLEAVE: 'pointerleave', 25845 POINTERCANCEL: 'pointercancel', 25846}); 25847 25848;// CONCATENATED MODULE: ./node_modules/ol/MapBrowserEventHandler.js 25849/** 25850 * @module ol/MapBrowserEventHandler 25851 */ 25852 25853 25854 25855 25856 25857 25858 25859 25860 25861 25862class MapBrowserEventHandler extends events_Target { 25863 /** 25864 * @param {import("./Map.js").default} map The map with the viewport to listen to events on. 25865 * @param {number} [moveTolerance] The minimal distance the pointer must travel to trigger a move. 25866 */ 25867 constructor(map, moveTolerance) { 25868 super(map); 25869 25870 /** 25871 * This is the element that we will listen to the real events on. 25872 * @type {import("./Map.js").default} 25873 * @private 25874 */ 25875 this.map_ = map; 25876 25877 /** 25878 * @type {any} 25879 * @private 25880 */ 25881 this.clickTimeoutId_; 25882 25883 /** 25884 * Emulate dblclick and singleclick. Will be true when only one pointer is active. 25885 * @type {boolean} 25886 */ 25887 this.emulateClicks_ = false;
25888 25889 /** 25890 * @type {boolean} 25891 * @private 25892 */ 25893 this.dragging_ = false; 25894 25895 /** 25896 * @type {!Array<import("./events.js").EventsKey>} 25897 * @private 25898 */ 25899 this.dragListenerKeys_ = []; 25900 25901 /** 25902 * @type {number} 25903 * @private 25904 */ 25905 this.moveTolerance_ = moveTolerance === undefined ? 1 : moveTolerance; 25906 25907 /** 25908 * The most recent "down" type event (or null if none have occurred). 25909 * Set on pointerdown. 25910 * @type {PointerEvent|null} 25911 * @private 25912 */ 25913 this.down_ = null; 25914 25915 const element = this.map_.getViewport(); 25916 25917 /** 25918 * @type {Array<PointerEvent>} 25919 * @private 25920 */ 25921 this.activePointers_ = []; 25922 25923 /** 25924 * @type {!Object<number, Event>} 25925 * @private 25926 */ 25927 this.trackedTouches_ = {}; 25928 25929 this.element_ = element; 25930 25931 /** 25932 * @type {?import("./events.js").EventsKey} 25933 * @private 25934 */ 25935 this.pointerdownListenerKey_ = listen( 25936 element, 25937 pointer_EventType.POINTERDOWN, 25938 this.handlePointerDown_, 25939 this 25940 ); 25941 25942 /** 25943 * @type {PointerEvent} 25944 * @private 25945 */ 25946 this.originalPointerMoveEvent_; 25947 25948 /** 25949 * @type {?import("./events.js").EventsKey} 25950 * @private 25951 */ 25952 this.relayedListenerKey_ = listen( 25953 element, 25954 pointer_EventType.POINTERMOVE, 25955 this.relayMoveEvent_, 25956 this 25957 ); 25958 25959 /** 25960 * @private 25961 */ 25962 this.boundHandleTouchMove_ = this.handleTouchMove_.bind(this); 25963 25964 this.element_.addEventListener( 25965 EventType.TOUCHMOVE, 25966 this.boundHandleTouchMove_, 25967 PASSIVE_EVENT_LISTENERS ? {passive: false} : false 25968 ); 25969 } 25970 25971 /** 25972 * @param {PointerEvent} pointerEvent Pointer 25973 * event. 25974 * @private 25975 */ 25976 emulateClick_(pointerEvent) { 25977 let newEvent = new ol_MapBrowserEvent( 25978 ol_MapBrowserEventType.CLICK, 25979 this.map_, 25980 pointerEvent 25981 ); 25982 this.dispatchEvent(newEvent); 25983 if (this.clickTimeoutId_ !== undefined) { 25984 // double-click 25985 clearTimeout(this.clickTimeoutId_); 25986 this.clickTimeoutId_ = undefined; 25987 newEvent = new ol_MapBrowserEvent( 25988 ol_MapBrowserEventType.DBLCLICK, 25989 this.map_, 25990 pointerEvent 25991 ); 25992 this.dispatchEvent(newEvent); 25993 } else { 25994 // click 25995 this.clickTimeoutId_ = setTimeout( 25996 /** @this {MapBrowserEventHandler} */ 25997 function () { 25998 this.clickTimeoutId_ = undefined; 25999 const newEvent = new ol_MapBrowserEvent( 26000 ol_MapBrowserEventType.SINGLECLICK, 26001 this.map_, 26002 pointerEvent 26003 ); 26004 this.dispatchEvent(newEvent); 26005 }.bind(this), 26006 250 26007 ); 26008 } 26009 } 26010 26011 /** 26012 * Keeps track on how many pointers are currently active. 26013 * 26014 * @param {PointerEvent} pointerEvent Pointer 26015 * event. 26016 * @private 26017 */ 26018 updateActivePointers_(pointerEvent) { 26019 const event = pointerEvent; 26020 const id = event.pointerId; 26021 26022 if ( 26023 event.type == ol_MapBrowserEventType.POINTERUP || 26024 event.type == ol_MapBrowserEventType.POINTERCANCEL 26025 ) { 26026 delete this.trackedTouches_[id]; 26027 for (const pointerId in this.trackedTouches_) { 26028 if (this.trackedTouches_[pointerId].target !== event.target) { 26029 // Some platforms assign a new pointerId when the target changes. 26030 // If this happens, delete one tracked pointer. If there is more 26031 // than one tracked pointer for the old target, it will be cleared 26032 // by subsequent POINTERUP events from other pointers. 26033 delete this.trackedTouches_[pointerId]; 26034 break; 26035 } 26036 } 26037 } else if ( 26038 event.type == ol_MapBrowserEventType.POINTERDOWN || 26039 event.type == ol_MapBrowserEventType.POINTERMOVE 26040 ) { 26041 this.trackedTouches_[id] = event; 26042 } 26043 this.activePointers_ = Object.values(this.trackedTouches_); 26044 } 26045 26046 /** 26047 * @param {PointerEvent} pointerEvent Pointer 26048 * event. 26049 * @private 26050 */ 26051 handlePointerUp_(pointerEvent) { 26052 this.updateActivePointers_(pointerEvent); 26053 const newEvent = new ol_MapBrowserEvent( 26054 ol_MapBrowserEventType.POINTERUP, 26055 this.map_, 26056 pointerEvent, 26057 undefined, 26058 undefined, 26059 this.activePointers_ 26060 ); 26061 this.dispatchEvent(newEvent); 26062 26063 // We emulate click events on left mouse button click, touch contact, and pen 26064 // contact. isMouseActionButton returns true in these cases (evt.button is set 26065 // to 0). 26066 // See http://www.w3.org/TR/pointerevents/#button-states 26067 // We only fire click, singleclick, and doubleclick if nobody has called 26068 // event.preventDefault(). 26069 if ( 26070 this.emulateClicks_ && 26071 !newEvent.defaultPrevented && 26072 !this.dragging_ && 26073 this.isMouseActionButton_(pointerEvent) 26074 ) { 26075 this.emulateClick_(this.down_); 26076 } 26077 26078 if (this.activePointers_.length === 0) { 26079 this.dragListenerKeys_.forEach(unlistenByKey); 26080 this.dragListenerKeys_.length = 0; 26081 this.dragging_ = false;
26082 this.down_ = null; 26083 } 26084 } 26085 26086 /** 26087 * @param {PointerEvent} pointerEvent Pointer 26088 * event. 26089 * @return {boolean} If the left mouse button was pressed. 26090 * @private 26091 */ 26092 isMouseActionButton_(pointerEvent) { 26093 return pointerEvent.button === 0; 26094 } 26095 26096 /** 26097 * @param {PointerEvent} pointerEvent Pointer 26098 * event. 26099 * @private 26100 */ 26101 handlePointerDown_(pointerEvent) { 26102 this.emulateClicks_ = this.activePointers_.length === 0; 26103 this.updateActivePointers_(pointerEvent); 26104 const newEvent = new ol_MapBrowserEvent( 26105 ol_MapBrowserEventType.POINTERDOWN, 26106 this.map_, 26107 pointerEvent, 26108 undefined, 26109 undefined, 26110 this.activePointers_ 26111 ); 26112 this.dispatchEvent(newEvent); 26113 26114 // Store a copy of the down event 26115 this.down_ = /** @type {PointerEvent} */ ({}); 26116 for (const property in pointerEvent) { 26117 const value = pointerEvent[property]; 26118 this.down_[property] = typeof value === 'function' ? VOID : value; 26119 } 26120 26121 if (this.dragListenerKeys_.length === 0) { 26122 const doc = this.map_.getOwnerDocument(); 26123 this.dragListenerKeys_.push( 26124 listen( 26125 doc, 26126 ol_MapBrowserEventType.POINTERMOVE, 26127 this.handlePointerMove_, 26128 this 26129 ), 26130 listen(doc, ol_MapBrowserEventType.POINTERUP, this.handlePointerUp_, this), 26131 /* Note that the listener for `pointercancel is set up on 26132 * `pointerEventHandler_` and not `documentPointerEventHandler_` like 26133 * the `pointerup` and `pointermove` listeners. 26134 * 26135 * The reason for this is the following: `TouchSource.vacuumTouches_()` 26136 * issues `pointercancel` events, when there was no `touchend` for a 26137 * `touchstart`. Now, let's say a first `touchstart` is registered on 26138 * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up. 26139 * But `documentPointerEventHandler_` doesn't know about the first 26140 * `touchstart`. If there is no `touchend` for the `touchstart`, we can 26141 * only receive a `touchcancel` from `pointerEventHandler_`, because it is 26142 * only registered there. 26143 */ 26144 listen( 26145 this.element_, 26146 ol_MapBrowserEventType.POINTERCANCEL, 26147 this.handlePointerUp_, 26148 this 26149 ) 26150 ); 26151 if (this.element_.getRootNode && this.element_.getRootNode() !== doc) { 26152 this.dragListenerKeys_.push( 26153 listen( 26154 this.element_.getRootNode(), 26155 ol_MapBrowserEventType.POINTERUP, 26156 this.handlePointerUp_, 26157 this 26158 ) 26159 ); 26160 } 26161 } 26162 } 26163 26164 /** 26165 * @param {PointerEvent} pointerEvent Pointer 26166 * event. 26167 * @private 26168 */ 26169 handlePointerMove_(pointerEvent) { 26170 // Between pointerdown and pointerup, pointermove events are triggered. 26171 // To avoid a 'false' touchmove event to be dispatched, we test if the pointer 26172 // moved a significant distance. 26173 if (this.isMoving_(pointerEvent)) { 26174 this.updateActivePointers_(pointerEvent); 26175 this.dragging_ = true; 26176 const newEvent = new ol_MapBrowserEvent( 26177 ol_MapBrowserEventType.POINTERDRAG, 26178 this.map_, 26179 pointerEvent, 26180 this.dragging_, 26181 undefined, 26182 this.activePointers_ 26183 ); 26184 this.dispatchEvent(newEvent); 26185 } 26186 } 26187 26188 /** 26189 * Wrap and relay a pointermove event. 26190 * @param {PointerEvent} pointerEvent Pointer 26191 * event. 26192 * @private 26193 */ 26194 relayMoveEvent_(pointerEvent) { 26195 this.originalPointerMoveEvent_ = pointerEvent; 26196 const dragging = !!(this.down_ && this.isMoving_(pointerEvent)); 26197 this.dispatchEvent( 26198 new ol_MapBrowserEvent( 26199 ol_MapBrowserEventType.POINTERMOVE, 26200 this.map_, 26201 pointerEvent, 26202 dragging 26203 ) 26204 ); 26205 } 26206 26207 /** 26208 * Flexible handling of a `touch-action: none` css equivalent: because calling 26209 * `preventDefault()` on a `pointermove` event does not stop native page scrolling 26210 * and zooming, we also listen for `touchmove` and call `preventDefault()` on it 26211 * when an interaction (currently `DragPan` handles the event. 26212 * @param {TouchEvent} event Event. 26213 * @private 26214 */ 26215 handleTouchMove_(event) { 26216 // Due to https://github.com/mpizenberg/elm-pep/issues/2, `this.originalPointerMoveEvent_` 26217 // may not be initialized yet when we get here on a platform without native pointer events. 26218 const originalEvent = this.originalPointerMoveEvent_; 26219 if ( 26220 (!originalEvent || originalEvent.defaultPrevented) && 26221 (typeof event.cancelable !== 'boolean' || event.cancelable === true) 26222 ) { 26223 event.preventDefault(); 26224 } 26225 } 26226 26227 /** 26228 * @param {PointerEvent} pointerEvent Pointer 26229 * event. 26230 * @return {boolean} Is moving. 26231 * @private 26232 */ 26233 isMoving_(pointerEvent) { 26234 return ( 26235 this.dragging_ || 26236 Math.abs(pointerEvent.clientX - this.down_.clientX) > 26237 this.moveTolerance_ || 26238 Math.abs(pointerEvent.clientY - this.down_.clientY) > this.moveTolerance_ 26239 ); 26240 } 26241 26242 /** 26243 * Clean up. 26244 */ 26245 disposeInternal() { 26246 if (this.relayedListenerKey_) { 26247 unlistenByKey(this.relayedListenerKey_); 26248 this.relayedListenerKey_ = null; 26249 } 26250 this.element_.removeEventListener( 26251 EventType.TOUCHMOVE, 26252 this.boundHandleTouchMove_ 26253 ); 26254 26255 if (this.pointerdownListenerKey_) { 26256 unlistenByKey(this.pointerdownListenerKey_); 26257 this.pointerdownListenerKey_ = null; 26258 } 26259 26260 this.dragListenerKeys_.forEach(unlistenByKey); 26261 this.dragListenerKeys_.length = 0; 26262 26263 this.element_ = null; 26264 super.disposeInternal(); 26265 } 26266} 26267 26268/* harmony default export */ const ol_MapBrowserEventHandler = (MapBrowserEventHandler); 26269 26270;// CONCATENATED MODULE: ./node_modules/ol/MapEventType.js 26271/** 26272 * @module ol/MapEventType 26273 */ 26274 26275/** 26276 * @enum {string} 26277 */ 26278/* harmony default export */ const MapEventType = ({ 26279 /** 26280 * Triggered after a map frame is rendered. 26281 * @event module:ol/MapEvent~MapEvent#postrender 26282 * @api 26283 */ 26284 POSTRENDER: 'postrender', 26285 26286 /** 26287 * Triggered when the map starts moving. 26288 * @event module:ol/MapEvent~MapEvent#movestart 26289 * @api 26290 */ 26291 MOVESTART: 'movestart', 26292 26293 /** 26294 * Triggered after the map is moved. 26295 * @event module:ol/MapEvent~MapEvent#moveend 26296 * @api 26297 */ 26298 MOVEEND: 'moveend', 26299 26300 /** 26301 * Triggered when loading of additional map data (tiles, images, features) starts. 26302 * @event module:ol/MapEvent~MapEvent#loadstart 26303 * @api 26304 */ 26305 LOADSTART: 'loadstart', 26306 26307 /** 26308 * Triggered when loading of additional map data has completed. 26309 * @event module:ol/MapEvent~MapEvent#loadend 26310 * @api 26311 */ 26312 LOADEND: 'loadend', 26313}); 26314 26315/*** 26316 * @typedef {'postrender'|'movestart'|'moveend'|'loadstart'|'loadend'} Types 26317 */ 26318 26319;// CONCATENATED MODULE: ./node_modules/ol/MapProperty.js 26320/** 26321 * @module ol/MapProperty 26322 */ 26323
26324/** 26325 * @enum {string} 26326 */ 26327/* harmony default export */ const MapProperty = ({ 26328 LAYERGROUP: 'layergroup', 26329 SIZE: 'size', 26330 TARGET: 'target', 26331 VIEW: 'view', 26332}); 26333 26334;// CONCATENATED MODULE: ./node_modules/ol/structs/PriorityQueue.js 26335/** 26336 * @module ol/structs/PriorityQueue 26337 */ 26338 26339 26340 26341/** 26342 * @type {number} 26343 */ 26344const DROP = Infinity; 26345 26346/** 26347 * @classdesc 26348 * Priority queue. 26349 * 26350 * The implementation is inspired from the Closure Library's Heap class and 26351 * Python's heapq module. 26352 * 26353 * See https://github.com/google/closure-library/blob/master/closure/goog/structs/heap.js 26354 * and https://hg.python.org/cpython/file/2.7/Lib/heapq.py. 26355 * 26356 * @template T 26357 */ 26358class PriorityQueue { 26359 /** 26360 * @param {function(T): number} priorityFunction Priority function. 26361 * @param {function(T): string} keyFunction Key function. 26362 */ 26363 constructor(priorityFunction, keyFunction) { 26364 /** 26365 * @type {function(T): number} 26366 * @private 26367 */ 26368 this.priorityFunction_ = priorityFunction; 26369 26370 /** 26371 * @type {function(T): string} 26372 * @private 26373 */ 26374 this.keyFunction_ = keyFunction; 26375 26376 /** 26377 * @type {Array<T>} 26378 * @private 26379 */ 26380 this.elements_ = []; 26381 26382 /** 26383 * @type {Array<number>} 26384 * @private 26385 */ 26386 this.priorities_ = []; 26387 26388 /** 26389 * @type {!Object<string, boolean>} 26390 * @private 26391 */ 26392 this.queuedElements_ = {}; 26393 } 26394 26395 /** 26396 * FIXME empty description for jsdoc 26397 */ 26398 clear() { 26399 this.elements_.length = 0; 26400 this.priorities_.length = 0; 26401 clear(this.queuedElements_); 26402 } 26403 26404 /** 26405 * Remove and return the highest-priority element. O(log N). 26406 * @return {T} Element. 26407 */ 26408 dequeue() { 26409 const elements = this.elements_; 26410 const priorities = this.priorities_; 26411 const element = elements[0]; 26412 if (elements.length == 1) { 26413 elements.length = 0; 26414 priorities.length = 0; 26415 } else { 26416 elements[0] = elements.pop(); 26417 priorities[0] = priorities.pop(); 26418 this.siftUp_(0); 26419 } 26420 const elementKey = this.keyFunction_(element); 26421 delete this.queuedElements_[elementKey]; 26422 return element; 26423 } 26424 26425 /** 26426 * Enqueue an element. O(log N). 26427 * @param {T} element Element. 26428 * @return {boolean} The element was added to the queue. 26429 */ 26430 enqueue(element) { 26431 asserts_assert(!(this.keyFunction_(element) in this.queuedElements_), 31); // Tried to enqueue an `element` that was already added to the queue 26432 const priority = this.priorityFunction_(element); 26433 if (priority != DROP) { 26434 this.elements_.push(element); 26435 this.priorities_.push(priority); 26436 this.queuedElements_[this.keyFunction_(element)] = true; 26437 this.siftDown_(0, this.elements_.length - 1); 26438 return true; 26439 } 26440 return false; 26441 } 26442 26443 /** 26444 * @return {number} Count. 26445 */ 26446 getCount() { 26447 return this.elements_.length; 26448 } 26449 26450 /** 26451 * Gets the index of the left child of the node at the given index. 26452 * @param {number} index The index of the node to get the left child for. 26453 * @return {number} The index of the left child. 26454 * @private 26455 */ 26456 getLeftChildIndex_(index) { 26457 return index * 2 + 1; 26458 } 26459 26460 /** 26461 * Gets the index of the right child of the node at the given index. 26462 * @param {number} index The index of the node to get the right child for. 26463 * @return {number} The index of the right child. 26464 * @private 26465 */ 26466 getRightChildIndex_(index) { 26467 return index * 2 + 2; 26468 } 26469 26470 /** 26471 * Gets the index of the parent of the node at the given index. 26472 * @param {number} index The index of the node to get the parent for. 26473 * @return {number} The index of the parent. 26474 * @private 26475 */ 26476 getParentIndex_(index) { 26477 return (index - 1) >> 1; 26478 } 26479 26480 /** 26481 * Make this a heap. O(N). 26482 * @private 26483 */ 26484 heapify_() { 26485 let i; 26486 for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) { 26487 this.siftUp_(i); 26488 } 26489 } 26490 26491 /** 26492 * @return {boolean} Is empty. 26493 */ 26494 isEmpty() { 26495 return this.elements_.length === 0; 26496 } 26497 26498 /** 26499 * @param {string} key Key. 26500 * @return {boolean} Is key queued. 26501 */ 26502 isKeyQueued(key) { 26503 return key in this.queuedElements_; 26504 } 26505 26506 /** 26507 * @param {T} element Element. 26508 * @return {boolean} Is queued. 26509 */ 26510 isQueued(element) { 26511 return this.isKeyQueued(this.keyFunction_(element)); 26512 } 26513 26514 /** 26515 * @param {number} index The index of the node to move down. 26516 * @private 26517 */ 26518 siftUp_(index) { 26519 const elements = this.elements_; 26520 const priorities = this.priorities_; 26521 const count = elements.length; 26522 const element = elements[index]; 26523 const priority = priorities[index]; 26524 const startIndex = index; 26525 26526 while (index < count >> 1) { 26527 const lIndex = this.getLeftChildIndex_(index); 26528 const rIndex = this.getRightChildIndex_(index); 26529 26530 const smallerChildIndex = 26531 rIndex < count && priorities[rIndex] < priorities[lIndex] 26532 ? rIndex 26533 : lIndex; 26534 26535 elements[index] = elements[smallerChildIndex]; 26536 priorities[index] = priorities[smallerChildIndex]; 26537 index = smallerChildIndex; 26538 } 26539 26540 elements[index] = element; 26541 priorities[index] = priority; 26542 this.siftDown_(startIndex, index); 26543 } 26544 26545 /** 26546 * @param {number} startIndex The index of the root. 26547 * @param {number} index The index of the node to move up. 26548 * @private 26549 */ 26550 siftDown_(startIndex, index) { 26551 const elements = this.elements_; 26552 const priorities = this.priorities_; 26553 const element = elements[index]; 26554 const priority = priorities[index]; 26555 26556 while (index > startIndex) { 26557 const parentIndex = this.getParentIndex_(index); 26558 if (priorities[parentIndex] > priority) { 26559 elements[index] = elements[parentIndex]; 26560 priorities[index] = priorities[parentIndex]; 26561 index = parentIndex; 26562 } else { 26563 break; 26564 } 26565 } 26566 elements[index] = element; 26567 priorities[index] = priority; 26568 } 26569 26570 /** 26571 * FIXME empty description for jsdoc 26572 */ 26573 reprioritize() { 26574 const priorityFunction = this.priorityFunction_; 26575 const elements = this.elements_; 26576 const priorities = this.priorities_; 26577 let index = 0; 26578 const n = elements.length; 26579 let element, i, priority; 26580 for (i = 0; i < n; ++i) { 26581 element = elements[i]; 26582 priority = priorityFunction(element); 26583 if (priority == DROP) { 26584 delete this.queuedElements_[this.keyFunction_(element)]; 26585 } else { 26586 priorities[index] = priority; 26587 elements[index++] = element; 26588 } 26589 } 26590 elements.length = index; 26591 priorities.length = index; 26592 this.heapify_(); 26593 } 26594} 26595
26596/* harmony default export */ const structs_PriorityQueue = (PriorityQueue); 26597 26598;// CONCATENATED MODULE: ./node_modules/ol/TileState.js 26599/** 26600 * @module ol/TileState 26601 */ 26602 26603/** 26604 * @enum {number} 26605 */ 26606/* harmony default export */ const TileState = ({ 26607 IDLE: 0, 26608 LOADING: 1, 26609 LOADED: 2, 26610 /** 26611 * Indicates that tile loading failed 26612 * @type {number} 26613 */ 26614 ERROR: 3, 26615 EMPTY: 4, 26616}); 26617 26618;// CONCATENATED MODULE: ./node_modules/ol/TileQueue.js 26619/** 26620 * @module ol/TileQueue 26621 */ 26622 26623 26624 26625 26626/** 26627 * @typedef {function(import("./Tile.js").default, string, import("./coordinate.js").Coordinate, number): number} PriorityFunction 26628 */ 26629 26630class TileQueue extends structs_PriorityQueue { 26631 /** 26632 * @param {PriorityFunction} tilePriorityFunction Tile priority function. 26633 * @param {function(): ?} tileChangeCallback Function called on each tile change event. 26634 */ 26635 constructor(tilePriorityFunction, tileChangeCallback) { 26636 super( 26637 /** 26638 * @param {Array} element Element. 26639 * @return {number} Priority. 26640 */ 26641 function (element) { 26642 return tilePriorityFunction.apply(null, element); 26643 }, 26644 /** 26645 * @param {Array} element Element. 26646 * @return {string} Key. 26647 */ 26648 function (element) { 26649 return /** @type {import("./Tile.js").default} */ (element[0]).getKey(); 26650 } 26651 ); 26652 26653 /** @private */ 26654 this.boundHandleTileChange_ = this.handleTileChange.bind(this); 26655 26656 /** 26657 * @private 26658 * @type {function(): ?} 26659 */ 26660 this.tileChangeCallback_ = tileChangeCallback; 26661 26662 /** 26663 * @private 26664 * @type {number} 26665 */ 26666 this.tilesLoading_ = 0; 26667 26668 /** 26669 * @private 26670 * @type {!Object<string,boolean>} 26671 */ 26672 this.tilesLoadingKeys_ = {}; 26673 } 26674 26675 /** 26676 * @param {Array} element Element. 26677 * @return {boolean} The element was added to the queue. 26678 */ 26679 enqueue(element) { 26680 const added = super.enqueue(element); 26681 if (added) { 26682 const tile = element[0]; 26683 tile.addEventListener(EventType.CHANGE, this.boundHandleTileChange_); 26684 } 26685 return added; 26686 } 26687 26688 /** 26689 * @return {number} Number of tiles loading. 26690 */ 26691 getTilesLoading() { 26692 return this.tilesLoading_; 26693 } 26694 26695 /** 26696 * @param {import("./events/Event.js").default} event Event. 26697 * @protected 26698 */ 26699 handleTileChange(event) { 26700 const tile = /** @type {import("./Tile.js").default} */ (event.target); 26701 const state = tile.getState(); 26702 if ( 26703 state === TileState.LOADED || 26704 state === TileState.ERROR || 26705 state === TileState.EMPTY 26706 ) { 26707 if (state !== TileState.ERROR) { 26708 tile.removeEventListener(EventType.CHANGE, this.boundHandleTileChange_); 26709 } 26710 const tileKey = tile.getKey(); 26711 if (tileKey in this.tilesLoadingKeys_) { 26712 delete this.tilesLoadingKeys_[tileKey]; 26713 --this.tilesLoading_; 26714 } 26715 this.tileChangeCallback_(); 26716 } 26717 } 26718 26719 /** 26720 * @param {number} maxTotalLoading Maximum number tiles to load simultaneously. 26721 * @param {number} maxNewLoads Maximum number of new tiles to load. 26722 */ 26723 loadMoreTiles(maxTotalLoading, maxNewLoads) { 26724 let newLoads = 0; 26725 let state, tile, tileKey; 26726 while ( 26727 this.tilesLoading_ < maxTotalLoading && 26728 newLoads < maxNewLoads && 26729 this.getCount() > 0 26730 ) { 26731 tile = /** @type {import("./Tile.js").default} */ (this.dequeue()[0]); 26732 tileKey = tile.getKey(); 26733 state = tile.getState(); 26734 if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) { 26735 this.tilesLoadingKeys_[tileKey] = true; 26736 ++this.tilesLoading_; 26737 ++newLoads; 26738 tile.load(); 26739 } 26740 } 26741 } 26742} 26743 26744/* harmony default export */ const ol_TileQueue = (TileQueue); 26745 26746/** 26747 * @param {import('./Map.js').FrameState} frameState Frame state. 26748 * @param {import("./Tile.js").default} tile Tile. 26749 * @param {string} tileSourceKey Tile source key. 26750 * @param {import("./coordinate.js").Coordinate} tileCenter Tile center. 26751 * @param {number} tileResolution Tile resolution. 26752 * @return {number} Tile priority. 26753 */ 26754function getTilePriority( 26755 frameState, 26756 tile, 26757 tileSourceKey, 26758 tileCenter, 26759 tileResolution 26760) { 26761 // Filter out tiles at higher zoom levels than the current zoom level, or that 26762 // are outside the visible extent. 26763 if (!frameState || !(tileSourceKey in frameState.wantedTiles)) { 26764 return DROP; 26765 } 26766 if (!frameState.wantedTiles[tileSourceKey][tile.getKey()]) { 26767 return DROP; 26768 } 26769 // Prioritize the highest zoom level tiles closest to the focus. 26770 // Tiles at higher zoom levels are prioritized using Math.log(tileResolution). 26771 // Within a zoom level, tiles are prioritized by the distance in pixels between 26772 // the center of the tile and the center of the viewport. The factor of 65536 26773 // means that the prioritization should behave as desired for tiles up to 26774 // 65536 * Math.log(2) = 45426 pixels from the focus. 26775 const center = frameState.viewState.center; 26776 const deltaX = tileCenter[0] - center[0]; 26777 const deltaY = tileCenter[1] - center[1]; 26778 return ( 26779 65536 * Math.log(tileResolution) + 26780 Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution 26781 ); 26782} 26783 26784;// CONCATENATED MODULE: ./node_modules/ol/control/Control.js 26785/** 26786 * @module ol/control/Control 26787 */ 26788 26789 26790 26791 26792 26793 26794/** 26795 * @typedef {Object} Options 26796 * @property {HTMLElement} [element] The element is the control's 26797 * container element. This only needs to be specified if you're developing 26798 * a custom control. 26799 * @property {function(import("../MapEvent.js").default):void} [render] Function called when
26800 * the control should be re-rendered. This is called in a `requestAnimationFrame` 26801 * callback. 26802 * @property {HTMLElement|string} [target] Specify a target if you want 26803 * the control to be rendered outside of the map's viewport. 26804 */ 26805 26806/** 26807 * @classdesc 26808 * A control is a visible widget with a DOM element in a fixed position on the 26809 * screen. They can involve user input (buttons), or be informational only; 26810 * the position is determined using CSS. By default these are placed in the 26811 * container with CSS class name `ol-overlaycontainer-stopevent`, but can use 26812 * any outside DOM element. 26813 * 26814 * This is the base class for controls. You can use it for simple custom 26815 * controls by creating the element with listeners, creating an instance: 26816 * ```js 26817 * const myControl = new Control({element: myElement}); 26818 * ``` 26819 * and then adding this to the map. 26820 * 26821 * The main advantage of having this as a control rather than a simple separate 26822 * DOM element is that preventing propagation is handled for you. Controls 26823 * will also be objects in a {@link module:ol/Collection~Collection}, so you can use their methods. 26824 * 26825 * You can also extend this base for your own control class. See 26826 * examples/custom-controls for an example of how to do this. 26827 * 26828 * @api 26829 */ 26830class Control extends ol_Object { 26831 /** 26832 * @param {Options} options Control options. 26833 */ 26834 constructor(options) { 26835 super(); 26836 26837 const element = options.element; 26838 if (element && !options.target && !element.style.pointerEvents) { 26839 element.style.pointerEvents = 'auto'; 26840 } 26841 26842 /** 26843 * @protected 26844 * @type {HTMLElement} 26845 */ 26846 this.element = element ? element : null; 26847 26848 /** 26849 * @private 26850 * @type {HTMLElement} 26851 */ 26852 this.target_ = null; 26853 26854 /** 26855 * @private 26856 * @type {import("../Map.js").default|null} 26857 */ 26858 this.map_ = null; 26859 26860 /** 26861 * @protected 26862 * @type {!Array<import("../events.js").EventsKey>} 26863 */ 26864 this.listenerKeys = []; 26865 26866 if (options.render) { 26867 this.render = options.render; 26868 } 26869 26870 if (options.target) { 26871 this.setTarget(options.target); 26872 } 26873 } 26874 26875 /** 26876 * Clean up. 26877 */ 26878 disposeInternal() { 26879 removeNode(this.element); 26880 super.disposeInternal(); 26881 } 26882 26883 /** 26884 * Get the map associated with this control. 26885 * @return {import("../Map.js").default|null} Map. 26886 * @api 26887 */ 26888 getMap() { 26889 return this.map_; 26890 } 26891 26892 /** 26893 * Remove the control from its current map and attach it to the new map. 26894 * Pass `null` to just remove the control from the current map. 26895 * Subclasses may set up event handlers to get notified about changes to 26896 * the map here. 26897 * @param {import("../Map.js").default|null} map Map. 26898 * @api 26899 */ 26900 setMap(map) { 26901 if (this.map_) { 26902 removeNode(this.element); 26903 } 26904 for (let i = 0, ii = this.listenerKeys.length; i < ii; ++i) { 26905 unlistenByKey(this.listenerKeys[i]); 26906 } 26907 this.listenerKeys.length = 0; 26908 this.map_ = map; 26909 if (map) { 26910 const target = this.target_ 26911 ? this.target_ 26912 : map.getOverlayContainerStopEvent(); 26913 target.appendChild(this.element); 26914 if (this.render !== VOID) { 26915 this.listenerKeys.push( 26916 listen(map, MapEventType.POSTRENDER, this.render, this) 26917 ); 26918 } 26919 map.render(); 26920 } 26921 } 26922 26923 /** 26924 * Renders the control. 26925 * @param {import("../MapEvent.js").default} mapEvent Map event. 26926 * @api 26927 */ 26928 render(mapEvent) {} 26929 26930 /** 26931 * This function is used to set a target element for the control. It has no 26932 * effect if it is called after the control has been added to the map (i.e. 26933 * after `setMap` is called on the control). If no `target` is set in the 26934 * options passed to the control constructor and if `setTarget` is not called 26935 * then the control is added to the map's overlay container. 26936 * @param {HTMLElement|string} target Target. 26937 * @api 26938 */ 26939 setTarget(target) { 26940 this.target_ = 26941 typeof target === 'string' ? document.getElementById(target) : target; 26942 } 26943} 26944 26945/* harmony default export */ const control_Control = (Control); 26946 26947;// CONCATENATED MODULE: ./node_modules/ol/control/Attribution.js 26948/** 26949 * @module ol/control/Attribution 26950 */ 26951 26952 26953 26954 26955 26956 26957 26958/** 26959 * @typedef {Object} Options 26960 * @property {string} [className='ol-attribution'] CSS class name. 26961 * @property {HTMLElement|string} [target] Specify a target if you 26962 * want the control to be rendered outside of the map's 26963 * viewport. 26964 * @property {boolean} [collapsible] Specify if attributions can 26965 * be collapsed. If not specified, sources control this behavior with their 26966 * `attributionsCollapsible` setting. 26967 * @property {boolean} [collapsed=true] Specify if attributions should 26968 * be collapsed at startup. 26969 * @property {string} [tipLabel='Attributions'] Text label to use for the button tip. 26970 * @property {string|HTMLElement} [label='i'] Text label to use for the 26971 * collapsed attributions button. 26972 * Instead of text, also an element (e.g. a `span` element) can be used. 26973 * @property {string} [expandClassName=className + '-expand'] CSS class name for the 26974 * collapsed attributions button. 26975 * @property {string|HTMLElement} [collapseLabel='âº'] Text label to use 26976 * for the expanded attributions button. 26977 * Instead of text, also an element (e.g. a `span` element) can be used. 26978 * @property {string} [collapseClassName=className + '-collapse'] CSS class name for the 26979 * expanded attributions button. 26980 * @property {function(import("../MapEvent.js").default):void} [render] Function called when
26981 * the control should be re-rendered. This is called in a `requestAnimationFrame` 26982 * callback. 26983 */ 26984 26985/** 26986 * @classdesc 26987 * Control to show all the attributions associated with the layer sources 26988 * in the map. This control is one of the default controls included in maps. 26989 * By default it will show in the bottom right portion of the map, but this can 26990 * be changed by using a css selector for `.ol-attribution`. 26991 * 26992 * @api 26993 */ 26994class Attribution extends control_Control { 26995 /** 26996 * @param {Options} [options] Attribution options. 26997 */ 26998 constructor(options) { 26999 options = options ? options : {}; 27000 27001 super({ 27002 element: document.createElement('div'), 27003 render: options.render, 27004 target: options.target, 27005 }); 27006 27007 /** 27008 * @private 27009 * @type {HTMLElement} 27010 */ 27011 this.ulElement_ = document.createElement('ul'); 27012 27013 /** 27014 * @private 27015 * @type {boolean} 27016 */ 27017 this.collapsed_ = 27018 options.collapsed !== undefined ? options.collapsed : true; 27019 27020 /** 27021 * @private 27022 * @type {boolean} 27023 */ 27024 this.userCollapsed_ = this.collapsed_; 27025 27026 /** 27027 * @private 27028 * @type {boolean} 27029 */ 27030 this.overrideCollapsible_ = options.collapsible !== undefined; 27031 27032 /** 27033 * @private 27034 * @type {boolean} 27035 */ 27036 this.collapsible_ = 27037 options.collapsible !== undefined ? options.collapsible : true; 27038 27039 if (!this.collapsible_) { 27040 this.collapsed_ = false; 27041 } 27042 27043 const className = 27044 options.className !== undefined ? options.className : 'ol-attribution'; 27045 27046 const tipLabel = 27047 options.tipLabel !== undefined ? options.tipLabel : 'Attributions'; 27048 27049 const expandClassName = 27050 options.expandClassName !== undefined 27051 ? options.expandClassName 27052 : className + '-expand'; 27053 27054 const collapseLabel = 27055 options.collapseLabel !== undefined ? options.collapseLabel : '\u203A'; 27056 27057 const collapseClassName = 27058 options.collapseClassName !== undefined 27059 ? options.collapseClassName 27060 : className + '-collapse'; 27061 27062 if (typeof collapseLabel === 'string') { 27063 /** 27064 * @private 27065 * @type {HTMLElement} 27066 */ 27067 this.collapseLabel_ = document.createElement('span'); 27068 this.collapseLabel_.textContent = collapseLabel; 27069 this.collapseLabel_.className = collapseClassName; 27070 } else { 27071 this.collapseLabel_ = collapseLabel; 27072 } 27073 27074 const label = options.label !== undefined ? options.label : 'i'; 27075 27076 if (typeof label === 'string') { 27077 /** 27078 * @private 27079 * @type {HTMLElement} 27080 */ 27081 this.label_ = document.createElement('span'); 27082 this.label_.textContent = label; 27083 this.label_.className = expandClassName; 27084 } else { 27085 this.label_ = label; 27086 } 27087 27088 const activeLabel = 27089 this.collapsible_ && !this.collapsed_ ? this.collapseLabel_ : this.label_; 27090 27091 /** 27092 * @private 27093 * @type {HTMLElement} 27094 */ 27095 this.toggleButton_ = document.createElement('button'); 27096 this.toggleButton_.setAttribute('type', 'button'); 27097 this.toggleButton_.setAttribute('aria-expanded', String(!this.collapsed_)); 27098 this.toggleButton_.title = tipLabel; 27099 this.toggleButton_.appendChild(activeLabel); 27100 27101 this.toggleButton_.addEventListener( 27102 EventType.CLICK, 27103 this.handleClick_.bind(this), 27104 false 27105 ); 27106 27107 const cssClasses = 27108 className + 27109 ' ' + 27110 CLASS_UNSELECTABLE + 27111 ' ' + 27112 CLASS_CONTROL + 27113 (this.collapsed_ && this.collapsible_ ? ' ' + CLASS_COLLAPSED : '') + 27114 (this.collapsible_ ? '' : ' ol-uncollapsible'); 27115 const element = this.element; 27116 element.className = cssClasses; 27117 element.appendChild(this.toggleButton_); 27118 element.appendChild(this.ulElement_); 27119 27120 /** 27121 * A list of currently rendered resolutions. 27122 * @type {Array<string>} 27123 * @private 27124 */ 27125 this.renderedAttributions_ = []; 27126 27127 /** 27128 * @private 27129 * @type {boolean} 27130 */ 27131 this.renderedVisible_ = true; 27132 } 27133 27134 /** 27135 * Collect a list of visible attributions and set the collapsible state. 27136 * @param {import("../Map.js").FrameState} frameState Frame state. 27137 * @return {Array<string>} Attributions. 27138 * @private 27139 */ 27140 collectSourceAttributions_(frameState) { 27141 /** 27142 * Used to determine if an attribution already exists.
27143 * @type {!Object<string, boolean>} 27144 */ 27145 const lookup = {}; 27146 27147 /** 27148 * A list of visible attributions. 27149 * @type {Array<string>} 27150 */ 27151 const visibleAttributions = []; 27152 27153 let collapsible = true; 27154 const layerStatesArray = frameState.layerStatesArray; 27155 for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) { 27156 const layerState = layerStatesArray[i]; 27157 if (!inView(layerState, frameState.viewState)) { 27158 continue; 27159 } 27160 27161 const source = /** @type {import("../layer/Layer.js").default} */ ( 27162 layerState.layer 27163 ).getSource(); 27164 if (!source) { 27165 continue; 27166 } 27167 27168 const attributionGetter = source.getAttributions(); 27169 if (!attributionGetter) { 27170 continue; 27171 } 27172 27173 const attributions = attributionGetter(frameState); 27174 if (!attributions) { 27175 continue; 27176 } 27177 27178 collapsible = 27179 collapsible && source.getAttributionsCollapsible() !== false; 27180 27181 if (Array.isArray(attributions)) { 27182 for (let j = 0, jj = attributions.length; j < jj; ++j) { 27183 if (!(attributions[j] in lookup)) { 27184 visibleAttributions.push(attributions[j]); 27185 lookup[attributions[j]] = true; 27186 } 27187 } 27188 } else { 27189 if (!(attributions in lookup)) { 27190 visibleAttributions.push(attributions); 27191 lookup[attributions] = true; 27192 } 27193 } 27194 } 27195 if (!this.overrideCollapsible_) { 27196 this.setCollapsible(collapsible); 27197 } 27198 return visibleAttributions; 27199 } 27200 27201 /** 27202 * @private 27203 * @param {?import("../Map.js").FrameState} frameState Frame state. 27204 */ 27205 updateElement_(frameState) { 27206 if (!frameState) { 27207 if (this.renderedVisible_) { 27208 this.element.style.display = 'none'; 27209 this.renderedVisible_ = false; 27210 } 27211 return; 27212 } 27213 27214 const attributions = this.collectSourceAttributions_(frameState); 27215 27216 const visible = attributions.length > 0; 27217 if (this.renderedVisible_ != visible) { 27218 this.element.style.display = visible ? '' : 'none'; 27219 this.renderedVisible_ = visible; 27220 } 27221 27222 if (equals(attributions, this.renderedAttributions_)) { 27223 return; 27224 } 27225 27226 removeChildren(this.ulElement_); 27227 27228 // append the attributions 27229 for (let i = 0, ii = attributions.length; i < ii; ++i) { 27230 const element = document.createElement('li'); 27231 element.innerHTML = attributions[i]; 27232 this.ulElement_.appendChild(element); 27233 } 27234 27235 this.renderedAttributions_ = attributions; 27236 } 27237 27238 /** 27239 * @param {MouseEvent} event The event to handle 27240 * @private 27241 */ 27242 handleClick_(event) { 27243 event.preventDefault(); 27244 this.handleToggle_(); 27245 this.userCollapsed_ = this.collapsed_; 27246 } 27247 27248 /** 27249 * @private 27250 */ 27251 handleToggle_() { 27252 this.element.classList.toggle(CLASS_COLLAPSED); 27253 if (this.collapsed_) { 27254 replaceNode(this.collapseLabel_, this.label_); 27255 } else { 27256 replaceNode(this.label_, this.collapseLabel_); 27257 } 27258 this.collapsed_ = !this.collapsed_; 27259 this.toggleButton_.setAttribute('aria-expanded', String(!this.collapsed_)); 27260 } 27261 27262 /** 27263 * Return `true` if the attribution is collapsible, `false` otherwise. 27264 * @return {boolean} True if the widget is collapsible. 27265 * @api 27266 */ 27267 getCollapsible() { 27268 return this.collapsible_; 27269 } 27270 27271 /** 27272 * Set whether the attribution should be collapsible. 27273 * @param {boolean} collapsible True if the widget is collapsible. 27274 * @api 27275 */ 27276 setCollapsible(collapsible) { 27277 if (this.collapsible_ === collapsible) { 27278 return; 27279 } 27280 this.collapsible_ = collapsible; 27281 this.element.classList.toggle('ol-uncollapsible'); 27282 if (this.userCollapsed_) { 27283 this.handleToggle_(); 27284 } 27285 } 27286 27287 /** 27288 * Collapse or expand the attribution according to the passed parameter. Will 27289 * not do anything if the attribution isn't collapsible or if the current 27290 * collapsed state is already the one requested. 27291 * @param {boolean} collapsed True if the widget is collapsed. 27292 * @api 27293 */ 27294 setCollapsed(collapsed) { 27295 this.userCollapsed_ = collapsed; 27296 if (!this.collapsible_ || this.collapsed_ === collapsed) { 27297 return; 27298 } 27299 this.handleToggle_(); 27300 } 27301 27302 /** 27303 * Return `true` when the attribution is currently collapsed or `false` 27304 * otherwise. 27305 * @return {boolean} True if the widget is collapsed. 27306 * @api 27307 */ 27308 getCollapsed() { 27309 return this.collapsed_; 27310 } 27311 27312 /** 27313 * Update the attribution element. 27314 * @param {import("../MapEvent.js").default} mapEvent Map event. 27315 * @override 27316 */ 27317 render(mapEvent) { 27318 this.updateElement_(mapEvent.frameState); 27319 } 27320} 27321 27322/* harmony default export */ const control_Attribution = (Attribution); 27323 27324;// CONCATENATED MODULE: ./node_modules/ol/control/Rotate.js 27325/** 27326 * @module ol/control/Rotate 27327 */ 27328 27329 27330 27331 27332 27333/** 27334 * @typedef {Object} Options 27335 * @property {string} [className='ol-rotate'] CSS class name. 27336 * @property {string|HTMLElement} [label='â§'] Text label to use for the rotate button. 27337 * Instead of text, also an element (e.g. a `span` element) can be used. 27338 * @property {string} [tipLabel='Reset rotation'] Text label to use for the rotate tip. 27339 * @property {string} [compassClassName='ol-compass'] CSS class name for the compass. 27340 * @property {number} [duration=250] Animation duration in milliseconds. 27341 * @property {boolean} [autoHide=true] Hide the control when rotation is 0. 27342 * @property {function(import("../MapEvent.js").default):void} [render] Function called when the control should
27343 * be re-rendered. This is called in a `requestAnimationFrame` callback. 27344 * @property {function():void} [resetNorth] Function called when the control is clicked. 27345 * This will override the default `resetNorth`. 27346 * @property {HTMLElement|string} [target] Specify a target if you want the control to be 27347 * rendered outside of the map's viewport. 27348 */ 27349 27350/** 27351 * @classdesc 27352 * A button control to reset rotation to 0. 27353 * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css 27354 * selector is added to the button when the rotation is 0. 27355 * 27356 * @api 27357 */ 27358class Rotate extends control_Control { 27359 /** 27360 * @param {Options} [options] Rotate options. 27361 */ 27362 constructor(options) { 27363 options = options ? options : {}; 27364 27365 super({ 27366 element: document.createElement('div'), 27367 render: options.render, 27368 target: options.target, 27369 }); 27370 27371 const className = 27372 options.className !== undefined ? options.className : 'ol-rotate'; 27373 27374 const label = options.label !== undefined ? options.label : '\u21E7'; 27375 27376 const compassClassName = 27377 options.compassClassName !== undefined 27378 ? options.compassClassName 27379 : 'ol-compass'; 27380 27381 /** 27382 * @type {HTMLElement} 27383 * @private 27384 */ 27385 this.label_ = null; 27386 27387 if (typeof label === 'string') { 27388 this.label_ = document.createElement('span'); 27389 this.label_.className = compassClassName; 27390 this.label_.textContent = label; 27391 } else { 27392 this.label_ = label; 27393 this.label_.classList.add(compassClassName); 27394 } 27395 27396 const tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation'; 27397 27398 const button = document.createElement('button'); 27399 button.className = className + '-reset'; 27400 button.setAttribute('type', 'button'); 27401 button.title = tipLabel; 27402 button.appendChild(this.label_); 27403 27404 button.addEventListener( 27405 EventType.CLICK, 27406 this.handleClick_.bind(this), 27407 false 27408 ); 27409 27410 const cssClasses = 27411 className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; 27412 const element = this.element; 27413 element.className = cssClasses; 27414 element.appendChild(button); 27415 27416 this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined; 27417 27418 /** 27419 * @type {number} 27420 * @private 27421 */ 27422 this.duration_ = options.duration !== undefined ? options.duration : 250; 27423 27424 /** 27425 * @type {boolean} 27426 * @private 27427 */ 27428 this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true; 27429 27430 /** 27431 * @private 27432 * @type {number|undefined} 27433 */ 27434 this.rotation_ = undefined; 27435 27436 if (this.autoHide_) { 27437 this.element.classList.add(CLASS_HIDDEN); 27438 } 27439 } 27440 27441 /** 27442 * @param {MouseEvent} event The event to handle 27443 * @private 27444 */ 27445 handleClick_(event) { 27446 event.preventDefault(); 27447 if (this.callResetNorth_ !== undefined) { 27448 this.callResetNorth_(); 27449 } else { 27450 this.resetNorth_(); 27451 } 27452 } 27453 27454 /** 27455 * @private 27456 */ 27457 resetNorth_() { 27458 const map = this.getMap(); 27459 const view = map.getView(); 27460 if (!view) { 27461 // the map does not have a view, so we can't act 27462 // upon it 27463 return; 27464 } 27465 const rotation = view.getRotation(); 27466 if (rotation !== undefined) { 27467 if (this.duration_ > 0 && rotation % (2 * Math.PI) !== 0) { 27468 view.animate({ 27469 rotation: 0, 27470 duration: this.duration_, 27471 easing: easeOut, 27472 }); 27473 } else { 27474 view.setRotation(0); 27475 } 27476 } 27477 } 27478 27479 /** 27480 * Update the rotate control element. 27481 * @param {import("../MapEvent.js").default} mapEvent Map event. 27482 * @override 27483 */ 27484 render(mapEvent) { 27485 const frameState = mapEvent.frameState; 27486 if (!frameState) { 27487 return; 27488 } 27489 const rotation = frameState.viewState.rotation; 27490 if (rotation != this.rotation_) { 27491 const transform = 'rotate(' + rotation + 'rad)'; 27492 if (this.autoHide_) { 27493 const contains = this.element.classList.contains(CLASS_HIDDEN); 27494 if (!contains && rotation === 0) { 27495 this.element.classList.add(CLASS_HIDDEN); 27496 } else if (contains && rotation !== 0) { 27497 this.element.classList.remove(CLASS_HIDDEN); 27498 } 27499 } 27500 this.label_.style.transform = transform; 27501 } 27502 this.rotation_ = rotation; 27503 } 27504} 27505 27506/* harmony default export */ const control_Rotate = (Rotate); 27507 27508;// CONCATENATED MODULE: ./node_modules/ol/control/Zoom.js 27509/** 27510 * @module ol/control/Zoom 27511 */ 27512 27513 27514 27515 27516 27517/** 27518 * @typedef {Object} Options 27519 * @property {number} [duration=250] Animation duration in milliseconds. 27520 * @property {string} [className='ol-zoom'] CSS class name. 27521 * @property {string} [zoomInClassName=className + '-in'] CSS class name for the zoom
27521-in button. 27522 * @property {string} [zoomOutClassName=className + '-out'] CSS class name for the zoom-out button. 27523 * @property {string|HTMLElement} [zoomInLabel='+'] Text label to use for the zoom-in 27524 * button. Instead of text, also an element (e.g. a `span` element) can be used. 27525 * @property {string|HTMLElement} [zoomOutLabel='â'] Text label to use for the zoom-out button. 27526 * Instead of text, also an element (e.g. a `span` element) can be used. 27527 * @property {string} [zoomInTipLabel='Zoom in'] Text label to use for the button tip. 27528 * @property {string} [zoomOutTipLabel='Zoom out'] Text label to use for the button tip. 27529 * @property {number} [delta=1] The zoom delta applied on each click. 27530 * @property {HTMLElement|string} [target] Specify a target if you want the control to be 27531 * rendered outside of the map's viewport. 27532 */ 27533 27534/** 27535 * @classdesc 27536 * A control with 2 buttons, one for zoom in and one for zoom out. 27537 * This control is one of the default controls of a map. To style this control 27538 * use css selectors `.ol-zoom-in` and `.ol-zoom-out`. 27539 * 27540 * @api 27541 */ 27542class Zoom extends control_Control { 27543 /** 27544 * @param {Options} [options] Zoom options. 27545 */ 27546 constructor(options) { 27547 options = options ? options : {}; 27548 27549 super({ 27550 element: document.createElement('div'), 27551 target: options.target, 27552 }); 27553 27554 const className = 27555 options.className !== undefined ? options.className : 'ol-zoom'; 27556 27557 const delta = options.delta !== undefined ? options.delta : 1; 27558 27559 const zoomInClassName = 27560 options.zoomInClassName !== undefined 27561 ? options.zoomInClassName 27562 : className + '-in'; 27563 27564 const zoomOutClassName = 27565 options.zoomOutClassName !== undefined 27566 ? options.zoomOutClassName 27567 : className + '-out'; 27568 27569 const zoomInLabel = 27570 options.zoomInLabel !== undefined ? options.zoomInLabel : '+'; 27571 const zoomOutLabel = 27572 options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2013'; 27573 27574 const zoomInTipLabel = 27575 options.zoomInTipLabel !== undefined ? options.zoomInTipLabel : 'Zoom in'; 27576 const zoomOutTipLabel = 27577 options.zoomOutTipLabel !== undefined 27578 ? options.zoomOutTipLabel 27579 : 'Zoom out'; 27580 27581 const inElement = document.createElement('button'); 27582 inElement.className = zoomInClassName; 27583 inElement.setAttribute('type', 'button'); 27584 inElement.title = zoomInTipLabel; 27585 inElement.appendChild( 27586 typeof zoomInLabel === 'string' 27587 ? document.createTextNode(zoomInLabel) 27588 : zoomInLabel 27589 ); 27590 27591 inElement.addEventListener( 27592 EventType.CLICK, 27593 this.handleClick_.bind(this, delta), 27594 false 27595 ); 27596 27597 const outElement = document.createElement('button'); 27598 outElement.className = zoomOutClassName; 27599 outElement.setAttribute('type', 'button'); 27600 outElement.title = zoomOutTipLabel; 27601 outElement.appendChild( 27602 typeof zoomOutLabel === 'string' 27603 ? document.createTextNode(zoomOutLabel) 27604 : zoomOutLabel 27605 ); 27606 27607 outElement.addEventListener( 27608 EventType.CLICK, 27609 this.handleClick_.bind(this, -delta), 27610 false 27611 ); 27612 27613 const cssClasses = 27614 className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL; 27615 const element = this.element; 27616 element.className = cssClasses; 27617 element.appendChild(inElement); 27618 element.appendChild(outElement); 27619 27620 /** 27621 * @type {number} 27622 * @private 27623 */ 27624 this.duration_ = options.duration !== undefined ? options.duration : 250; 27625 } 27626 27627 /** 27628 * @param {number} delta Zoom delta. 27629 * @param {MouseEvent} event The event to handle 27630 * @private 27631 */ 27632 handleClick_(delta, event) { 27633 event.preventDefault(); 27634 this.zoomByDelta_(delta); 27635 } 27636 27637 /** 27638 * @param {number} delta Zoom delta. 27639 * @private 27640 */ 27641 zoomByDelta_(delta) { 27642 const map = this.getMap(); 27643 const view = map.getView(); 27644 if (!view) { 27645 // the map does not have a view, so we can't act 27646 // upon it 27647 return; 27648 } 27649 const currentZoom = view.getZoom(); 27650 if (currentZoom !== undefined) {
27651 const newZoom = view.getConstrainedZoom(currentZoom + delta); 27652 if (this.duration_ > 0) { 27653 if (view.getAnimating()) { 27654 view.cancelAnimations(); 27655 } 27656 view.animate({ 27657 zoom: newZoom, 27658 duration: this.duration_, 27659 easing: easeOut, 27660 }); 27661 } else { 27662 view.setZoom(newZoom); 27663 } 27664 } 27665 } 27666} 27667 27668/* harmony default export */ const control_Zoom = (Zoom); 27669 27670;// CONCATENATED MODULE: ./node_modules/ol/control/defaults.js 27671/** 27672 * @module ol/control/defaults 27673 */ 27674 27675 27676 27677 27678 27679/** 27680 * @typedef {Object} DefaultsOptions 27681 * @property {boolean} [attribution=true] Include 27682 * {@link module:ol/control/Attribution~Attribution}. 27683 * @property {import("./Attribution.js").Options} [attributionOptions] 27684 * Options for {@link module:ol/control/Attribution~Attribution}. 27685 * @property {boolean} [rotate=true] Include 27686 * {@link module:ol/control/Rotate~Rotate}. 27687 * @property {import("./Rotate.js").Options} [rotateOptions] Options 27688 * for {@link module:ol/control/Rotate~Rotate}. 27689 * @property {boolean} [zoom] Include {@link module:ol/control/Zoom~Zoom}. 27690 * @property {import("./Zoom.js").Options} [zoomOptions] Options for 27691 * {@link module:ol/control/Zoom~Zoom}. 27692 */ 27693 27694/** 27695 * Set of controls included in maps by default. Unless configured otherwise, 27696 * this returns a collection containing an instance of each of the following 27697 * controls: 27698 * * {@link module:ol/control/Zoom~Zoom} 27699 * * {@link module:ol/control/Rotate~Rotate} 27700 * * {@link module:ol/control/Attribution~Attribution} 27701 * 27702 * @param {DefaultsOptions} [options] Options for the default controls. 27703 * @return {Collection<import("./Control.js").default>} A collection of controls 27704 * to be used with the {@link module:ol/Map~Map} constructor's `controls` option. 27705 * @api 27706 */ 27707function defaults(options) { 27708 options = options ? options : {}; 27709 27710 /** @type {Collection<import("./Control.js").default>} */ 27711 const controls = new ol_Collection(); 27712 27713 const zoomControl = options.zoom !== undefined ? options.zoom : true; 27714 if (zoomControl) { 27715 controls.push(new control_Zoom(options.zoomOptions)); 27716 } 27717 27718 const rotateControl = options.rotate !== undefined ? options.rotate : true; 27719 if (rotateControl) { 27720 controls.push(new control_Rotate(options.rotateOptions)); 27721 } 27722 27723 const attributionControl = 27724 options.attribution !== undefined ? options.attribution : true; 27725 if (attributionControl) { 27726 controls.push(new control_Attribution(options.attributionOptions)); 27727 } 27728 27729 return controls; 27730} 27731 27732;// CONCATENATED MODULE: ./node_modules/ol/interaction/Property.js 27733/** 27734 * @module ol/interaction/Property 27735 */ 27736 27737/** 27738 * @enum {string} 27739 */ 27740/* harmony default export */ const interaction_Property = ({ 27741 ACTIVE: 'active', 27742}); 27743 27744;// CONCATENATED MODULE: ./node_modules/ol/interaction/Interaction.js 27745/** 27746 * @module ol/interaction/Interaction 27747 */ 27748 27749 27750 27751 27752/*** 27753 * @template Return 27754 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 27755 * import("../Observable").OnSignature<import("../ObjectEventType").Types| 27756 * 'change:active', import("../Object").ObjectEvent, Return> & 27757 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types| 27758 * 'change:active', Return>} InteractionOnSignature 27759 */ 27760 27761/** 27762 * Object literal with config options for interactions. 27763 * @typedef {Object} InteractionOptions 27764 * @property {function(import("../MapBrowserEvent.js").default):boolean} handleEvent 27765 * Method called by the map to notify the interaction that a browser event was 27766 * dispatched to the map. If the function returns a falsy value, propagation of 27767 * the event to other interactions in the map's interactions chain will be 27768 * prevented (this includes functions with no explicit return). The interactions 27769 * are traversed in reverse order of the interactions collection of the map. 27770 */ 27771 27772/** 27773 * @classdesc 27774 * Abstract base class; normally only used for creating subclasses and not 27775 * instantiated in apps. 27776 * User actions that change the state of the map. Some are similar to controls, 27777 * but are not associated with a DOM element. 27778 * For example, {@link module:ol/interaction/KeyboardZoom~KeyboardZoom} is 27779 * functionally the same as {@link module:ol/control/Zoom~Zoom}, but triggered 27780 * by a keyboard event not a button element event. 27781 * Although interactions do not have a DOM element, some of them do render
27782 * vectors and so are visible on the screen. 27783 * @api 27784 */ 27785class Interaction extends ol_Object { 27786 /** 27787 * @param {InteractionOptions} [options] Options. 27788 */ 27789 constructor(options) { 27790 super(); 27791 27792 /*** 27793 * @type {InteractionOnSignature<import("../events").EventsKey>} 27794 */ 27795 this.on; 27796 27797 /*** 27798 * @type {InteractionOnSignature<import("../events").EventsKey>} 27799 */ 27800 this.once; 27801 27802 /*** 27803 * @type {InteractionOnSignature<void>} 27804 */ 27805 this.un; 27806 27807 if (options && options.handleEvent) { 27808 this.handleEvent = options.handleEvent; 27809 } 27810 27811 /** 27812 * @private 27813 * @type {import("../Map.js").default|null} 27814 */ 27815 this.map_ = null; 27816 27817 this.setActive(true); 27818 } 27819 27820 /** 27821 * Return whether the interaction is currently active. 27822 * @return {boolean} `true` if the interaction is active, `false` otherwise. 27823 * @observable 27824 * @api 27825 */ 27826 getActive() { 27827 return /** @type {boolean} */ (this.get(interaction_Property.ACTIVE)); 27828 } 27829 27830 /** 27831 * Get the map associated with this interaction. 27832 * @return {import("../Map.js").default|null} Map. 27833 * @api 27834 */ 27835 getMap() { 27836 return this.map_; 27837 } 27838 27839 /** 27840 * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event}. 27841 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 27842 * @return {boolean} `false` to stop event propagation. 27843 * @api 27844 */ 27845 handleEvent(mapBrowserEvent) { 27846 return true; 27847 } 27848 27849 /** 27850 * Activate or deactivate the interaction. 27851 * @param {boolean} active Active. 27852 * @observable 27853 * @api 27854 */ 27855 setActive(active) { 27856 this.set(interaction_Property.ACTIVE, active); 27857 } 27858 27859 /** 27860 * Remove the interaction from its current map and attach it to the new map. 27861 * Subclasses may set up event handlers to get notified about changes to 27862 * the map here. 27863 * @param {import("../Map.js").default|null} map Map. 27864 */ 27865 setMap(map) { 27866 this.map_ = map; 27867 } 27868} 27869 27870/** 27871 * @param {import("../View.js").default} view View. 27872 * @param {import("../coordinate.js").Coordinate} delta Delta. 27873 * @param {number} [duration] Duration. 27874 */ 27875function pan(view, delta, duration) { 27876 const currentCenter = view.getCenterInternal(); 27877 if (currentCenter) { 27878 const center = [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]; 27879 view.animateInternal({ 27880 duration: duration !== undefined ? duration : 250, 27881 easing: linear, 27882 center: view.getConstrainedCenter(center), 27883 }); 27884 } 27885} 27886 27887/** 27888 * @param {import("../View.js").default} view View. 27889 * @param {number} delta Delta from previous zoom level. 27890 * @param {import("../coordinate.js").Coordinate} [anchor] Anchor coordinate in the user projection. 27891 * @param {number} [duration] Duration. 27892 */ 27893function zoomByDelta(view, delta, anchor, duration) { 27894 const currentZoom = view.getZoom(); 27895 27896 if (currentZoom === undefined) { 27897 return; 27898 } 27899
27900 const newZoom = view.getConstrainedZoom(currentZoom + delta); 27901 const newResolution = view.getResolutionForZoom(newZoom); 27902 27903 if (view.getAnimating()) { 27904 view.cancelAnimations(); 27905 } 27906 view.animate({ 27907 resolution: newResolution, 27908 anchor: anchor, 27909 duration: duration !== undefined ? duration : 250, 27910 easing: easeOut, 27911 }); 27912} 27913 27914/* harmony default export */ const interaction_Interaction = (Interaction); 27915 27916;// CONCATENATED MODULE: ./node_modules/ol/interaction/DoubleClickZoom.js 27917/** 27918 * @module ol/interaction/DoubleClickZoom 27919 */ 27920 27921 27922 27923/** 27924 * @typedef {Object} Options 27925 * @property {number} [duration=250] Animation duration in milliseconds. 27926 * @property {number} [delta=1] The zoom delta applied on each double click. 27927 */ 27928 27929/** 27930 * @classdesc 27931 * Allows the user to zoom by double-clicking on the map. 27932 * @api 27933 */ 27934class DoubleClickZoom extends interaction_Interaction { 27935 /** 27936 * @param {Options} [options] Options. 27937 */ 27938 constructor(options) { 27939 super(); 27940 27941 options = options ? options : {}; 27942 27943 /** 27944 * @private 27945 * @type {number} 27946 */ 27947 this.delta_ = options.delta ? options.delta : 1; 27948 27949 /** 27950 * @private 27951 * @type {number} 27952 */ 27953 this.duration_ = options.duration !== undefined ? options.duration : 250; 27954 } 27955 27956 /** 27957 * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} (if it was a 27958 * doubleclick) and eventually zooms the map. 27959 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 27960 * @return {boolean} `false` to stop event propagation. 27961 */ 27962 handleEvent(mapBrowserEvent) { 27963 let stopEvent = false; 27964 if (mapBrowserEvent.type == ol_MapBrowserEventType.DBLCLICK) { 27965 const browserEvent = /** @type {MouseEvent} */ ( 27966 mapBrowserEvent.originalEvent 27967 ); 27968 const map = mapBrowserEvent.map; 27969 const anchor = mapBrowserEvent.coordinate; 27970 const delta = browserEvent.shiftKey ? -this.delta_ : this.delta_; 27971 const view = map.getView(); 27972 zoomByDelta(view, delta, anchor, this.duration_); 27973 browserEvent.preventDefault(); 27974 stopEvent = true; 27975 } 27976 return !stopEvent; 27977 } 27978} 27979 27980/* harmony default export */ const interaction_DoubleClickZoom = (DoubleClickZoom); 27981 27982;// CONCATENATED MODULE: ./node_modules/ol/interaction/Pointer.js 27983/** 27984 * @module ol/interaction/Pointer 27985 */ 27986 27987 27988 27989/** 27990 * @typedef {Object} Options 27991 * @property {function(import("../MapBrowserEvent.js").default):boolean} [handleDownEvent] 27992 * Function handling "down" events. If the function returns `true` then a drag 27993 * sequence is started. 27994 * @property {function(import("../MapBrowserEvent.js").default):void} [handleDragEvent] 27995 * Function handling "drag" events. This function is called on "move" events 27996 * during a drag sequence. 27997 * @property {function(import("../MapBrowserEvent.js").default):boolean} [handleEvent] 27998 * Method called by the map to notify the interaction that a browser event was 27999 * dispatched to the map. The function may return `false` to prevent the 28000 * propagation of the event to other interactions in the map's interactions 28001 * chain. 28002 * @property {function(import("../MapBrowserEvent.js").default):void} [handleMoveEvent] 28003 * Function handling "move" events. This function is called on "move" events. 28004 * This functions is also called during a drag sequence, so during a drag 28005 * sequence both the `handleDragEvent` function and this function are called. 28006 * If `handleDownEvent` is defined and it returns true this function will not 28007 * be called during a drag sequence. 28008 * @property {function(import("../MapBrowserEvent.js").default):boolean} [handleUpEvent] 28009 * Function handling "up" events. If the function returns `false` then the 28010 * current drag sequence is stopped. 28011 * @property {function(boolean):boolean} [stopDown] 28012 * Should the down event be propagated to other interactions, or should be 28013 * stopped? 28014 */ 28015 28016/** 28017 * @classdesc 28018 * Base class that calls user-defined functions on `down`, `move` and `up` 28019 * events. This class also manages "drag sequences". 28020 * 28021 * When the `handleDownEvent` user function returns `true` a drag sequence is 28022 * started. During a drag sequence the `handleDragEvent` user function is 28023 * called on `move` events. The drag sequence ends when the `handleUpEvent` 28024 * user function is called and returns `false`. 28025 * @api 28026 */ 28027class PointerInteraction extends interaction_Interaction { 28028 /** 28029 * @param {Options} [options] Options. 28030 */ 28031 constructor(options) { 28032 options = options ? options : {}; 28033 28034 super( 28035 /** @type {import("./Interaction.js").InteractionOptions} */ (options) 28036 ); 28037 28038 if (options.handleDownEvent) { 28039 this.handleDownEvent = options.handleDownEvent; 28040 } 28041 28042 if (options.handleDragEvent) { 28043 this.handleDragEvent = options.handleDragEvent; 28044 } 28045 28046 if (options.handleMoveEvent) { 28047 this.handleMoveEvent = options.handleMoveEvent; 28048 } 28049 28050 if (options.handleUpEvent) { 28051 this.handleUpEvent = options.handleUpEvent; 28052 } 28053 28054 if (options.stopDown) { 28055 this.stopDown = options.stopDown; 28056 } 28057 28058 /** 28059 * @type {boolean} 28060 * @protected 28061 */ 28062 this.handlingDownUpSequence = false;
28063 28064 /** 28065 * @type {Array<PointerEvent>} 28066 * @protected 28067 */ 28068 this.targetPointers = []; 28069 } 28070 28071 /** 28072 * Returns the current number of pointers involved in the interaction, 28073 * e.g. `2` when two fingers are used. 28074 * @return {number} The number of pointers. 28075 * @api 28076 */ 28077 getPointerCount() { 28078 return this.targetPointers.length; 28079 } 28080 28081 /** 28082 * Handle pointer down events. 28083 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28084 * @return {boolean} If the event was consumed. 28085 * @protected 28086 */ 28087 handleDownEvent(mapBrowserEvent) { 28088 return false; 28089 } 28090 28091 /** 28092 * Handle pointer drag events. 28093 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28094 * @protected 28095 */ 28096 handleDragEvent(mapBrowserEvent) {} 28097 28098 /** 28099 * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} and may call into 28100 * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are 28101 * detected. 28102 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28103 * @return {boolean} `false` to stop event propagation. 28104 * @api 28105 */ 28106 handleEvent(mapBrowserEvent) { 28107 if (!mapBrowserEvent.originalEvent) { 28108 return true; 28109 } 28110 28111 let stopEvent = false; 28112 this.updateTrackedPointers_(mapBrowserEvent); 28113 if (this.handlingDownUpSequence) { 28114 if (mapBrowserEvent.type == ol_MapBrowserEventType.POINTERDRAG) { 28115 this.handleDragEvent(mapBrowserEvent); 28116 // prevent page scrolling during dragging 28117 mapBrowserEvent.originalEvent.preventDefault(); 28118 } else if (mapBrowserEvent.type == ol_MapBrowserEventType.POINTERUP) { 28119 const handledUp = this.handleUpEvent(mapBrowserEvent); 28120 this.handlingDownUpSequence = 28121 handledUp && this.targetPointers.length > 0; 28122 } 28123 } else { 28124 if (mapBrowserEvent.type == ol_MapBrowserEventType.POINTERDOWN) { 28125 const handled = this.handleDownEvent(mapBrowserEvent); 28126 this.handlingDownUpSequence = handled; 28127 stopEvent = this.stopDown(handled); 28128 } else if (mapBrowserEvent.type == ol_MapBrowserEventType.POINTERMOVE) { 28129 this.handleMoveEvent(mapBrowserEvent); 28130 } 28131 } 28132 return !stopEvent; 28133 } 28134 28135 /** 28136 * Handle pointer move events. 28137 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28138 * @protected 28139 */ 28140 handleMoveEvent(mapBrowserEvent) {} 28141 28142 /** 28143 * Handle pointer up events. 28144 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28145 * @return {boolean} If the event was consumed. 28146 * @protected 28147 */ 28148 handleUpEvent(mapBrowserEvent) { 28149 return false; 28150 } 28151 28152 /** 28153 * This function is used to determine if "down" events should be propagated 28154 * to other interactions or should be stopped. 28155 * @param {boolean} handled Was the event handled by the interaction? 28156 * @return {boolean} Should the `down` event be stopped? 28157 */ 28158 stopDown(handled) { 28159 return handled; 28160 } 28161 28162 /** 28163 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28164 * @private 28165 */ 28166 updateTrackedPointers_(mapBrowserEvent) { 28167 if (mapBrowserEvent.activePointers) { 28168 this.targetPointers = mapBrowserEvent.activePointers; 28169 } 28170 } 28171} 28172 28173/** 28174 * @param {Array<PointerEvent>} pointerEvents List of events. 28175 * @return {import("../pixel.js").Pixel} Centroid pixel. 28176 */ 28177function Pointer_centroid(pointerEvents) { 28178 const length = pointerEvents.length; 28179 let clientX = 0; 28180 let clientY = 0; 28181 for (let i = 0; i < length; i++) { 28182 clientX += pointerEvents[i].clientX; 28183 clientY += pointerEvents[i].clientY; 28184 } 28185 return [clientX / length, clientY / length]; 28186} 28187 28188/* harmony default export */ const Pointer = (PointerInteraction); 28189 28190;// CONCATENATED MODULE: ./node_modules/ol/events/condition.js 28191/** 28192 * @module ol/events/condition 28193 */ 28194 28195 28196 28197 28198 28199/** 28200 * A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a 28201 * `{boolean}`. If the condition is met, true should be returned. 28202 * 28203 * @typedef {function(this: ?, import("../MapBrowserEvent.js").default): boolean} Condition 28204 */ 28205 28206/** 28207 * Creates a condition function that passes when all provided conditions pass. 28208 * @param {...Condition} var_args Conditions to check. 28209 * @return {Condition} Condition function. 28210 */ 28211function condition_all(var_args) { 28212 const conditions = arguments; 28213 /** 28214 * @param {import("../MapBrowserEvent.js").default} event Event. 28215 * @return {boolean} All conditions passed. 28216 */ 28217 return function (event) { 28218 let pass = true; 28219 for (let i = 0, ii = conditions.length; i < ii; ++i) { 28220 pass = pass && conditions[i](event); 28221 if (!pass) { 28222 break; 28223 } 28224 } 28225 return pass; 28226 }; 28227} 28228 28229/** 28230 * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when 28231 * additionally the shift-key is pressed). 28232 * 28233 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28234 * @return {boolean} True if only the alt key is pressed. 28235 * @api 28236 */
28237const altKeyOnly = function (mapBrowserEvent) { 28238 const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ ( 28239 mapBrowserEvent.originalEvent 28240 ); 28241 return ( 28242 originalEvent.altKey && 28243 !(originalEvent.metaKey || originalEvent.ctrlKey) && 28244 !originalEvent.shiftKey 28245 ); 28246}; 28247 28248/** 28249 * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise 28250 * (e.g. when additionally the platform-modifier-key is pressed). 28251 * 28252 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28253 * @return {boolean} True if only the alt and shift keys are pressed. 28254 * @api 28255 */ 28256const altShiftKeysOnly = function (mapBrowserEvent) { 28257 const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ ( 28258 mapBrowserEvent.originalEvent 28259 ); 28260 return ( 28261 originalEvent.altKey && 28262 !(originalEvent.metaKey || originalEvent.ctrlKey) && 28263 originalEvent.shiftKey 28264 ); 28265}; 28266 28267/** 28268 * Return `true` if the map has the focus. This condition requires a map target 28269 * element with a `tabindex` attribute, e.g. `<div id="map" tabindex="1">`. 28270 * 28271 * @param {import("../MapBrowserEvent.js").default} event Map browser event. 28272 * @return {boolean} The map has the focus. 28273 * @api 28274 */ 28275const condition_focus = function (event) { 28276 const targetElement = event.map.getTargetElement(); 28277 const activeElement = event.map.getOwnerDocument().activeElement; 28278 return targetElement.contains(activeElement); 28279}; 28280 28281/** 28282 * Return `true` if the map has the focus or no 'tabindex' attribute set. 28283 * 28284 * @param {import("../MapBrowserEvent.js").default} event Map browser event. 28285 * @return {boolean} The map container has the focus or no 'tabindex' attribute. 28286 */ 28287const focusWithTabindex = function (event) { 28288 return event.map.getTargetElement().hasAttribute('tabindex') 28289 ? condition_focus(event) 28290 : true; 28291}; 28292 28293/** 28294 * Return always true. 28295 * 28296 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28297 * @return {boolean} True. 28298 * @api 28299 */ 28300const always = TRUE; 28301 28302/** 28303 * Return `true` if the event is a `click` event, `false` otherwise. 28304 * 28305 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28306 * @return {boolean} True if the event is a map `click` event. 28307 * @api 28308 */ 28309const click = function (mapBrowserEvent) { 28310 return mapBrowserEvent.type == MapBrowserEventType.CLICK; 28311}; 28312 28313/** 28314 * Return `true` if the event has an "action"-producing mouse button. 28315 * 28316 * By definition, this includes left-click on windows/linux, and left-click 28317 * without the ctrl key on Macs. 28318 * 28319 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28320 * @return {boolean} The result. 28321 */ 28322const mouseActionButton = function (mapBrowserEvent) { 28323 const originalEvent = /** @type {MouseEvent} */ ( 28324 mapBrowserEvent.originalEvent 28325 ); 28326 return originalEvent.button == 0 && !(WEBKIT && has_MAC && originalEvent.ctrlKey); 28327}; 28328 28329/** 28330 * Return always false. 28331 * 28332 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28333 * @return {boolean} False. 28334 * @api 28335 */ 28336const never = (/* unused pure expression or super */ null && (FALSE)); 28337 28338/** 28339 * Return `true` if the browser event is a `pointermove` event, `false` 28340 * otherwise. 28341 * 28342 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28343 * @return {boolean} True if the browser event is a `pointermove` event. 28344 * @api 28345 */ 28346const pointerMove = function (mapBrowserEvent) { 28347 return mapBrowserEvent.type == 'pointermove'; 28348}; 28349 28350/** 28351 * Return `true` if the event is a map `singleclick` event, `false` otherwise. 28352 * 28353 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28354 * @return {boolean} True if the event is a map `singleclick` event. 28355 * @api 28356 */ 28357const singleClick = function (mapBrowserEvent) { 28358 return mapBrowserEvent.type == MapBrowserEventType.SINGLECLICK; 28359}; 28360 28361/** 28362 * Return `true` if the event is a map `dblclick` event, `false` otherwise. 28363 * 28364 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28365 * @return {boolean} True if the event is a map `dblclick` event. 28366 * @api 28367 */ 28368const doubleClick = function (mapBrowserEvent) { 28369 return mapBrowserEvent.type == MapBrowserEventType.DBLCLICK; 28370}; 28371 28372/** 28373 * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is 28374 * pressed. 28375 * 28376 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28377 * @return {boolean} True only if there no modifier keys are pressed. 28378 * @api 28379 */ 28380const noModifierKeys = function (mapBrowserEvent) { 28381 const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ ( 28382 mapBrowserEvent.originalEvent 28383 ); 28384 return (
28385 !originalEvent.altKey && 28386 !(originalEvent.metaKey || originalEvent.ctrlKey) && 28387 !originalEvent.shiftKey 28388 ); 28389}; 28390 28391/** 28392 * Return `true` if only the platform-modifier-key (the meta-key on Mac, 28393 * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally 28394 * the shift-key is pressed). 28395 * 28396 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28397 * @return {boolean} True if only the platform modifier key is pressed. 28398 * @api 28399 */ 28400const platformModifierKeyOnly = function (mapBrowserEvent) { 28401 const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ ( 28402 mapBrowserEvent.originalEvent 28403 ); 28404 return ( 28405 !originalEvent.altKey && 28406 (MAC ? originalEvent.metaKey : originalEvent.ctrlKey) && 28407 !originalEvent.shiftKey 28408 ); 28409}; 28410 28411/** 28412 * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when 28413 * additionally the alt-key is pressed). 28414 * 28415 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28416 * @return {boolean} True if only the shift key is pressed. 28417 * @api 28418 */
28419const shiftKeyOnly = function (mapBrowserEvent) { 28420 const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ ( 28421 mapBrowserEvent.originalEvent 28422 ); 28423 return ( 28424 !originalEvent.altKey && 28425 !(originalEvent.metaKey || originalEvent.ctrlKey) && 28426 originalEvent.shiftKey 28427 ); 28428}; 28429 28430/** 28431 * Return `true` if the target element is not editable, i.e. not an `input`, 28432 * `select`, or `textarea` element and no `contenteditable` attribute is 28433 * set or inherited, `false` otherwise. 28434 * 28435 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28436 * @return {boolean} True only if the target element is not editable. 28437 * @api 28438 */ 28439const targetNotEditable = function (mapBrowserEvent) { 28440 const originalEvent = /** @type {KeyboardEvent|MouseEvent|TouchEvent} */ ( 28441 mapBrowserEvent.originalEvent 28442 ); 28443 const tagName = /** @type {Element} */ (originalEvent.target).tagName; 28444 return ( 28445 tagName !== 'INPUT' && 28446 tagName !== 'SELECT' && 28447 tagName !== 'TEXTAREA' && 28448 // `isContentEditable` is only available on `HTMLElement`, but it may also be a 28449 // different type like `SVGElement`. 28450 // @ts-ignore 28451 !originalEvent.target.isContentEditable 28452 ); 28453}; 28454 28455/** 28456 * Return `true` if the event originates from a mouse device. 28457 * 28458 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28459 * @return {boolean} True if the event originates from a mouse device. 28460 * @api 28461 */ 28462const mouseOnly = function (mapBrowserEvent) { 28463 const pointerEvent = /** @type {import("../MapBrowserEvent").default} */ ( 28464 mapBrowserEvent 28465 ).originalEvent; 28466 asserts_assert(pointerEvent !== undefined, 56); // mapBrowserEvent must originate from a pointer event 28467 // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType 28468 return pointerEvent.pointerType == 'mouse'; 28469}; 28470 28471/** 28472 * Return `true` if the event originates from a touchable device. 28473 * 28474 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28475 * @return {boolean} True if the event originates from a touchable device. 28476 * @api 28477 */ 28478const touchOnly = function (mapBrowserEvent) { 28479 const pointerEvt = /** @type {import("../MapBrowserEvent").default} */ ( 28480 mapBrowserEvent 28481 ).originalEvent; 28482 assert(pointerEvt !== undefined, 56); // mapBrowserEvent must originate from a pointer event 28483 // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType 28484 return pointerEvt.pointerType === 'touch'; 28485}; 28486 28487/** 28488 * Return `true` if the event originates from a digital pen. 28489 * 28490 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28491 * @return {boolean} True if the event originates from a digital pen. 28492 * @api 28493 */ 28494const penOnly = function (mapBrowserEvent) { 28495 const pointerEvt = /** @type {import("../MapBrowserEvent").default} */ ( 28496 mapBrowserEvent 28497 ).originalEvent; 28498 assert(pointerEvt !== undefined, 56); // mapBrowserEvent must originate from a pointer event 28499 // see https://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType 28500 return pointerEvt.pointerType === 'pen'; 28501}; 28502 28503/** 28504 * Return `true` if the event originates from a primary pointer in 28505 * contact with the surface or if the left mouse button is pressed. 28506 * See https://www.w3.org/TR/pointerevents/#button-states. 28507 * 28508 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 28509 * @return {boolean} True if the event originates from a primary pointer. 28510 * @api 28511 */ 28512const primaryAction = function (mapBrowserEvent) { 28513 const pointerEvent = /** @type {import("../MapBrowserEvent").default} */ ( 28514 mapBrowserEvent 28515 ).originalEvent; 28516 asserts_assert(pointerEvent !== undefined, 56); // mapBrowserEvent must originate from a pointer event 28517 return pointerEvent.isPrimary && pointerEvent.button === 0; 28518}; 28519 28520;// CONCATENATED MODULE: ./node_modules/ol/interaction/DragPan.js 28521/** 28522 * @module ol/interaction/DragPan 28523 */ 28524 28525 28526 28527 28528 28529 28530/** 28531 * @typedef {Object} Options 28532 * @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean 28533 * to indicate whether that event should be handled. 28534 * Default is {@link module:ol/events/condition.noModifierKeys}
28534 and {@link module:ol/events/condition.primaryAction}. 28535 * @property {boolean} [onFocusOnly=false] When the map's target has a `tabindex` attribute set, 28536 * the interaction will only handle events when the map has the focus. 28537 * @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan. 28538 */ 28539 28540/** 28541 * @classdesc 28542 * Allows the user to pan the map by dragging the map. 28543 * @api 28544 */ 28545class DragPan extends Pointer { 28546 /** 28547 * @param {Options} [options] Options. 28548 */ 28549 constructor(options) { 28550 super({ 28551 stopDown: functions_FALSE, 28552 }); 28553 28554 options = options ? options : {}; 28555 28556 /** 28557 * @private 28558 * @type {import("../Kinetic.js").default|undefined} 28559 */ 28560 this.kinetic_ = options.kinetic; 28561 28562 /** 28563 * @type {import("../pixel.js").Pixel} 28564 */ 28565 this.lastCentroid = null; 28566 28567 /** 28568 * @type {number} 28569 */ 28570 this.lastPointersCount_; 28571 28572 /** 28573 * @type {boolean} 28574 */ 28575 this.panning_ = false; 28576 28577 const condition = options.condition 28578 ? options.condition 28579 : condition_all(noModifierKeys, primaryAction); 28580 28581 /** 28582 * @private 28583 * @type {import("../events/condition.js").Condition} 28584 */ 28585 this.condition_ = options.onFocusOnly 28586 ? condition_all(focusWithTabindex, condition) 28587 : condition; 28588 28589 /** 28590 * @private 28591 * @type {boolean} 28592 */ 28593 this.noKinetic_ = false; 28594 } 28595 28596 /** 28597 * Handle pointer drag events. 28598 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28599 */ 28600 handleDragEvent(mapBrowserEvent) { 28601 if (!this.panning_) { 28602 this.panning_ = true; 28603 this.getMap().getView().beginInteraction(); 28604 } 28605 const targetPointers = this.targetPointers; 28606 const centroid = Pointer_centroid(targetPointers); 28607 if (targetPointers.length == this.lastPointersCount_) { 28608 if (this.kinetic_) { 28609 this.kinetic_.update(centroid[0], centroid[1]); 28610 } 28611 if (this.lastCentroid) { 28612 const delta = [ 28613 this.lastCentroid[0] - centroid[0], 28614 centroid[1] - this.lastCentroid[1], 28615 ]; 28616 const map = mapBrowserEvent.map; 28617 const view = map.getView(); 28618 scale(delta, view.getResolution()); 28619 rotate(delta, view.getRotation()); 28620 view.adjustCenterInternal(delta); 28621 } 28622 } else if (this.kinetic_) { 28623 // reset so we don't overestimate the kinetic energy after 28624 // after one finger down, tiny drag, second finger down 28625 this.kinetic_.begin(); 28626 } 28627 this.lastCentroid = centroid; 28628 this.lastPointersCount_ = targetPointers.length; 28629 mapBrowserEvent.originalEvent.preventDefault(); 28630 } 28631 28632 /** 28633 * Handle pointer up events. 28634 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28635 * @return {boolean} If the event was consumed. 28636 */ 28637 handleUpEvent(mapBrowserEvent) { 28638 const map = mapBrowserEvent.map; 28639 const view = map.getView(); 28640 if (this.targetPointers.length === 0) { 28641 if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) { 28642 const distance = this.kinetic_.getDistance(); 28643 const angle = this.kinetic_.getAngle(); 28644 const center = view.getCenterInternal(); 28645 const centerpx = map.getPixelFromCoordinateInternal(center); 28646 const dest = map.getCoordinateFromPixelInternal([ 28647 centerpx[0] - distance * Math.cos(angle), 28648 centerpx[1] - distance * Math.sin(angle), 28649 ]); 28650 view.animateInternal({ 28651 center: view.getConstrainedCenter(dest), 28652 duration: 500, 28653 easing: easeOut, 28654 }); 28655 } 28656 if (this.panning_) { 28657 this.panning_ = false; 28658 view.endInteraction(); 28659 } 28660 return false; 28661 } else { 28662 if (this.kinetic_) { 28663 // reset so we don't overestimate the kinetic energy after 28664 // after one finger up, tiny drag, second finger up 28665 this.kinetic_.begin(); 28666 } 28667 this.lastCentroid = null; 28668 return true; 28669 } 28670 } 28671 28672 /** 28673 * Handle pointer down events. 28674 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28675 * @return {boolean} If the event was consumed. 28676 */ 28677 handleDownEvent(mapBrowserEvent) { 28678 if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) { 28679 const map = mapBrowserEvent.map; 28680 const view = map.getView(); 28681 this.lastCentroid = null; 28682 // stop any current animation 28683 if (view.getAnimating()) { 28684 view.cancelAnimations(); 28685 } 28686 if (this.kinetic_) { 28687 this.kinetic_.begin(); 28688 } 28689 // No kinetic as soon as more than one pointer on the screen is 28690 // detected. This is to prevent nasty pans after pinch. 28691 this.noKinetic_ = this.targetPointers.length > 1; 28692 return true; 28693 } else { 28694 return false;
28695 } 28696 } 28697} 28698 28699/* harmony default export */ const interaction_DragPan = (DragPan); 28700 28701;// CONCATENATED MODULE: ./node_modules/ol/interaction/DragRotate.js 28702/** 28703 * @module ol/interaction/DragRotate 28704 */ 28705 28706 28707 28708 28709 28710/** 28711 * @typedef {Object} Options 28712 * @property {import("../events/condition.js").Condition} [condition] A function that takes an 28713 * {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean 28714 * to indicate whether that event should be handled. 28715 * Default is {@link module:ol/events/condition.altShiftKeysOnly}. 28716 * @property {number} [duration=250] Animation duration in milliseconds. 28717 */ 28718 28719/** 28720 * @classdesc 28721 * Allows the user to rotate the map by clicking and dragging on the map, 28722 * normally combined with an {@link module:ol/events/condition} that limits 28723 * it to when the alt and shift keys are held down. 28724 * 28725 * This interaction is only supported for mouse devices. 28726 * @api 28727 */ 28728class DragRotate extends Pointer { 28729 /** 28730 * @param {Options} [options] Options. 28731 */ 28732 constructor(options) { 28733 options = options ? options : {}; 28734 28735 super({ 28736 stopDown: functions_FALSE, 28737 }); 28738 28739 /** 28740 * @private 28741 * @type {import("../events/condition.js").Condition} 28742 */ 28743 this.condition_ = options.condition ? options.condition : altShiftKeysOnly; 28744 28745 /** 28746 * @private 28747 * @type {number|undefined} 28748 */ 28749 this.lastAngle_ = undefined; 28750 28751 /** 28752 * @private 28753 * @type {number} 28754 */ 28755 this.duration_ = options.duration !== undefined ? options.duration : 250; 28756 } 28757 28758 /** 28759 * Handle pointer drag events. 28760 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28761 */ 28762 handleDragEvent(mapBrowserEvent) { 28763 if (!mouseOnly(mapBrowserEvent)) { 28764 return; 28765 } 28766 28767 const map = mapBrowserEvent.map; 28768 const view = map.getView(); 28769 if (view.getConstraints().rotation === disable) { 28770 return; 28771 } 28772 const size = map.getSize(); 28773 const offset = mapBrowserEvent.pixel; 28774 const theta = Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2); 28775 if (this.lastAngle_ !== undefined) { 28776 const delta = theta - this.lastAngle_; 28777 view.adjustRotationInternal(-delta); 28778 } 28779 this.lastAngle_ = theta; 28780 } 28781 28782 /** 28783 * Handle pointer up events. 28784 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28785 * @return {boolean} If the event was consumed. 28786 */ 28787 handleUpEvent(mapBrowserEvent) { 28788 if (!mouseOnly(mapBrowserEvent)) { 28789 return true; 28790 } 28791 28792 const map = mapBrowserEvent.map; 28793 const view = map.getView(); 28794 view.endInteraction(this.duration_); 28795 return false; 28796 } 28797 28798 /** 28799 * Handle pointer down events. 28800 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 28801 * @return {boolean} If the event was consumed. 28802 */ 28803 handleDownEvent(mapBrowserEvent) { 28804 if (!mouseOnly(mapBrowserEvent)) { 28805 return false; 28806 } 28807 28808 if ( 28809 mouseActionButton(mapBrowserEvent) && 28810 this.condition_(mapBrowserEvent) 28811 ) { 28812 const map = mapBrowserEvent.map; 28813 map.getView().beginInteraction(); 28814 this.lastAngle_ = undefined; 28815 return true; 28816 } else { 28817 return false; 28818 } 28819 } 28820} 28821 28822/* harmony default export */ const interaction_DragRotate = (DragRotate); 28823 28824;// CONCATENATED MODULE: ./node_modules/ol/render/Box.js 28825/** 28826 * @module ol/render/Box 28827 */ 28828 28829 28830 28831 28832class RenderBox extends ol_Disposable { 28833 /** 28834 * @param {string} className CSS class name. 28835 */ 28836 constructor(className) { 28837 super(); 28838 28839 /** 28840 * @type {import("../geom/Polygon.js").default} 28841 * @private 28842 */ 28843 this.geometry_ = null; 28844 28845 /** 28846 * @type {HTMLDivElement} 28847 * @private 28848 */ 28849 this.element_ = document.createElement('div'); 28850 this.element_.style.position = 'absolute'; 28851 this.element_.style.pointerEvents = 'auto'; 28852 this.element_.className = 'ol-box ' + className; 28853 28854 /** 28855 * @private 28856 * @type {import("../Map.js").default|null} 28857 */ 28858 this.map_ = null; 28859 28860 /** 28861 * @private 28862 * @type {import("../pixel.js").Pixel} 28863 */ 28864 this.startPixel_ = null; 28865 28866 /** 28867 * @private 28868 * @type {import("../pixel.js").Pixel} 28869 */ 28870 this.endPixel_ = null; 28871 } 28872 28873 /** 28874 * Clean up. 28875 */ 28876 disposeInternal() { 28877 this.setMap(null); 28878 } 28879 28880 /** 28881 * @private 28882 */ 28883 render_() { 28884 const startPixel = this.startPixel_; 28885 const endPixel = this.endPixel_; 28886 const px = 'px'; 28887 const style = this.element_.style; 28888 style.left = Math.min(startPixel[0], endPixel[0]) + px; 28889 style.top = Math.min(startPixel[1], endPixel[1]) + px; 28890 style.width = Math.abs(endPixel[0] - startPixel[0]) + px; 28891 style.height = Math.abs(endPixel[1] - startPixel[1]) + px; 28892 } 28893 28894 /** 28895 * @param {import("../Map.js").default|null} map Map. 28896 */
28897 setMap(map) { 28898 if (this.map_) { 28899 this.map_.getOverlayContainer().removeChild(this.element_); 28900 const style = this.element_.style; 28901 style.left = 'inherit'; 28902 style.top = 'inherit'; 28903 style.width = 'inherit'; 28904 style.height = 'inherit'; 28905 } 28906 this.map_ = map; 28907 if (this.map_) { 28908 this.map_.getOverlayContainer().appendChild(this.element_); 28909 } 28910 } 28911 28912 /** 28913 * @param {import("../pixel.js").Pixel} startPixel Start pixel. 28914 * @param {import("../pixel.js").Pixel} endPixel End pixel. 28915 */ 28916 setPixels(startPixel, endPixel) { 28917 this.startPixel_ = startPixel; 28918 this.endPixel_ = endPixel; 28919 this.createOrUpdateGeometry(); 28920 this.render_(); 28921 } 28922 28923 /** 28924 * Creates or updates the cached geometry. 28925 */ 28926 createOrUpdateGeometry() { 28927 const startPixel = this.startPixel_; 28928 const endPixel = this.endPixel_; 28929 const pixels = [ 28930 startPixel, 28931 [startPixel[0], endPixel[1]], 28932 endPixel, 28933 [endPixel[0], startPixel[1]], 28934 ]; 28935 const coordinates = pixels.map( 28936 this.map_.getCoordinateFromPixelInternal, 28937 this.map_ 28938 ); 28939 // close the polygon 28940 coordinates[4] = coordinates[0].slice(); 28941 if (!this.geometry_) { 28942 this.geometry_ = new geom_Polygon([coordinates]); 28943 } else { 28944 this.geometry_.setCoordinates([coordinates]); 28945 } 28946 } 28947 28948 /** 28949 * @return {import("../geom/Polygon.js").default} Geometry. 28950 */ 28951 getGeometry() { 28952 return this.geometry_; 28953 } 28954} 28955 28956/* harmony default export */ const Box = (RenderBox); 28957 28958;// CONCATENATED MODULE: ./node_modules/ol/interaction/DragBox.js 28959/** 28960 * @module ol/interaction/DragBox 28961 */ 28962// FIXME draw drag box 28963 28964 28965 28966 28967 28968/** 28969 * A function that takes a {@link module:ol/MapBrowserEvent~MapBrowserEvent} and two 28970 * {@link module:ol/pixel~Pixel}s and returns a `{boolean}`. If the condition is met, 28971 * true should be returned. 28972 * @typedef {function(this: ?, import("../MapBrowserEvent.js").default, import("../pixel.js").Pixel, import("../pixel.js").Pixel):boolean} EndCondition 28973 */ 28974 28975/** 28976 * @typedef {Object} Options 28977 * @property {string} [className='ol-dragbox'] CSS class name for styling the box. 28978 * @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean 28979 * to indicate whether that event should be handled. 28980 * Default is {@link ol/events/condition~mouseActionButton}. 28981 * @property {number} [minArea=64] The minimum area of the box in pixel, this value is used by the default 28982 * `boxEndCondition` function. 28983 * @property {EndCondition} [boxEndCondition] A function that takes a {@link module:ol/MapBrowserEvent~MapBrowserEvent} and two 28984 * {@link module:ol/pixel~Pixel}s to indicate whether a `boxend` event should be fired. 28985 * Default is `true` if the area of the box is bigger than the `minArea` option. 28986 * @property {function(this:DragBox, import("../MapBrowserEvent.js").default):void} [onBoxEnd] Code to execute just 28987 * before `boxend` is fired. 28988 */ 28989 28990/** 28991 * @enum {string} 28992 */ 28993const DragBoxEventType = { 28994 /** 28995 * Triggered upon drag box start. 28996 * @event DragBoxEvent#boxstart 28997 * @api 28998 */ 28999 BOXSTART: 'boxstart', 29000 29001 /** 29002 * Triggered on drag when box is active. 29003 * @event DragBoxEvent#boxdrag 29004 * @api 29005 */ 29006 BOXDRAG: 'boxdrag', 29007 29008 /** 29009 * Triggered upon drag box end. 29010 * @event DragBoxEvent#boxend 29011 * @api 29012 */ 29013 BOXEND: 'boxend', 29014 29015 /** 29016 * Triggered upon drag box canceled. 29017 * @event DragBoxEvent#boxcancel 29018 * @api 29019 */ 29020 BOXCANCEL: 'boxcancel', 29021}; 29022 29023/** 29024 * @classdesc 29025 * Events emitted by {@link module:ol/interaction/DragBox~DragBox} instances are instances of 29026 * this type. 29027 */ 29028class DragBoxEvent extends Event { 29029 /** 29030 * @param {string} type The event type. 29031 * @param {import("../coordinate.js").Coordinate} coordinate The event coordinate. 29032 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Originating event. 29033 */ 29034 constructor(type, coordinate, mapBrowserEvent) { 29035 super(type); 29036 29037 /** 29038 * The coordinate of the drag event. 29039 * @const 29040 * @type {import("../coordinate.js").Coordinate} 29041 * @api 29042 */ 29043 this.coordinate = coordinate; 29044 29045 /** 29046 * @const 29047 * @type {import("../MapBrowserEvent.js").default} 29048 * @api 29049 */ 29050 this.mapBrowserEvent = mapBrowserEvent; 29051 } 29052} 29053 29054/*** 29055 * @template Return 29056 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 29057 * import("../Observable").OnSignature<import("../ObjectEventType").Types| 29058 * 'change:active', import("../Object").ObjectEvent, Return> & 29059 * import("../Observable").OnSignature<'boxcancel'|'boxdrag'|'boxend'|'boxstart', DragBoxEvent, Return> & 29060 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types| 29061 * 'change:active'|'boxcancel'|'boxdrag'|'boxend', Return>} DragBoxOnSignature 29062 */ 29063 29064/** 29065 * @classdesc 29066 * Allows the user to draw a vector box by clicking and dragging on the map, 29067 * normally combined with an {@link module:ol/events/condition} that limits 29068 * it to when the shift or other key is held down. This is used, for example, 29069 * for zooming to a specific area of the map 29070 * (see {@link module:ol/interaction/DragZoom~DragZoom} and 29071 * {@link module:ol/interaction/DragRotateAndZoom~DragRotateAndZoom}). 29072 * 29073 * @fires DragBoxEvent 29074 * @api 29075 */ 29076class DragBox extends Pointer { 29077 /** 29078 * @param {Options} [options] Options. 29079 */ 29080 constructor(options) { 29081 super(); 29082 29083 /*** 29084 * @type {DragBoxOnSignature<import("../events").EventsKey>} 29085 */ 29086 this.on; 29087 29088 /*** 29089 * @type {DragBoxOnSignature<import("../events").EventsKey>} 29090 */ 29091 this.once; 29092 29093 /*** 29094 * @type {DragBoxOnSignature<void>} 29095 */ 29096 this.un; 29097 29098 options = options ? options : {}; 29099 29100 /** 29101 * @type {import("../render/Box.js").default} 29102 * @private 29103 */ 29104 this.box_ = new Box(options.className || 'ol-dragbox'); 29105 29106 /** 29107 * @type {number} 29108 * @private 29109 */ 29110 this.minArea_ = options.minArea !== undefined ? options.minArea : 64; 29111 29112 if (options.onBoxEnd) { 29113 this.onBoxEnd = options.onBoxEnd; 29114 } 29115 29116 /** 29117 * @type {import("../pixel.js").Pixel} 29118 * @private 29119 */ 29120 this.startPixel_ = null; 29121 29122 /** 29123 * @private 29124 * @type {import("../events/condition.js").Condition} 29125 */ 29126 this.condition_ = options.condition ? options.condition : mouseActionButton; 29127 29128 /** 29129 * @private 29130 * @type {EndCondition} 29131 */ 29132 this.boxEndCondition_ = options.boxEndCondition 29133 ? options.boxEndCondition 29134 : this.defaultBoxEndCondition; 29135 } 29136 29137 /** 29138 * The default condition for determining whether the boxend event 29139 * should fire. 29140 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent The originating MapBrowserEvent 29141 * leading to the box end. 29142 * @param {import("../pixel.js").Pixel} startPixel The starting pixel of the box. 29143 * @param {import("../pixel.js").Pixel} endPixel The end pixel of the box. 29144 * @return {boolean} Whether or not the boxend condition should be fired. 29145 */ 29146 defaultBoxEndCondition(mapBrowserEvent, startPixel, endPixel) { 29147 const width = endPixel[0] - startPixel[0]; 29148 const height = endPixel[1] - startPixel[1]; 29149 return width * width + height * height >= this.minArea_; 29150 } 29151 29152 /** 29153 * Returns geometry of last drawn box. 29154 * @return {import("../geom/Polygon.js").default} Geometry. 29155 * @api 29156 */ 29157 getGeometry() { 29158 return this.box_.getGeometry(); 29159 } 29160 29161 /** 29162 * Handle pointer drag events. 29163 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 29164 */ 29165 handleDragEvent(mapBrowserEvent) { 29166 this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel); 29167 29168 this.dispatchEvent( 29169 new DragBoxEvent( 29170 DragBoxEventType.BOXDRAG, 29171 mapBrowserEvent.coordinate, 29172 mapBrowserEvent 29173 ) 29174 ); 29175 } 29176 29177 /** 29178 * Handle pointer up events. 29179 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 29180 * @return {boolean} If the event was consumed. 29181 */ 29182 handleUpEvent(mapBrowserEvent) { 29183 this.box_.setMap(null); 29184 29185 const completeBox = this.boxEndCondition_( 29186 mapBrowserEvent, 29187 this.startPixel_, 29188 mapBrowserEvent.pixel 29189 ); 29190 if (completeBox) { 29191 this.onBoxEnd(mapBrowserEvent); 29192 } 29193 this.dispatchEvent( 29194 new DragBoxEvent( 29195 completeBox ? DragBoxEventType.BOXEND : DragBoxEventType.BOXCANCEL, 29196 mapBrowserEvent.coordinate, 29197 mapBrowserEvent 29198 ) 29199 ); 29200 return false;
29201 } 29202 29203 /** 29204 * Handle pointer down events. 29205 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 29206 * @return {boolean} If the event was consumed. 29207 */ 29208 handleDownEvent(mapBrowserEvent) { 29209 if (this.condition_(mapBrowserEvent)) { 29210 this.startPixel_ = mapBrowserEvent.pixel; 29211 this.box_.setMap(mapBrowserEvent.map); 29212 this.box_.setPixels(this.startPixel_, this.startPixel_); 29213 this.dispatchEvent( 29214 new DragBoxEvent( 29215 DragBoxEventType.BOXSTART, 29216 mapBrowserEvent.coordinate, 29217 mapBrowserEvent 29218 ) 29219 ); 29220 return true; 29221 } else { 29222 return false; 29223 } 29224 } 29225 29226 /** 29227 * Function to execute just before `onboxend` is fired 29228 * @param {import("../MapBrowserEvent.js").default} event Event. 29229 */ 29230 onBoxEnd(event) {} 29231} 29232 29233/* harmony default export */ const interaction_DragBox = (DragBox); 29234 29235;// CONCATENATED MODULE: ./node_modules/ol/interaction/DragZoom.js 29236/** 29237 * @module ol/interaction/DragZoom 29238 */ 29239 29240 29241 29242 29243/** 29244 * @typedef {Object} Options 29245 * @property {string} [className='ol-dragzoom'] CSS class name for styling the 29246 * box. 29247 * @property {import("../events/condition.js").Condition} [condition] A function that 29248 * takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a 29249 * boolean to indicate whether that event should be handled. 29250 * Default is {@link module:ol/events/condition.shiftKeyOnly}. 29251 * @property {number} [duration=200] Animation duration in milliseconds. 29252 * @property {boolean} [out=false] Use interaction for zooming out. 29253 * @property {number} [minArea=64] The minimum area of the box in pixel, this value is used by the parent default 29254 * `boxEndCondition` function. 29255 */ 29256 29257/** 29258 * @classdesc 29259 * Allows the user to zoom the map by clicking and dragging on the map, 29260 * normally combined with an {@link module:ol/events/condition} that limits 29261 * it to when a key, shift by default, is held down. 29262 * 29263 * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or 29264 * your custom one configured with `className`. 29265 * @api 29266 */ 29267class DragZoom extends interaction_DragBox { 29268 /** 29269 * @param {Options} [options] Options. 29270 */ 29271 constructor(options) { 29272 options = options ? options : {}; 29273 29274 const condition = options.condition ? options.condition : shiftKeyOnly; 29275 29276 super({ 29277 condition: condition, 29278 className: options.className || 'ol-dragzoom', 29279 minArea: options.minArea, 29280 }); 29281 29282 /** 29283 * @private 29284 * @type {number} 29285 */ 29286 this.duration_ = options.duration !== undefined ? options.duration : 200; 29287 29288 /** 29289 * @private 29290 * @type {boolean} 29291 */ 29292 this.out_ = options.out !== undefined ? options.out : false; 29293 } 29294 29295 /** 29296 * Function to execute just before `onboxend` is fired 29297 * @param {import("../MapBrowserEvent.js").default} event Event. 29298 */ 29299 onBoxEnd(event) { 29300 const map = this.getMap();
29301 const view = /** @type {!import("../View.js").default} */ (map.getView()); 29302 let geometry = this.getGeometry(); 29303 29304 if (this.out_) { 29305 const rotatedExtent = view.rotatedExtentForGeometry(geometry); 29306 const resolution = view.getResolutionForExtentInternal(rotatedExtent); 29307 const factor = view.getResolution() / resolution; 29308 geometry = geometry.clone(); 29309 geometry.scale(factor * factor); 29310 } 29311 29312 view.fitInternal(geometry, { 29313 duration: this.duration_, 29314 easing: easeOut, 29315 }); 29316 } 29317} 29318 29319/* harmony default export */ const interaction_DragZoom = (DragZoom); 29320 29321;// CONCATENATED MODULE: ./node_modules/ol/events/KeyCode.js 29322/** 29323 * @module ol/events/KeyCode 29324 */ 29325 29326/** 29327 * @enum {number} 29328 * @const 29329 */ 29330/* harmony default export */ const KeyCode = ({ 29331 LEFT: 37, 29332 UP: 38, 29333 RIGHT: 39, 29334 DOWN: 40, 29335}); 29336 29337;// CONCATENATED MODULE: ./node_modules/ol/interaction/KeyboardPan.js 29338/** 29339 * @module ol/interaction/KeyboardPan 29340 */ 29341 29342 29343 29344 29345 29346 29347/** 29348 * @typedef {Object} Options 29349 * @property {import("../events/condition.js").Condition} [condition] A function that 29350 * takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a 29351 * boolean to indicate whether that event should be handled. Default is 29352 * {@link module:ol/events/condition.noModifierKeys} and 29353 * {@link module:ol/events/condition.targetNotEditable}. 29354 * @property {number} [duration=100] Animation duration in milliseconds. 29355 * @property {number} [pixelDelta=128] The amount of pixels to pan on each key 29356 * press. 29357 */ 29358 29359/** 29360 * @classdesc 29361 * Allows the user to pan the map using keyboard arrows. 29362 * Note that, although this interaction is by default included in maps, 29363 * the keys can only be used when browser focus is on the element to which 29364 * the keyboard events are attached. By default, this is the map div, 29365 * though you can change this with the `keyboardEventTarget` in 29366 * {@link module:ol/Map~Map}. `document` never loses focus but, for any other 29367 * element, focus will have to be on, and returned to, this element if the keys 29368 * are to function. 29369 * See also {@link module:ol/interaction/KeyboardZoom~KeyboardZoom}. 29370 * @api 29371 */ 29372class KeyboardPan extends interaction_Interaction { 29373 /** 29374 * @param {Options} [options] Options. 29375 */ 29376 constructor(options) { 29377 super(); 29378 29379 options = options || {}; 29380 29381 /** 29382 * @private 29383 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Browser event. 29384 * @return {boolean} Combined condition result. 29385 */ 29386 this.defaultCondition_ = function (mapBrowserEvent) { 29387 return ( 29388 noModifierKeys(mapBrowserEvent) && targetNotEditable(mapBrowserEvent) 29389 ); 29390 }; 29391 29392 /** 29393 * @private 29394 * @type {import("../events/condition.js").Condition} 29395 */ 29396 this.condition_ = 29397 options.condition !== undefined 29398 ? options.condition 29399 : this.defaultCondition_; 29400 29401 /** 29402 * @private 29403 * @type {number} 29404 */ 29405 this.duration_ = options.duration !== undefined ? options.duration : 100; 29406 29407 /** 29408 * @private 29409 * @type {number} 29410 */ 29411 this.pixelDelta_ = 29412 options.pixelDelta !== undefined ? options.pixelDelta : 128; 29413 } 29414 29415 /** 29416 * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} if it was a 29417 * `KeyEvent`, and decides the direction to pan to (if an arrow key was 29418 * pressed). 29419 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 29420 * @return {boolean} `false` to stop event propagation. 29421 * @this {KeyboardPan} 29422 */ 29423 handleEvent(mapBrowserEvent) { 29424 let stopEvent = false; 29425 if (mapBrowserEvent.type == EventType.KEYDOWN) { 29426 const keyEvent = /** @type {KeyboardEvent} */ ( 29427 mapBrowserEvent.originalEvent 29428 ); 29429 const keyCode = keyEvent.keyCode; 29430 if ( 29431 this.condition_(mapBrowserEvent) && 29432 (keyCode == KeyCode.DOWN || 29433 keyCode == KeyCode.LEFT || 29434 keyCode == KeyCode.RIGHT || 29435 keyCode == KeyCode.UP) 29436 ) { 29437 const map = mapBrowserEvent.map; 29438 const view = map.getView(); 29439 const mapUnitsDelta = view.getResolution() * this.pixelDelta_; 29440 let deltaX = 0, 29441 deltaY = 0; 29442 if (keyCode == KeyCode.DOWN) { 29443 deltaY = -mapUnitsDelta; 29444 } else if (keyCode == KeyCode.LEFT) { 29445 deltaX = -mapUnitsDelta; 29446 } else if (keyCode == KeyCode.RIGHT) { 29447 deltaX = mapUnitsDelta; 29448 } else { 29449 deltaY = mapUnitsDelta; 29450 } 29451 const delta = [deltaX, deltaY]; 29452 rotate(delta, view.getRotation()); 29453 pan(view, delta, this.duration_); 29454 keyEvent.preventDefault(); 29455 stopEvent = true; 29456 } 29457 } 29458 return !stopEvent; 29459 } 29460} 29461 29462/* harmony default export */ const interaction_KeyboardPan = (KeyboardPan); 29463 29464;// CONCATENATED MODULE: ./node_modules/ol/interaction/KeyboardZoom.js 29465/** 29466 * @module ol/interaction/KeyboardZoom 29467 */ 29468 29469 29470 29471 29472/** 29473 * @typedef {Object} Options 29474 * @property {number} [duration=100] Animation duration in milliseconds. 29475 * @property {import("../events/condition.js").Condition} [condition] A function that 29476 * takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a 29477 * boolean to indicate whether that event should be handled. Default is 29478 * {@link module:ol/events/condition.targetNotEditable}. 29479 * @property {number} [delta=1] The zoom level delta on each key press. 29480 */ 29481 29482/** 29483 * @classdesc 29484 * Allows the user to zoom the map using keyboard + and -. 29485 * Note that, although this interaction is by default included in maps, 29486 * the keys can only be used when browser focus is on the element to which 29487 * the keyboard events are attached. By default, this is the map div, 29488 * though you can change this with the `keyboardEventTarget` in 29489 * {@link module:ol/Map~Map}. `document` never loses focus but, for any other 29490 * element, focus will have to be on, and returned to, this element if the keys 29491 * are to function. 29492 * See also {@link module:ol/interaction/KeyboardPan~KeyboardPan}. 29493 * @api 29494 */ 29495class KeyboardZoom extends interaction_Interaction { 29496 /** 29497 * @param {Options} [options] Options. 29498 */ 29499 constructor(options) { 29500 super(); 29501 29502 options = options ? options : {}; 29503 29504 /** 29505 * @private 29506 * @type {import("../events/condition.js").Condition} 29507 */ 29508 this.condition_ = options.condition ? options.condition : targetNotEditable; 29509 29510 /** 29511 * @private 29512 * @type {number} 29513 */ 29514 this.delta_ = options.delta ? options.delta : 1; 29515 29516 /** 29517 * @private 29518 * @type {number} 29519 */ 29520 this.duration_ = options.duration !== undefined ? options.duration : 100; 29521 } 29522 29523 /** 29524 * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} if it was a
29525 * `KeyEvent`, and decides whether to zoom in or out (depending on whether the 29526 * key pressed was '+' or '-'). 29527 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 29528 * @return {boolean} `false` to stop event propagation. 29529 * @this {KeyboardZoom} 29530 */ 29531 handleEvent(mapBrowserEvent) { 29532 let stopEvent = false; 29533 if ( 29534 mapBrowserEvent.type == EventType.KEYDOWN || 29535 mapBrowserEvent.type == EventType.KEYPRESS 29536 ) { 29537 const keyEvent = /** @type {KeyboardEvent} */ ( 29538 mapBrowserEvent.originalEvent 29539 ); 29540 const charCode = keyEvent.charCode; 29541 if ( 29542 this.condition_(mapBrowserEvent) && 29543 (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0)) 29544 ) { 29545 const map = mapBrowserEvent.map; 29546 const delta = 29547 charCode == '+'.charCodeAt(0) ? this.delta_ : -this.delta_; 29548 const view = map.getView(); 29549 zoomByDelta(view, delta, undefined, this.duration_); 29550 keyEvent.preventDefault(); 29551 stopEvent = true; 29552 } 29553 } 29554 return !stopEvent; 29555 } 29556} 29557 29558/* harmony default export */ const interaction_KeyboardZoom = (KeyboardZoom); 29559 29560;// CONCATENATED MODULE: ./node_modules/ol/Kinetic.js 29561/** 29562 * @module ol/Kinetic 29563 */ 29564 29565/** 29566 * @classdesc 29567 * Implementation of inertial deceleration for map movement. 29568 * 29569 * @api 29570 */ 29571class Kinetic { 29572 /** 29573 * @param {number} decay Rate of decay (must be negative). 29574 * @param {number} minVelocity Minimum velocity (pixels/millisecond). 29575 * @param {number} delay Delay to consider to calculate the kinetic 29576 * initial values (milliseconds). 29577 */ 29578 constructor(decay, minVelocity, delay) { 29579 /** 29580 * @private 29581 * @type {number} 29582 */ 29583 this.decay_ = decay; 29584 29585 /** 29586 * @private 29587 * @type {number} 29588 */ 29589 this.minVelocity_ = minVelocity; 29590 29591 /** 29592 * @private 29593 * @type {number} 29594 */ 29595 this.delay_ = delay; 29596 29597 /** 29598 * @private 29599 * @type {Array<number>} 29600 */ 29601 this.points_ = []; 29602 29603 /** 29604 * @private 29605 * @type {number} 29606 */ 29607 this.angle_ = 0; 29608 29609 /** 29610 * @private 29611 * @type {number} 29612 */ 29613 this.initialVelocity_ = 0; 29614 } 29615 29616 /** 29617 * FIXME empty description for jsdoc 29618 */ 29619 begin() { 29620 this.points_.length = 0; 29621 this.angle_ = 0; 29622 this.initialVelocity_ = 0; 29623 } 29624 29625 /** 29626 * @param {number} x X. 29627 * @param {number} y Y. 29628 */ 29629 update(x, y) { 29630 this.points_.push(x, y, Date.now()); 29631 } 29632 29633 /** 29634 * @return {boolean} Whether we should do kinetic animation. 29635 */ 29636 end() { 29637 if (this.points_.length < 6) { 29638 // at least 2 points are required (i.e. there must be at least 6 elements 29639 // in the array) 29640 return false; 29641 } 29642 const delay = Date.now() - this.delay_; 29643 const lastIndex = this.points_.length - 3; 29644 if (this.points_[lastIndex + 2] < delay) { 29645 // the last tracked point is too old, which means that the user stopped 29646 // panning before releasing the map 29647 return false; 29648 } 29649 29650 // get the first point which still falls into the delay time 29651 let firstIndex = lastIndex - 3; 29652 while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) { 29653 firstIndex -= 3; 29654 } 29655 29656 const duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2]; 29657 // we don't want a duration of 0 (divide by zero) 29658 // we also make sure the user panned for a duration of at least one frame 29659 // (1/60s) to compute sane displacement values 29660 if (duration < 1000 / 60) { 29661 return false; 29662 } 29663 29664 const dx = this.points_[lastIndex] - this.points_[firstIndex]; 29665 const dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1]; 29666 this.angle_ = Math.atan2(dy, dx); 29667 this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration; 29668 return this.initialVelocity_ > this.minVelocity_; 29669 } 29670 29671 /** 29672 * @return {number} Total distance travelled (pixels). 29673 */ 29674 getDistance() { 29675 return (this.minVelocity_ - this.initialVelocity_) / this.decay_; 29676 } 29677 29678 /** 29679 * @return {number} Angle of the kinetic panning animation (radians). 29680 */ 29681 getAngle() { 29682 return this.angle_; 29683 } 29684} 29685 29686/* harmony default export */ const ol_Kinetic = (Kinetic); 29687 29688;// CONCATENATED MODULE: ./node_modules/ol/interaction/MouseWheelZoom.js 29689/** 29690 * @module ol/interaction/MouseWheelZoom 29691 */ 29692 29693 29694 29695 29696 29697 29698/** 29699 * @typedef {'trackpad' | 'wheel'} Mode 29700 */ 29701 29702/** 29703 * @typedef {Object} Options 29704 * @property {import("../events/condition.js").Condition} [condition] A function that 29705 * takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a 29706 * boolean to indicate whether that event should be handled. Default is 29707 * {@link module:ol/events/condition.always}. 29708 * @property {boolean} [onFocusOnly=false] When the map's target has a `tabindex` attribute set, 29709 * the interaction will only handle events when the map has the focus. 29710 * @property {number} [maxDelta=1] Maximum mouse wheel delta. 29711 * @property {number} [duration=250] Animation duration in milliseconds. 29712 * @property {number} [timeout=80] Mouse wheel timeout duration in milliseconds. 29713 * @property {boolean} [useAnchor=true] Enable zooming using the mouse's
29714 * location as the anchor. When set to `false`, zooming in and out will zoom to 29715 * the center of the screen instead of zooming on the mouse's location. 29716 * @property {boolean} [constrainResolution=false] If true, the mouse wheel zoom 29717 * event will always animate to the closest zoom level after an interaction; 29718 * false means intermediary zoom levels are allowed. 29719 */ 29720 29721/** 29722 * @classdesc 29723 * Allows the user to zoom the map by scrolling the mouse wheel. 29724 * @api 29725 */ 29726class MouseWheelZoom extends interaction_Interaction { 29727 /** 29728 * @param {Options} [options] Options. 29729 */ 29730 constructor(options) { 29731 options = options ? options : {}; 29732 29733 super( 29734 /** @type {import("./Interaction.js").InteractionOptions} */ (options) 29735 ); 29736 29737 /** 29738 * @private 29739 * @type {number} 29740 */ 29741 this.totalDelta_ = 0; 29742 29743 /** 29744 * @private 29745 * @type {number} 29746 */ 29747 this.lastDelta_ = 0; 29748 29749 /** 29750 * @private 29751 * @type {number} 29752 */ 29753 this.maxDelta_ = options.maxDelta !== undefined ? options.maxDelta : 1; 29754 29755 /** 29756 * @private 29757 * @type {number} 29758 */ 29759 this.duration_ = options.duration !== undefined ? options.duration : 250; 29760 29761 /** 29762 * @private 29763 * @type {number} 29764 */ 29765 this.timeout_ = options.timeout !== undefined ? options.timeout : 80; 29766 29767 /** 29768 * @private 29769 * @type {boolean} 29770 */ 29771 this.useAnchor_ = 29772 options.useAnchor !== undefined ? options.useAnchor : true; 29773 29774 /** 29775 * @private 29776 * @type {boolean} 29777 */ 29778 this.constrainResolution_ = 29779 options.constrainResolution !== undefined 29780 ? options.constrainResolution 29781 : false; 29782 29783 const condition = options.condition ? options.condition : always; 29784 29785 /** 29786 * @private 29787 * @type {import("../events/condition.js").Condition} 29788 */ 29789 this.condition_ = options.onFocusOnly 29790 ? condition_all(focusWithTabindex, condition) 29791 : condition; 29792 29793 /** 29794 * @private 29795 * @type {?import("../coordinate.js").Coordinate} 29796 */ 29797 this.lastAnchor_ = null; 29798 29799 /** 29800 * @private 29801 * @type {number|undefined} 29802 */ 29803 this.startTime_ = undefined; 29804 29805 /** 29806 * @private 29807 * @type {?} 29808 */ 29809 this.timeoutId_; 29810 29811 /** 29812 * @private 29813 * @type {Mode|undefined} 29814 */ 29815 this.mode_ = undefined; 29816 29817 /** 29818 * Trackpad events separated by this delay will be considered separate 29819 * interactions. 29820 * @type {number} 29821 */ 29822 this.trackpadEventGap_ = 400; 29823 29824 /** 29825 * @type {?} 29826 */ 29827 this.trackpadTimeoutId_; 29828 29829 /** 29830 * The number of delta values per zoom level 29831 * @private 29832 * @type {number} 29833 */ 29834 this.deltaPerZoom_ = 300; 29835 } 29836 29837 /** 29838 * @private 29839 */ 29840 endInteraction_() { 29841 this.trackpadTimeoutId_ = undefined; 29842 const map = this.getMap(); 29843 if (!map) { 29844 return; 29845 } 29846 const view = map.getView(); 29847 view.endInteraction( 29848 undefined, 29849 this.lastDelta_ ? (this.lastDelta_ > 0 ? 1 : -1) : 0, 29850 this.lastAnchor_ 29851 ); 29852 } 29853 29854 /** 29855 * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} (if it was a mousewheel-event) and eventually 29856 * zooms the map. 29857 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. 29858 * @return {boolean} `false` to stop event propagation. 29859 */ 29860 handleEvent(mapBrowserEvent) { 29861 if (!this.condition_(mapBrowserEvent)) { 29862 return true; 29863 } 29864 const type = mapBrowserEvent.type; 29865 if (type !== EventType.WHEEL) { 29866 return true; 29867 } 29868 29869 const map = mapBrowserEvent.map; 29870 const wheelEvent = /** @type {WheelEvent} */ ( 29871 mapBrowserEvent.originalEvent 29872 ); 29873 wheelEvent.preventDefault(); 29874 29875 if (this.useAnchor_) { 29876 this.lastAnchor_ = mapBrowserEvent.coordinate; 29877 } 29878 29879 // Delta normalisation inspired by 29880 // https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js 29881 let delta; 29882 if (mapBrowserEvent.type == EventType.WHEEL) { 29883 delta = wheelEvent.deltaY; 29884 if (FIREFOX && wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) { 29885 delta /= DEVICE_PIXEL_RATIO; 29886 } 29887 if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) { 29888 delta *= 40; 29889 } 29890 } 29891 29892 if (delta === 0) { 29893 return false;
29894 } else { 29895 this.lastDelta_ = delta; 29896 } 29897 29898 const now = Date.now(); 29899 29900 if (this.startTime_ === undefined) { 29901 this.startTime_ = now; 29902 } 29903 29904 if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) { 29905 this.mode_ = Math.abs(delta) < 4 ? 'trackpad' : 'wheel'; 29906 } 29907 29908 const view = map.getView(); 29909 if ( 29910 this.mode_ === 'trackpad' && 29911 !(view.getConstrainResolution() || this.constrainResolution_) 29912 ) { 29913 if (this.trackpadTimeoutId_) { 29914 clearTimeout(this.trackpadTimeoutId_); 29915 } else { 29916 if (view.getAnimating()) { 29917 view.cancelAnimations(); 29918 } 29919 view.beginInteraction(); 29920 } 29921 this.trackpadTimeoutId_ = setTimeout( 29922 this.endInteraction_.bind(this), 29923 this.timeout_ 29924 ); 29925 view.adjustZoom(-delta / this.deltaPerZoom_, this.lastAnchor_); 29926 this.startTime_ = now; 29927 return false; 29928 } 29929 29930 this.totalDelta_ += delta; 29931 29932 const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0); 29933 29934 clearTimeout(this.timeoutId_); 29935 this.timeoutId_ = setTimeout( 29936 this.handleWheelZoom_.bind(this, map), 29937 timeLeft 29938 ); 29939 29940 return false; 29941 } 29942 29943 /** 29944 * @private 29945 * @param {import("../Map.js").default} map Map. 29946 */ 29947 handleWheelZoom_(map) { 29948 const view = map.getView(); 29949 if (view.getAnimating()) { 29950 view.cancelAnimations(); 29951 } 29952 let delta = 29953 -math_clamp( 29954 this.totalDelta_, 29955 -this.maxDelta_ * this.deltaPerZoom_, 29956 this.maxDelta_ * this.deltaPerZoom_ 29957 ) / this.deltaPerZoom_; 29958 if (view.getConstrainResolution() || this.constrainResolution_) { 29959 // view has a zoom constraint, zoom by 1 29960 delta = delta ? (delta > 0 ? 1 : -1) : 0; 29961 } 29962 zoomByDelta(view, delta, this.lastAnchor_, this.duration_); 29963 29964 this.mode_ = undefined; 29965 this.totalDelta_ = 0; 29966 this.lastAnchor_ = null; 29967 this.startTime_ = undefined; 29968 this.timeoutId_ = undefined; 29969 } 29970 29971 /** 29972 * Enable or disable using the mouse's location as an anchor when zooming 29973 * @param {boolean} useAnchor true to zoom to the mouse's location, false 29974 * to zoom to the center of the map 29975 * @api 29976 */ 29977 setMouseAnchor(useAnchor) { 29978 this.useAnchor_ = useAnchor; 29979 if (!useAnchor) { 29980 this.lastAnchor_ = null; 29981 } 29982 } 29983} 29984 29985/* harmony default export */ const interaction_MouseWheelZoom = (MouseWheelZoom); 29986 29987;// CONCATENATED MODULE: ./node_modules/ol/interaction/PinchRotate.js 29988/** 29989 * @module ol/interaction/PinchRotate 29990 */ 29991 29992 29993 29994 29995/** 29996 * @typedef {Object} Options 29997 * @property {number} [duration=250] The duration of the animation in 29998 * milliseconds. 29999 * @property {number} [threshold=0.3] Minimal angle in radians to start a rotation. 30000 */ 30001 30002/** 30003 * @classdesc 30004 * Allows the user to rotate the map by twisting with two fingers 30005 * on a touch screen. 30006 * @api 30007 */ 30008class PinchRotate extends Pointer { 30009 /** 30010 * @param {Options} [options] Options. 30011 */ 30012 constructor(options) { 30013 options = options ? options : {}; 30014 30015 const pointerOptions = /** @type {import("./Pointer.js").Options} */ ( 30016 options 30017 ); 30018 30019 if (!pointerOptions.stopDown) { 30020 pointerOptions.stopDown = functions_FALSE; 30021 } 30022 30023 super(pointerOptions); 30024 30025 /** 30026 * @private 30027 * @type {import("../coordinate.js").Coordinate} 30028 */ 30029 this.anchor_ = null; 30030 30031 /** 30032 * @private 30033 * @type {number|undefined} 30034 */ 30035 this.lastAngle_ = undefined; 30036 30037 /** 30038 * @private 30039 * @type {boolean} 30040 */ 30041 this.rotating_ = false; 30042 30043 /** 30044 * @private 30045 * @type {number} 30046 */ 30047 this.rotationDelta_ = 0.0; 30048 30049 /** 30050 * @private 30051 * @type {number} 30052 */ 30053 this.threshold_ = options.threshold !== undefined ? options.threshold : 0.3; 30054 30055 /** 30056 * @private 30057 * @type {number} 30058 */ 30059 this.duration_ = options.duration !== undefined ? options.duration : 250; 30060 } 30061 30062 /** 30063 * Handle pointer drag events. 30064 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 30065 */ 30066 handleDragEvent(mapBrowserEvent) { 30067 let rotationDelta = 0.0; 30068 30069 const touch0 = this.targetPointers[0]; 30070 const touch1 = this.targetPointers[1]; 30071 30072 // angle between touches 30073 const angle = Math.atan2( 30074 touch1.clientY - touch0.clientY, 30075 touch1.clientX - touch0.clientX 30076 ); 30077 30078 if (this.lastAngle_ !== undefined) { 30079 const delta = angle - this.lastAngle_; 30080 this.rotationDelta_ += delta; 30081 if (!this.rotating_ && Math.abs(this.rotationDelta_) > this.threshold_) { 30082 this.rotating_ = true; 30083 } 30084 rotationDelta = delta; 30085 } 30086 this.lastAngle_ = angle; 30087 30088 const map = mapBrowserEvent.map; 30089 const view = map.getView(); 30090 if (view.getConstraints().rotation === disable) { 30091 return; 30092 } 30093 30094 // rotate anchor point. 30095 // FIXME: should be the intersection point between the lines: 30096 // touch0,touch1 and previousTouch0,previousTouch1 30097 const viewportPosition = map.getViewport().getBoundingClientRect(); 30098 const centroid = Pointer_centroid(this.targetPointers); 30099 centroid[0] -= viewportPosition.left; 30100 centroid[1] -= viewportPosition.top; 30101 this.anchor_ = map.getCoordinateFromPixelInternal(centroid); 30102 30103 // rotate 30104 if (this.rotating_) { 30105 map.render(); 30106 view.adjustRotationInternal(rotationDelta, this.anchor_); 30107 } 30108 } 30109 30110 /** 30111 * Handle pointer up events. 30112 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 30113 * @return {boolean} If the event was consumed. 30114 */ 30115 handleUpEvent(mapBrowserEvent) { 30116 if (this.targetPointers.length < 2) { 30117 const map = mapBrowserEvent.map; 30118 const view = map.getView(); 30119 view.endInteraction(this.duration_); 30120 return false;
30121 } else { 30122 return true; 30123 } 30124 } 30125 30126 /** 30127 * Handle pointer down events. 30128 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 30129 * @return {boolean} If the event was consumed. 30130 */ 30131 handleDownEvent(mapBrowserEvent) { 30132 if (this.targetPointers.length >= 2) { 30133 const map = mapBrowserEvent.map; 30134 this.anchor_ = null; 30135 this.lastAngle_ = undefined; 30136 this.rotating_ = false; 30137 this.rotationDelta_ = 0.0; 30138 if (!this.handlingDownUpSequence) { 30139 map.getView().beginInteraction(); 30140 } 30141 return true; 30142 } else { 30143 return false; 30144 } 30145 } 30146} 30147 30148/* harmony default export */ const interaction_PinchRotate = (PinchRotate); 30149 30150;// CONCATENATED MODULE: ./node_modules/ol/interaction/PinchZoom.js 30151/** 30152 * @module ol/interaction/PinchZoom 30153 */ 30154 30155 30156 30157/** 30158 * @typedef {Object} Options 30159 * @property {number} [duration=400] Animation duration in milliseconds. 30160 */ 30161 30162/** 30163 * @classdesc 30164 * Allows the user to zoom the map by pinching with two fingers 30165 * on a touch screen. 30166 * @api 30167 */ 30168class PinchZoom extends Pointer { 30169 /** 30170 * @param {Options} [options] Options. 30171 */ 30172 constructor(options) { 30173 options = options ? options : {}; 30174 30175 const pointerOptions = /** @type {import("./Pointer.js").Options} */ ( 30176 options 30177 ); 30178 30179 if (!pointerOptions.stopDown) { 30180 pointerOptions.stopDown = functions_FALSE; 30181 } 30182 30183 super(pointerOptions); 30184 30185 /** 30186 * @private 30187 * @type {import("../coordinate.js").Coordinate} 30188 */ 30189 this.anchor_ = null; 30190 30191 /** 30192 * @private 30193 * @type {number} 30194 */ 30195 this.duration_ = options.duration !== undefined ? options.duration : 400; 30196 30197 /** 30198 * @private 30199 * @type {number|undefined} 30200 */ 30201 this.lastDistance_ = undefined; 30202 30203 /** 30204 * @private 30205 * @type {number} 30206 */ 30207 this.lastScaleDelta_ = 1; 30208 } 30209 30210 /** 30211 * Handle pointer drag events. 30212 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 30213 */ 30214 handleDragEvent(mapBrowserEvent) { 30215 let scaleDelta = 1.0; 30216 30217 const touch0 = this.targetPointers[0]; 30218 const touch1 = this.targetPointers[1]; 30219 const dx = touch0.clientX - touch1.clientX; 30220 const dy = touch0.clientY - touch1.clientY; 30221 30222 // distance between touches 30223 const distance = Math.sqrt(dx * dx + dy * dy); 30224 30225 if (this.lastDistance_ !== undefined) { 30226 scaleDelta = this.lastDistance_ / distance; 30227 } 30228 this.lastDistance_ = distance; 30229 30230 const map = mapBrowserEvent.map; 30231 const view = map.getView(); 30232 30233 if (scaleDelta != 1.0) { 30234 this.lastScaleDelta_ = scaleDelta; 30235 } 30236 30237 // scale anchor point. 30238 const viewportPosition = map.getViewport().getBoundingClientRect(); 30239 const centroid = Pointer_centroid(this.targetPointers); 30240 centroid[0] -= viewportPosition.left; 30241 centroid[1] -= viewportPosition.top; 30242 this.anchor_ = map.getCoordinateFromPixelInternal(centroid); 30243 30244 // scale, bypass the resolution constraint 30245 map.render(); 30246 view.adjustResolutionInternal(scaleDelta, this.anchor_); 30247 } 30248 30249 /** 30250 * Handle pointer up events. 30251 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 30252 * @return {boolean} If the event was consumed. 30253 */ 30254 handleUpEvent(mapBrowserEvent) { 30255 if (this.targetPointers.length < 2) { 30256 const map = mapBrowserEvent.map; 30257 const view = map.getView(); 30258 const direction = this.lastScaleDelta_ > 1 ? 1 : -1; 30259 view.endInteraction(this.duration_, direction); 30260 return false; 30261 } else { 30262 return true; 30263 } 30264 } 30265 30266 /** 30267 * Handle pointer down events. 30268 * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. 30269 * @return {boolean} If the event was consumed. 30270 */ 30271 handleDownEvent(mapBrowserEvent) { 30272 if (this.targetPointers.length >= 2) { 30273 const map = mapBrowserEvent.map; 30274 this.anchor_ = null; 30275 this.lastDistance_ = undefined; 30276 this.lastScaleDelta_ = 1; 30277 if (!this.handlingDownUpSequence) { 30278 map.getView().beginInteraction(); 30279 } 30280 return true; 30281 } else { 30282 return false; 30283 } 30284 } 30285} 30286 30287/* harmony default export */ const interaction_PinchZoom = (PinchZo
30287om); 30288 30289;// CONCATENATED MODULE: ./node_modules/ol/interaction/defaults.js 30290/** 30291 * @module ol/interaction/defaults 30292 */ 30293 30294 30295 30296 30297 30298 30299 30300 30301 30302 30303 30304 30305/** 30306 * @typedef {Object} DefaultsOptions 30307 * @property {boolean} [altShiftDragRotate=true] Whether Alt-Shift-drag rotate is 30308 * desired. 30309 * @property {boolean} [onFocusOnly=false] Interact only when the map has the 30310 * focus. This affects the `MouseWheelZoom` and `DragPan` interactions and is 30311 * useful when page scroll is desired for maps that do not have the browser's 30312 * focus. 30313 * @property {boolean} [doubleClickZoom=true] Whether double click zoom is 30314 * desired. 30315 * @property {boolean} [keyboard=true] Whether keyboard interaction is desired. 30316 * @property {boolean} [mouseWheelZoom=true] Whether mousewheel zoom is desired. 30317 * @property {boolean} [shiftDragZoom=true] Whether Shift-drag zoom is desired. 30318 * @property {boolean} [dragPan=true] Whether drag pan is desired. 30319 * @property {boolean} [pinchRotate=true] Whether pinch rotate is desired. 30320 * @property {boolean} [pinchZoom=true] Whether pinch zoom is desired. 30321 * @property {number} [zoomDelta] Zoom level delta when using keyboard or double click zoom. 30322 * @property {number} [zoomDuration] Duration of the zoom animation in 30323 * milliseconds. 30324 */ 30325 30326/** 30327 * Set of interactions included in maps by default. Specific interactions can be 30328 * excluded by setting the appropriate option to false in the constructor 30329 * options, but the order of the interactions is fixed. If you want to specify 30330 * a different order for interactions, you will need to create your own 30331 * {@link module:ol/interaction/Interaction~Interaction} instances and insert 30332 * them into a {@link module:ol/Collection~Collection} in the order you want 30333 * before creating your {@link module:ol/Map~Map} instance. Changing the order can 30334 * be of interest if the event propagation needs to be stopped at a point. 30335 * The default set of interactions, in sequence, is: 30336 * * {@link module:ol/interaction/DragRotate~DragRotate} 30337 * * {@link module:ol/interaction/DoubleClickZoom~DoubleClickZoom} 30338 * * {@link module:ol/interaction/DragPan~DragPan} 30339 * * {@link module:ol/interaction/PinchRotate~PinchRotate} 30340 * * {@link module:ol/interaction/PinchZoom~PinchZoom} 30341 * * {@link module:ol/interaction/KeyboardPan~KeyboardPan} 30342 * * {@link module:ol/interaction/KeyboardZoom~KeyboardZoom} 30343 * * {@link module:ol/interaction/MouseWheelZoom~MouseWheelZoom} 30344 * * {@link module:ol/interaction/DragZoom~DragZoom} 30345 * 30346 * @param {DefaultsOptions} [options] Defaults options. 30347 * @return {Collection<import("./Interaction.js").default>} 30348 * A collection of interactions to be used with the {@link module:ol/Map~Map} 30349 * constructor's `interactions` option. 30350 * @api 30351 */ 30352function defaults_defaults(options) { 30353 options = options ? options : {}; 30354 30355 /** @type {Collection<import("./Interaction.js").default>} */ 30356 const interactions = new ol_Collection(); 30357 30358 const kinetic = new ol_Kinetic(-0.005, 0.05, 100); 30359 30360 const altShiftDragRotate = 30361 options.altShiftDragRotate !== undefined 30362 ? options.altShiftDragRotate 30363 : true; 30364 if (altShiftDragRotate) { 30365 interactions.push(new interaction_DragRotate()); 30366 } 30367 30368 const doubleClickZoom = 30369 options.doubleClickZoom !== undefined ? options.doubleClickZoom : true; 30370 if (doubleClickZoom) { 30371 interactions.push( 30372 new interaction_DoubleClickZoom({ 30373 delta: options.zoomDelta, 30374 duration: options.zoomDuration, 30375 }) 30376 ); 30377 } 30378 30379 const dragPan = options.dragPan !== undefined ? options.dragPan : true; 30380 if (dragPan) { 30381 interactions.push( 30382 new interaction_DragPan({ 30383 onFocusOnly: options.onFocusOnly, 30384 kinetic: kinetic, 30385 }) 30386 ); 30387 } 30388 30389 const pinchRotate = 30390 options.pinchRotate !== undefined ? options.pinchRotate : true; 30391 if (pinchRotate) { 30392 interactions.push(new interaction_PinchRotate()); 30393 } 30394 30395 const pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true; 30396 if (pinchZoom) { 30397 interactions.push( 30398 new interaction_PinchZoom({ 30399 duration: options.zoomDuration, 30400 }) 30401 ); 30402 } 30403 30404 const keyboard = options.keyboard !== undefined ? options.keyboard : true; 30405 if (keyboard) { 30406 interactions.push(new interaction_KeyboardPan()); 30407 interactions.push( 30408 new interaction_KeyboardZoom({ 30409 delta: options.zoomDelta, 30410 duration: options.zoomDuration, 30411 }) 30412 ); 30413 } 30414 30415 const mouseWheelZoom = 30416 options.mouseWheelZoom !== undefined ? options.mouseWheelZoom : true; 30417 if (mouseWheelZoom) { 30418 interactions.push( 30419 new interaction_MouseWheelZoom({ 30420 onFocusOnly: options.onFocusOnly, 30421 duration: options.zoomDuration, 30422 }) 30423 ); 30424 } 30425 30426 const shiftDragZoom = 30427 options.shiftDragZoom !== undefined ? options.shiftDragZoom : true; 30428 if (shiftDragZoom) { 30429 interactions.push( 30430 new interaction_DragZoom({ 30431 duration: options.zoomDuration, 30432 }) 30433 ); 30434 } 30435 30436 return interactions; 30437} 30438 30439;// CONCATENATED MODULE: ./node_modules/ol/size.js 30440/** 30441 * @module ol/size 30442 */ 30443 30444/** 30445 * An array of numbers representing a size: `[width, height]`. 30446 * @typedef {Array<number>} Size 30447 * @api 30448 */ 30449 30450/** 30451 * Returns a buffered size. 30452 * @param {Size} size Size. 30453 * @param {number} num The amount by which to buffer. 30454 * @param {Size} [dest] Optional reusable size array. 30455 * @return {Size} The buffered size. 30456 */ 30457function size_buffer(size, num, dest) { 30458 if (dest === undefined) { 30459 dest = [0, 0]; 30460 } 30461 dest[0] = size[0] + 2 * num; 30462 dest[1] = size[1] + 2 * num; 30463 return dest; 30464} 30465
30466/** 30467 * Determines if a size has a positive area. 30468 * @param {Size} size The size to test. 30469 * @return {boolean} The size has a positive area. 30470 */ 30471function hasArea(size) { 30472 return size[0] > 0 && size[1] > 0; 30473} 30474 30475/** 30476 * Returns a size scaled by a ratio. The result will be an array of integers. 30477 * @param {Size} size Size. 30478 * @param {number} ratio Ratio. 30479 * @param {Size} [dest] Optional reusable size array. 30480 * @return {Size} The scaled size. 30481 */ 30482function size_scale(size, ratio, dest) { 30483 if (dest === undefined) { 30484 dest = [0, 0]; 30485 } 30486 dest[0] = (size[0] * ratio + 0.5) | 0; 30487 dest[1] = (size[1] * ratio + 0.5) | 0; 30488 return dest; 30489} 30490 30491/** 30492 * Returns an `Size` array for the passed in number (meaning: square) or 30493 * `Size` array. 30494 * (meaning: non-square), 30495 * @param {number|Size} size Width and height. 30496 * @param {Size} [dest] Optional reusable size array. 30497 * @return {Size} Size. 30498 * @api 30499 */ 30500function toSize(size, dest) { 30501 if (Array.isArray(size)) { 30502 return size; 30503 } else { 30504 if (dest === undefined) { 30505 dest = [size, size]; 30506 } else { 30507 dest[0] = size; 30508 dest[1] = size; 30509 } 30510 return dest; 30511 } 30512} 30513 30514;// CONCATENATED MODULE: ./node_modules/ol/Map.js 30515/** 30516 * @module ol/Map 30517 */ 30518 30519 30520 30521 30522 30523 30524 30525 30526 30527 30528 30529 30530 30531 30532 30533 30534 30535 30536 30537 30538 30539 30540 30541 30542 30543 30544 30545 30546 30547 30548 30549 30550/** 30551 * State of the current frame. Only `pixelRatio`, `time` and `viewState` should 30552 * be used in applications. 30553 * @typedef {Object} FrameState 30554 * @property {number} pixelRatio The pixel ratio of the frame. 30555 * @property {number} time The time when rendering of the frame was requested. 30556 * @property {import("./View.js").State} viewState The state of the current view. 30557 * @property {boolean} animate Animate. 30558 * @property {import("./transform.js").Transform} coordinateToPixelTransform CoordinateToPixelTransform. 30559 * @property {import("rbush").default} declutterTree DeclutterTree. 30560 * @property {null|import("./extent.js").Extent} extent Extent. 30561 * @property {import("./extent.js").Extent} [nextExtent] Next extent during an animation series. 30562 * @property {number} index Index. 30563 * @property {Array<import("./layer/Layer.js").State>} layerStatesArray LayerStatesArray. 30564 * @property {number} layerIndex LayerIndex. 30565 * @property {import("./transform.js").Transform} pixelToCoordinateTransform PixelToCoordinateTransform. 30566 * @property {Array<PostRenderFunction>} postRenderFunctions PostRenderFunctions. 30567 * @property {import("./size.js").Size} size Size. 30568 * @property {TileQueue} tileQueue TileQueue. 30569 * @property {!Object<string, Object<string, boolean>>} usedTiles UsedTiles. 30570 * @property {Array<number>} viewHints ViewHints. 30571 * @property {!Object<string, Object<string, boolean>>} wantedTiles WantedTiles. 30572 * @property {string} mapId The id of the map. 30573 * @property {Object<string, boolean>} renderTargets Identifiers of previously rendered elements. 30574 */ 30575 30576/** 30577 * @typedef {function(Map, ?FrameState): any} PostRenderFunction 30578 */ 30579 30580/** 30581 * @typedef {Object} AtPixelOptions 30582 * @property {undefined|function(import("./layer/Layer.js").default<import("./source/Source").default>): boolean} [layerFilter] Layer filter 30583 * function. The filter function will receive one argument, the 30584 * {@link module:ol/layer/Layer~Layer layer-candidate} and it should return a boolean value. 30585 * Only layers which are visible and for which this function returns `true` 30586 * will be tested for features. By default, all visible layers will be tested. 30587 * @property {number} [hitTolerance=0] Hit-detection tolerance in css pixels. Pixels 30588 * inside the radius around the given position will be checked for features. 30589 * @property {boolean} [checkWrapped=true] Check-Wrapped Will check for wrapped geometries inside the range of 30590 * +/- 1 world width. Works only if a projection is used that can be wrapped. 30591 */ 30592 30593/** 30594 * @typedef {Object} MapOptionsInternal 30595 * @property {Collection<import("./control/Control.js").default>} [controls] Controls. 30596 * @property {Collection<import("./interaction/Interaction.js").default>} [interactions] Interactions. 30597 * @property {HTMLElement|Document} keyboardEventTarget KeyboardEventTarget. 30598 * @property {Collection<import("./Overlay.js").default>} overlays Overlays. 30599 * @property {Object<string, *>} values Values. 30600 */ 30601 30602/** 30603 * @typedef {import("./ObjectEventType").Types|'change:layergroup'|'change:size'|'change:target'|'change:view'} MapObjectEventTypes 30604 */ 30605
vendor: 8,924 bytes, lines 30606-30864
30606/*** 30607 * @template Return 30608 * @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> & 30609 * import("./Observable").OnSignature<MapObjectEventTypes, import("./Object").ObjectEvent, Return> & 30610 * import("./Observable").OnSignature<import("./MapBrowserEventType").Types, import("./MapBrowserEvent").default, Return> & 30611 * import("./Observable").OnSignature<import("./MapEventType").Types, import("./MapEvent").default, Return> & 30612 * import("./Observable").OnSignature<import("./render/EventType").MapRenderEventTypes, import("./render/Event").default, Return> & 30613 * import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|MapObjectEventTypes| 30614 * import("./MapBrowserEventType").Types|import("./MapEventType").Types| 30615 * import("./render/EventType").MapRenderEventTypes, Return>} MapEventHandler 30616 */ 30617 30618/** 30619 * Object literal with config options for the map. 30620 * @typedef {Object} MapOptions 30621 * @property {Collection<import("./control/Control.js").default>|Array<import("./control/Control.js").default>} [controls] 30622 * Controls initially added to the map. If not specified, 30623 * {@link module:ol/control/defaults.defaults} is used. 30624 * @property {number} [pixelRatio=window.devicePixelRatio] The ratio between 30625 * physical pixels and device-independent pixels (dips) on the device. 30626 * @property {Collection<import("./interaction/Interaction.js").default>|Array<import("./interaction/Interaction.js").default>} [interactions] 30627 * Interactions that are initially added to the map. If not specified, 30628 * {@link module:ol/interaction/defaults.defaults} is used. 30629 * @property {HTMLElement|Document|string} [keyboardEventTarget] The element to 30630 * listen to keyboard events on. This determines when the `KeyboardPan` and 30631 * `KeyboardZoom` interactions trigger. For example, if this option is set to 30632 * `document` the keyboard interactions will always trigger. If this option is 30633 * not specified, the element the library listens to keyboard events on is the 30634 * map target (i.e. the user-provided div for the map). If this is not 30635 * `document`, the target element needs to be focused for key events to be 30636 * emitted, requiring that the target element has a `tabindex` attribute. 30637 * @property {Array<import("./layer/Base.js").default>|Collection<import("./layer/Base.js").default>|LayerGroup} [layers] 30638 * Layers. If this is not defined, a map with no layers will be rendered. Note 30639 * that layers are rendered in the order supplied, so if you want, for example, 30640 * a vector layer to appear on top of a tile layer, it must come after the tile 30641 * layer. 30642 * @property {number} [maxTilesLoading=16] Maximum number tiles to load 30643 * simultaneously. 30644 * @property {number} [moveTolerance=1] The minimum distance in pixels the 30645 * cursor must move to be detected as a map move event instead of a click. 30646 * Increasing this value can make it easier to click on the map. 30647 * @property {Collection<import("./Overlay.js").default>|Array<import("./Overlay.js").default>} [overlays] 30648 * Overlays initially added to the map. By default, no overlays are added. 30649 * @property {HTMLElement|string} [target] The container for the map, either the 30650 * element itself or the `id` of the element. If not specified at construction 30651 * time, {@link module:ol/Map~Map#setTarget} must be called for the map to be 30652 * rendered. If passed by element, the container can be in a secondary document. 30653 * @property {View|Promise<import("./View.js").ViewOptions>} [view] The map's view. No layer sources will be 30654 * fetched unless this is specified at construction time or through 30655 * {@link module:ol/Map~Map#setView}. 30656 */ 30657 30658/** 30659 * @param {import("./layer/Base.js").default} layer Layer. 30660 */ 30661function removeLayerMapProperty(layer) { 30662 if (layer instanceof layer_Layer) { 30663 layer.setMapInternal(null); 30664 return; 30665 } 30666 if (layer instanceof Group) { 30667 layer.getLayers().forEach(removeLayerMapProperty); 30668 } 30669} 30670 30671/** 30672 * @param {import("./layer/Base.js").default} layer Layer. 30673 * @param {Map} map Map. 30674 */ 30675function setLayerMapProperty(layer, map) { 30676 if (layer instanceof layer_Layer) { 30677 layer.setMapInternal(map); 30678 return; 30679 } 30680 if (layer instanceof Group) { 30681 const layers = layer.getLayers().getArray(); 30682 for (let i = 0, ii = layers.length; i < ii; ++i) { 30683 setLayerMapProperty(layers[i], map); 30684 } 30685 } 30686} 30687 30688/** 30689 * @classdesc 30690 * The map is the core component of OpenLayers. For a map to render, a view, 30691 * one or more layers, and a target container are needed: 30692 * 30693 * import Map from 'ol/Map'; 30694 * import View from 'ol/View'; 30695 * import TileLayer from 'ol/layer/Tile'; 30696 * import OSM from 'ol/source/OSM'; 30697 * 30698 * const map = new Map({ 30699 * view: new View({ 30700 * center: [0, 0], 30701 * zoom: 1, 30702 * }), 30703 * layers: [ 30704 * new TileLayer({ 30705 * source: new OSM(), 30706 * }), 30707 * ], 30708 * target: 'map', 30709 * }); 30710 * 30711 * The above snippet creates a map using a {@link module:ol/layer/Tile~TileLayer} to 30712 * display {@link module:ol/source/OSM~OSM} OSM data and render it to a DOM 30713 * element with the id `map`. 30714 * 30715 * The constructor places a viewport container (with CSS class name 30716 * `ol-viewport`) in the target element (see `getViewport()`), and then two 30717 * further elements within the viewport: one with CSS class name 30718 * `ol-overlaycontainer-stopevent` for controls and some overlays, and one with 30719 * CSS class name `ol-overlaycontainer` for other overlays (see the `stopEvent` 30720 * option of {@link module:ol/Overlay~Overlay} for the difference). The map 30721 * itself is placed in a further element within the viewport. 30722 * 30723 * Layers are stored as a {@link module:ol/Collection~Collection} in 30724 * layerGroups. A top-level group is provided by the library. This is what is 30725 * accessed by `getLayerGroup` and `setLayerGroup`. Layers entered in the 30726 * options are added to this group, and `addLayer` and `removeLayer` change the 30727 * layer collection in the group. `getLayers` is a convenience function for 30728 * `getLayerGroup().getLayers()`. Note that {@link module:ol/layer/Group~LayerGroup} 30729 * is a subclass of {@link module:ol/layer/Base~BaseLayer}, so layers entered in the 30730 * options or added with `addLayer` can be groups, which can contain further 30731 * groups, and so on. 30732 * 30733 * @fires import("./MapBrowserEvent.js").MapBrowserEvent 30734 * @fires import("./MapEvent.js").MapEvent 30735 * @fires import("./render/Event.js").default#precompose 30736 * @fires import("./render/Event.js").default#postcompose 30737 * @fires import("./render/Event.js").default#rendercomplete 30738 * @api 30739 */ 30740class Map_Map extends ol_Object { 30741 /** 30742 * @param {MapOptions} [options] Map options. 30743 */ 30744 constructor(options) { 30745 super(); 30746 30747 options = options || {}; 30748 30749 /*** 30750 * @type {MapEventHandler<import("./events").EventsKey>} 30751 */ 30752 this.on; 30753 30754 /*** 30755 * @type {MapEventHandler<import("./events").EventsKey>} 30756 */ 30757 this.once; 30758 30759 /*** 30760 * @type {MapEventHandler<void>} 30761 */ 30762 this.un; 30763 30764 const optionsInternal = createOptionsInternal(options); 30765 30766 /** 30767 * @private 30768 * @type {boolean|undefined} 30769 */ 30770 this.renderComplete_; 30771 30772 /** 30773 * @private 30774 * @type {boolean} 30775 */ 30776 this.loaded_ = true; 30777 30778 /** @private */ 30779 this.boundHandleBrowserEvent_ = this.handleBrowserEvent.bind(this); 30780 30781 /** 30782 * @type {number} 30783 * @private 30784 */ 30785 this.maxTilesLoading_ = 30786 options.maxTilesLoading !== undefined ? options.maxTilesLoading : 16; 30787 30788 /** 30789 * @private 30790 * @type {number} 30791 */ 30792 this.pixelRatio_ = 30793 options.pixelRatio !== undefined 30794 ? options.pixelRatio 30795 : DEVICE_PIXEL_RATIO; 30796 30797 /** 30798 * @private 30799 * @type {*} 30800 */ 30801 this.postRenderTimeoutHandle_; 30802 30803 /** 30804 * @private 30805 * @type {number|undefined} 30806 */ 30807 this.animationDelayKey_; 30808 30809 /** 30810 * @private 30811 */ 30812 this.animationDelay_ = this.animationDelay_.bind(this); 30813 30814 /** 30815 * @private 30816 * @type {import("./transform.js").Transform} 30817 */ 30818 this.coordinateToPixelTransform_ = create(); 30819 30820 /** 30821 * @private 30822 * @type {import("./transform.js").Transform} 30823 */ 30824 this.pixelToCoordinateTransform_ = create(); 30825 30826 /** 30827 * @private 30828 * @type {number} 30829 */ 30830 this.frameIndex_ = 0; 30831 30832 /** 30833 * @private 30834 * @type {?FrameState} 30835 */ 30836 this.frameState_ = null; 30837 30838 /** 30839 * The extent at the previous 'moveend' event. 30840 * @private 30841 * @type {import("./extent.js").Extent} 30842 */ 30843 this.previousExtent_ = null; 30844 30845 /** 30846 * @private 30847 * @type {?import("./events.js").EventsKey} 30848 */ 30849 this.viewPropertyListenerKey_ = null; 30850 30851 /** 30852 * @private 30853 * @type {?import("./events.js").EventsKey} 30854 */ 30855 this.viewChangeListenerKey_ = null; 30856 30857 /** 30858 * @private 30859 * @type {?Array<import("./events.js").EventsKey>} 30860 */ 30861 this.layerGroupPropertyListenerKeys_ = null; 30862 30863 /** 30864 * @private
30865 * @type {!HTMLElement} 30866 */ 30867 this.viewport_ = document.createElement('div'); 30868 this.viewport_.className = 30869 'ol-viewport' + ('ontouchstart' in window ? ' ol-touch' : ''); 30870 this.viewport_.style.position = 'relative'; 30871 this.viewport_.style.overflow = 'hidden'; 30872 this.viewport_.style.width = '100%'; 30873 this.viewport_.style.height = '100%'; 30874 30875 /** 30876 * @private 30877 * @type {!HTMLElement} 30878 */ 30879 this.overlayContainer_ = document.createElement('div'); 30880 this.overlayContainer_.style.position = 'absolute'; 30881 this.overlayContainer_.style.zIndex = '0'; 30882 this.overlayContainer_.style.width = '100%'; 30883 this.overlayContainer_.style.height = '100%'; 30884 this.overlayContainer_.style.pointerEvents = 'none'; 30885 this.overlayContainer_.className = 'ol-overlaycontainer'; 30886 this.viewport_.appendChild(this.overlayContainer_); 30887 30888 /** 30889 * @private 30890 * @type {!HTMLElement} 30891 */ 30892 this.overlayContainerStopEvent_ = document.createElement('div'); 30893 this.overlayContainerStopEvent_.style.position = 'absolute'; 30894 this.overlayContainerStopEvent_.style.zIndex = '0'; 30895 this.overlayContainerStopEvent_.style.width = '100%'; 30896 this.overlayContainerStopEvent_.style.height = '100%'; 30897 this.overlayContainerStopEvent_.style.pointerEvents = 'none'; 30898 this.overlayContainerStopEvent_.className = 'ol-overlaycontainer-stopevent'; 30899 this.viewport_.appendChild(this.overlayContainerStopEvent_); 30900 30901 /** 30902 * @private 30903 * @type {MapBrowserEventHandler} 30904 */ 30905 this.mapBrowserEventHandler_ = null; 30906 30907 /** 30908 * @private 30909 * @type {number} 30910 */ 30911 this.moveTolerance_ = options.moveTolerance; 30912 30913 /** 30914 * @private 30915 * @type {HTMLElement|Document} 30916 */ 30917 this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget; 30918 30919 /** 30920 * @private 30921 * @type {?Array<import("./events.js").EventsKey>} 30922 */ 30923 this.targetChangeHandlerKeys_ = null; 30924 30925 /** 30926 * @type {Collection<import("./control/Control.js").default>} 30927 * @protected 30928 */ 30929 this.controls = optionsInternal.controls || defaults(); 30930 30931 /** 30932 * @type {Collection<import("./interaction/Interaction.js").default>} 30933 * @protected 30934 */ 30935 this.interactions = 30936 optionsInternal.interactions || 30937 defaults_defaults({ 30938 onFocusOnly: true, 30939 }); 30940 30941 /** 30942 * @type {Collection<import("./Overlay.js").default>} 30943 * @private 30944 */ 30945 this.overlays_ = optionsInternal.overlays; 30946 30947 /** 30948 * A lookup of overlays by id. 30949 * @private 30950 * @type {Object<string, import("./Overlay.js").default>} 30951 */ 30952 this.overlayIdIndex_ = {}; 30953 30954 /** 30955 * @type {import("./renderer/Map.js").default|null} 30956 * @private 30957 */ 30958 this.renderer_ = null; 30959 30960 /** 30961 * @private 30962 * @type {!Array<PostRenderFunction>} 30963 */ 30964 this.postRenderFunctions_ = []; 30965 30966 /** 30967 * @private 30968 * @type {TileQueue} 30969 */ 30970 this.tileQueue_ = new ol_TileQueue( 30971 this.getTilePriority.bind(this), 30972 this.handleTileChange_.bind(this) 30973 ); 30974 30975 this.addChangeListener( 30976 MapProperty.LAYERGROUP, 30977 this.handleLayerGroupChanged_ 30978 ); 30979 this.addChangeListener(MapProperty.VIEW, this.handleViewChanged_); 30980 this.addChangeListener(MapProperty.SIZE, this.handleSizeChanged_); 30981 this.addChangeListener(MapProperty.TARGET, this.handleTargetChanged_); 30982 30983 // setProperties will trigger the rendering of the map if the map 30984 // is "defined" already. 30985 this.setProperties(optionsInternal.values); 30986 30987 const map = this; 30988 if (options.view && !(options.view instanceof ol_View)) { 30989 options.view.then(function (viewOptions) {
30990 map.setView(new ol_View(viewOptions)); 30991 }); 30992 } 30993 30994 this.controls.addEventListener( 30995 CollectionEventType.ADD, 30996 /** 30997 * @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent 30998 */ 30999 function (event) { 31000 event.element.setMap(this); 31001 }.bind(this) 31002 ); 31003 31004 this.controls.addEventListener( 31005 CollectionEventType.REMOVE, 31006 /** 31007 * @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent. 31008 */ 31009 function (event) { 31010 event.element.setMap(null); 31011 }.bind(this) 31012 ); 31013 31014 this.interactions.addEventListener( 31015 CollectionEventType.ADD, 31016 /** 31017 * @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent. 31018 */ 31019 function (event) { 31020 event.element.setMap(this); 31021 }.bind(this) 31022 ); 31023 31024 this.interactions.addEventListener( 31025 CollectionEventType.REMOVE, 31026 /** 31027 * @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent. 31028 */ 31029 function (event) { 31030 event.element.setMap(null); 31031 }.bind(this) 31032 ); 31033 31034 this.overlays_.addEventListener( 31035 CollectionEventType.ADD, 31036 /** 31037 * @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent. 31038 */ 31039 function (event) { 31040 this.addOverlayInternal_(event.element); 31041 }.bind(this) 31042 ); 31043 31044 this.overlays_.addEventListener( 31045 CollectionEventType.REMOVE, 31046 /** 31047 * @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent. 31048 */ 31049 function (event) { 31050 const id = event.element.getId(); 31051 if (id !== undefined) { 31052 delete this.overlayIdIndex_[id.toString()]; 31053 } 31054 event.element.setMap(null); 31055 }.bind(this) 31056 ); 31057 31058 this.controls.forEach( 31059 /** 31060 * @param {import("./control/Control.js").default} control Control. 31061 * @this {Map} 31062 */ 31063 function (control) { 31064 control.setMap(this); 31065 }.bind(this) 31066 ); 31067 31068 this.interactions.forEach( 31069 /** 31070 * @param {import("./interaction/Interaction.js").default} interaction Interaction. 31071 * @this {Map} 31072 */ 31073 function (interaction) { 31074 interaction.setMap(this); 31075 }.bind(this) 31076 ); 31077 31078 this.overlays_.forEach(this.addOverlayInternal_.bind(this)); 31079 } 31080 31081 /** 31082 * Add the given control to the map. 31083 * @param {import("./control/Control.js").default} control Control. 31084 * @api 31085 */ 31086 addControl(control) { 31087 this.getControls().push(control); 31088 } 31089 31090 /** 31091 * Add the given interaction to the map. If you want to add an interaction 31092 * at another point of the collection use `getInteractions()` and the methods 31093 * available on {@link module:ol/Collection~Collection}. This can be used to 31094 * stop the event propagation from the handleEvent function. The interactions 31095 * get to handle the events in the reverse order of this collection. 31096 * @param {import("./interaction/Interaction.js").default} interaction Interaction to add. 31097 * @api 31098 */ 31099 addInteraction(interaction) { 31100 this.getInteractions().push(interaction); 31101 } 31102 31103 /** 31104 * Adds the given layer to the top of this map. If you want to add a layer 31105 * elsewhere in the stack, use `getLayers()` and the methods available on 31106 * {@link module:ol/Collection~Collection}. 31107 * @param {import("./layer/Base.js").default} layer Layer. 31108 * @api 31109 */ 31110 addLayer(layer) { 31111 const layers = this.getLayerGroup().getLayers(); 31112 layers.push(layer); 31113 } 31114 31115 /** 31116 * @param {import("./layer/Group.js").GroupEvent} event The layer add event. 31117 * @private 31118 */ 31119 handleLayerAdd_(event) { 31120 setLayerMapProperty(event.layer, this); 31121 } 31122 31123 /** 31124 * Add the given overlay to the map. 31125 * @param {import("./Overlay.js").default} overlay Overlay. 31126 * @api 31127 */ 31128 addOverlay(overlay) { 31129 this.getOverlays().push(overlay); 31130 } 31131 31132 /** 31133 * This deals with map's overlay collection changes. 31134 * @param {import("./Overlay.js").default} overlay Overlay. 31135 * @private 31136 */ 31137 addOverlayInternal_(overlay) { 31138 const id = overlay.getId(); 31139 if (id !== undefined) {
31140 this.overlayIdIndex_[id.toString()] = overlay; 31141 } 31142 overlay.setMap(this); 31143 } 31144 31145 /** 31146 * 31147 * Clean up. 31148 */ 31149 disposeInternal() { 31150 this.controls.clear(); 31151 this.interactions.clear(); 31152 this.overlays_.clear(); 31153 this.setTarget(null); 31154 super.disposeInternal(); 31155 } 31156 31157 /** 31158 * Detect features that intersect a pixel on the viewport, and execute a 31159 * callback with each intersecting feature. Layers included in the detection can 31160 * be configured through the `layerFilter` option in `options`. 31161 * @param {import("./pixel.js").Pixel} pixel Pixel. 31162 * @param {function(import("./Feature.js").FeatureLike, import("./layer/Layer.js").default<import("./source/Source").default>, import("./geom/SimpleGeometry.js").default): T} callback Feature callback. The callback will be 31163 * called with two arguments. The first argument is one 31164 * {@link module:ol/Feature~Feature feature} or 31165 * {@link module:ol/render/Feature~RenderFeature render feature} at the pixel, the second is 31166 * the {@link module:ol/layer/Layer~Layer layer} of the feature and will be null for 31167 * unmanaged layers. To stop detection, callback functions can return a 31168 * truthy value. 31169 * @param {AtPixelOptions} [options] Optional options. 31170 * @return {T|undefined} Callback result, i.e. the return value of last 31171 * callback execution, or the first truthy callback return value. 31172 * @template T 31173 * @api 31174 */ 31175 forEachFeatureAtPixel(pixel, callback, options) { 31176 if (!this.frameState_ || !this.renderer_) { 31177 return; 31178 } 31179 const coordinate = this.getCoordinateFromPixelInternal(pixel); 31180 options = options !== undefined ? options : {}; 31181 const hitTolerance = 31182 options.hitTolerance !== undefined ? options.hitTolerance : 0; 31183 const layerFilter = 31184 options.layerFilter !== undefined ? options.layerFilter : TRUE; 31185 const checkWrapped = options.checkWrapped !== false; 31186 return this.renderer_.forEachFeatureAtCoordinate( 31187 coordinate, 31188 this.frameState_, 31189 hitTolerance, 31190 checkWrapped, 31191 callback, 31192 null, 31193 layerFilter, 31194 null 31195 ); 31196 } 31197 31198 /** 31199 * Get all features that intersect a pixel on the viewport. 31200 * @param {import("./pixel.js").Pixel} pixel Pixel. 31201 * @param {AtPixelOptions} [options] Optional options. 31202 * @return {Array<import("./Feature.js").FeatureLike>} The detected features or 31203 * an empty array if none were found. 31204 * @api 31205 */ 31206 getFeaturesAtPixel(pixel, options) { 31207 const features = []; 31208 this.forEachFeatureAtPixel( 31209 pixel, 31210 function (feature) { 31211 features.push(feature); 31212 }, 31213 options 31214 ); 31215 return features; 31216 } 31217 31218 /** 31219 * Get all layers from all layer groups. 31220 * @return {Array<import("./layer/Layer.js").default>} Layers. 31221 * @api 31222 */ 31223 getAllLayers() { 31224 const layers = []; 31225 function addLayersFrom(layerGroup) { 31226 layerGroup.forEach(function (layer) { 31227 if (layer instanceof Group) { 31228 addLayersFrom(layer.getLayers()); 31229 } else { 31230 layers.push(layer); 31231 } 31232 }); 31233 } 31234 addLayersFrom(this.getLayers()); 31235 return layers; 31236 } 31237 31238 /** 31239 * Detect if features intersect a pixel on the viewport. Layers included in the 31240 * detection can be configured through the `layerFilter` option. 31241 * @param {import("./pixel.js").Pixel} pixel Pixel. 31242 * @param {AtPixelOptions} [options] Optional options. 31243 * @return {boolean} Is there a feature at the given pixel? 31244 * @api 31245 */ 31246 hasFeatureAtPixel(pixel, options) { 31247 if (!this.frameState_ || !this.renderer_) { 31248 return false; 31249 } 31250 const coordinate = this.getCoordinateFromPixelInternal(pixel); 31251 options = options !== undefined ? options : {}; 31252 const layerFilter = 31253 options.layerFilter !== undefined ? options.layerFilter : TRUE; 31254 const hitTolerance = 31255 options.hitTolerance !== undefined ? options.hitTolerance : 0; 31256 const checkWrapped = options.checkWrapped !== false; 31257 return this.renderer_.hasFeatureAtCoordinate( 31258 coordinate, 31259 this.frameState_, 31260 hitTolerance, 31261 checkWrapped, 31262 layerFilter, 31263 null 31264 ); 31265 } 31266 31267 /** 31268 * Returns the coordinate in user projection for a browser event. 31269 * @param {MouseEvent} event Event. 31270 * @return {import("./coordinate.js").Coordinate} Coordinate. 31271 * @api 31272 */
31273 getEventCoordinate(event) { 31274 return this.getCoordinateFromPixel(this.getEventPixel(event)); 31275 } 31276 31277 /** 31278 * Returns the coordinate in view projection for a browser event. 31279 * @param {MouseEvent} event Event. 31280 * @return {import("./coordinate.js").Coordinate} Coordinate. 31281 */ 31282 getEventCoordinateInternal(event) { 31283 return this.getCoordinateFromPixelInternal(this.getEventPixel(event)); 31284 } 31285 31286 /** 31287 * Returns the map pixel position for a browser event relative to the viewport. 31288 * @param {UIEvent} event Event. 31289 * @return {import("./pixel.js").Pixel} Pixel. 31290 * @api 31291 */ 31292 getEventPixel(event) { 31293 const viewportPosition = this.viewport_.getBoundingClientRect(); 31294 const eventPosition = 31295 //FIXME Are we really calling this with a TouchEvent anywhere? 31296 'changedTouches' in event 31297 ? /** @type {TouchEvent} */ (event).changedTouches[0] 31298 : /** @type {MouseEvent} */ (event); 31299 31300 return [ 31301 eventPosition.clientX - viewportPosition.left, 31302 eventPosition.clientY - viewportPosition.top, 31303 ]; 31304 } 31305 31306 /** 31307 * Get the target in which this map is rendered. 31308 * Note that this returns what is entered as an option or in setTarget: 31309 * if that was an element, it returns an element; if a string, it returns that. 31310 * @return {HTMLElement|string|undefined} The Element or id of the Element that the 31311 * map is rendered in. 31312 * @observable 31313 * @api 31314 */ 31315 getTarget() { 31316 return /** @type {HTMLElement|string|undefined} */ ( 31317 this.get(MapProperty.TARGET) 31318 ); 31319 } 31320 31321 /** 31322 * Get the DOM element into which this map is rendered. In contrast to 31323 * `getTarget` this method always return an `Element`, or `null` if the 31324 * map has no target. 31325 * @return {HTMLElement} The element that the map is rendered in. 31326 * @api 31327 */ 31328 getTargetElement() { 31329 const target = this.getTarget(); 31330 if (target !== undefined) { 31331 return typeof target === 'string' 31332 ? document.getElementById(target) 31333 : target; 31334 } else { 31335 return null; 31336 } 31337 } 31338 31339 /** 31340 * Get the coordinate for a given pixel. This returns a coordinate in the 31341 * user projection. 31342 * @param {import("./pixel.js").Pixel} pixel Pixel position in the map viewport. 31343 * @return {import("./coordinate.js").Coordinate} The coordinate for the pixel position. 31344 * @api 31345 */ 31346 getCoordinateFromPixel(pixel) { 31347 return toUserCoordinate( 31348 this.getCoordinateFromPixelInternal(pixel), 31349 this.getView().getProjection() 31350 ); 31351 } 31352 31353 /** 31354 * Get the coordinate for a given pixel. This returns a coordinate in the 31355 * map view projection. 31356 * @param {import("./pixel.js").Pixel} pixel Pixel position in the map viewport. 31357 * @return {import("./coordinate.js").Coordinate} The coordinate for the pixel position. 31358 */ 31359 getCoordinateFromPixelInternal(pixel) { 31360 const frameState = this.frameState_; 31361 if (!frameState) { 31362 return null; 31363 } else { 31364 return apply( 31365 frameState.pixelToCoordinateTransform, 31366 pixel.slice() 31367 ); 31368 } 31369 } 31370 31371 /** 31372 * Get the map controls. Modifying this collection changes the controls 31373 * associated with the map. 31374 * @return {Collection<import("./control/Control.js").default>} Controls. 31375 * @api 31376 */ 31377 getControls() { 31378 return this.controls; 31379 } 31380 31381 /** 31382 * Get the map overlays. Modifying this collection changes the overlays 31383 * associated with the map. 31384 * @return {Collection<import("./Overlay.js").default>} Overlays. 31385 * @api 31386 */ 31387 getOverlays() { 31388 return this.overlays_; 31389 } 31390 31391 /** 31392 * Get an overlay by its identifier (the value returned by overlay.getId()). 31393 * Note that the index treats string and numeric identifiers as the same. So 31394 * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`. 31395 * @param {string|number} id Overlay identifier. 31396 * @return {import("./Overlay.js").default} Overlay. 31397 * @api 31398 */ 31399 getOverlayById(id) { 31400 const overlay = this.overlayIdIndex_[id.toString()]; 31401 return overlay !== undefined ? overlay : null; 31402 } 31403 31404 /** 31405 * Get the map interactions. Modifying this collection changes the interactions 31406 * associated with the map. 31407 * 31408 * Interactions are used for e.g. pan, zoom and rotate. 31409 * @return {Collection<import("./interaction/Interaction.js").default>} Interactions. 31410 * @api 31411 */ 31412 getInteractions() { 31413 return this.interactions; 31414 } 31415 31416 /** 31417 * Get the layergroup associated with this map. 31418 * @return {LayerGroup} A layer group containing the layers in this map. 31419 * @observable 31420 * @api 31421 */ 31422 getLayerGroup() { 31423 return /** @type {LayerGroup} */ (this.get(MapProperty.LAYERGROUP)); 31424 } 31425 31426 /** 31427 * Clear any existing layers and add layers to the map. 31428 * @param {Array<import("./layer/Base.js").default>|Collection<import("./layer/Base.js").default>} layers The layers to be added to the map. 31429 * @api 31430 */ 31431 setLayers(layers) { 31432 const group = this.getLayerGroup();
vendor: 5,084 bytes, lines 31433-31609
31433 if (layers instanceof ol_Collection) { 31434 group.setLayers(layers); 31435 return; 31436 } 31437 31438 const collection = group.getLayers(); 31439 collection.clear(); 31440 collection.extend(layers); 31441 } 31442 31443 /** 31444 * Get the collection of layers associated with this map. 31445 * @return {!Collection<import("./layer/Base.js").default>} Layers. 31446 * @api 31447 */ 31448 getLayers() { 31449 const layers = this.getLayerGroup().getLayers(); 31450 return layers; 31451 } 31452 31453 /** 31454 * @return {boolean} Layers have sources that are still loading. 31455 */ 31456 getLoadingOrNotReady() { 31457 const layerStatesArray = this.getLayerGroup().getLayerStatesArray(); 31458 for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) { 31459 const state = layerStatesArray[i]; 31460 if (!state.visible) { 31461 continue; 31462 } 31463 const renderer = state.layer.getRenderer(); 31464 if (renderer && !renderer.ready) { 31465 return true; 31466 } 31467 const source = state.layer.getSource(); 31468 if (source && source.loading) { 31469 return true; 31470 } 31471 } 31472 return false; 31473 } 31474 31475 /** 31476 * Get the pixel for a coordinate. This takes a coordinate in the user 31477 * projection and returns the corresponding pixel. 31478 * @param {import("./coordinate.js").Coordinate} coordinate A map coordinate. 31479 * @return {import("./pixel.js").Pixel} A pixel position in the map viewport. 31480 * @api 31481 */ 31482 getPixelFromCoordinate(coordinate) { 31483 const viewCoordinate = fromUserCoordinate( 31484 coordinate, 31485 this.getView().getProjection() 31486 ); 31487 return this.getPixelFromCoordinateInternal(viewCoordinate); 31488 } 31489 31490 /** 31491 * Get the pixel for a coordinate. This takes a coordinate in the map view 31492 * projection and returns the corresponding pixel. 31493 * @param {import("./coordinate.js").Coordinate} coordinate A map coordinate. 31494 * @return {import("./pixel.js").Pixel} A pixel position in the map viewport. 31495 */ 31496 getPixelFromCoordinateInternal(coordinate) { 31497 const frameState = this.frameState_; 31498 if (!frameState) { 31499 return null; 31500 } else { 31501 return apply( 31502 frameState.coordinateToPixelTransform, 31503 coordinate.slice(0, 2) 31504 ); 31505 } 31506 } 31507 31508 /** 31509 * Get the map renderer. 31510 * @return {import("./renderer/Map.js").default|null} Renderer 31511 */ 31512 getRenderer() { 31513 return this.renderer_; 31514 } 31515 31516 /** 31517 * Get the size of this map. 31518 * @return {import("./size.js").Size|undefined} The size in pixels of the map in the DOM. 31519 * @observable 31520 * @api 31521 */ 31522 getSize() { 31523 return /** @type {import("./size.js").Size|undefined} */ ( 31524 this.get(MapProperty.SIZE) 31525 ); 31526 } 31527 31528 /** 31529 * Get the view associated with this map. A view manages properties such as 31530 * center and resolution. 31531 * @return {View} The view that controls this map. 31532 * @observable 31533 * @api 31534 */ 31535 getView() { 31536 return /** @type {View} */ (this.get(MapProperty.VIEW)); 31537 } 31538 31539 /** 31540 * Get the element that serves as the map viewport. 31541 * @return {HTMLElement} Viewport. 31542 * @api 31543 */ 31544 getViewport() { 31545 return this.viewport_; 31546 } 31547 31548 /** 31549 * Get the element that serves as the container for overlays. Elements added to 31550 * this container will let mousedown and touchstart events through to the map, 31551 * so clicks and gestures on an overlay will trigger {@link module:ol/MapBrowserEvent~MapBrowserEvent} 31552 * events. 31553 * @return {!HTMLElement} The map's overlay container. 31554 */ 31555 getOverlayContainer() { 31556 return this.overlayContainer_; 31557 } 31558 31559 /** 31560 * Get the element that serves as a container for overlays that don't allow 31561 * event propagation. Elements added to this container won't let mousedown and 31562 * touchstart events through to the map, so clicks and gestures on an overlay 31563 * don't trigger any {@link module:ol/MapBrowserEvent~MapBrowserEvent}. 31564 * @return {!HTMLElement} The map's overlay container that stops events. 31565 */ 31566 getOverlayContainerStopEvent() { 31567 return this.overlayContainerStopEvent_; 31568 } 31569 31570 /** 31571 * @return {!Document} The document where the map is displayed. 31572 */ 31573 getOwnerDocument() { 31574 const targetElement = this.getTargetElement(); 31575 return targetElement ? targetElement.ownerDocument : document; 31576 } 31577 31578 /** 31579 * @param {import("./Tile.js").default} tile Tile. 31580 * @param {string} tileSourceKey Tile source key. 31581 * @param {import("./coordinate.js").Coordinate} tileCenter Tile center. 31582 * @param {number} tileResolution Tile resolution. 31583 * @return {number} Tile priority. 31584 */ 31585 getTilePriority(tile, tileSourceKey, tileCenter, tileResolution) { 31586 return getTilePriority( 31587 this.frameState_, 31588 tile, 31589 tileSourceKey, 31590 tileCenter, 31591 tileResolution 31592 ); 31593 } 31594 31595 /** 31596 * @param {UIEvent} browserEvent Browser event. 31597 * @param {string} [type] Type. 31598 */ 31599 handleBrowserEvent(browserEvent, type) { 31600 type = type || browserEvent.type; 31601 const mapBrowserEvent = new ol_MapBrowserEvent(type, this, browserEvent); 31602 this.handleMapBrowserEvent(mapBrowserEvent); 31603 } 31604 31605 /** 31606 * @param {MapBrowserEvent} mapBrowserEvent The event to handle. 31607 */ 31608 handleMapBrowserEvent(mapBrowserEvent) { 31609 if (!this.frameState_) {
31610 // With no view defined, we cannot translate pixels into geographical 31611 // coordinates so interactions cannot be used. 31612 return; 31613 } 31614 const originalEvent = /** @type {PointerEvent} */ ( 31615 mapBrowserEvent.originalEvent 31616 ); 31617 const eventType = originalEvent.type; 31618 if ( 31619 eventType === pointer_EventType.POINTERDOWN || 31620 eventType === EventType.WHEEL || 31621 eventType === EventType.KEYDOWN 31622 ) { 31623 const doc = this.getOwnerDocument(); 31624 const rootNode = this.viewport_.getRootNode 31625 ? this.viewport_.getRootNode() 31626 : doc; 31627 const target = /** @type {Node} */ (originalEvent.target); 31628 if ( 31629 // Abort if the target is a child of the container for elements whose events are not meant 31630 // to be handled by map interactions. 31631 this.overlayContainerStopEvent_.contains(target) || 31632 // Abort if the event target is a child of the container that is no longer in the page. 31633 // It's possible for the target to no longer be in the page if it has been removed in an 31634 // event listener, this might happen in a Control that recreates it's content based on 31635 // user interaction either manually or via a render in something like https://reactjs.org/ 31636 !(rootNode === doc ? doc.documentElement : rootNode).contains(target) 31637 ) { 31638 return; 31639 } 31640 } 31641 mapBrowserEvent.frameState = this.frameState_; 31642 if (this.dispatchEvent(mapBrowserEvent) !== false) { 31643 const interactionsArray = this.getInteractions().getArray().slice(); 31644 for (let i = interactionsArray.length - 1; i >= 0; i--) { 31645 const interaction = interactionsArray[i]; 31646 if ( 31647 interaction.getMap() !== this || 31648 !interaction.getActive() || 31649 !this.getTargetElement() 31650 ) { 31651 continue; 31652 } 31653 const cont = interaction.handleEvent(mapBrowserEvent); 31654 if (!cont || mapBrowserEvent.propagationStopped) { 31655 break; 31656 } 31657 } 31658 } 31659 } 31660 31661 /** 31662 * @protected 31663 */ 31664 handlePostRender() { 31665 const frameState = this.frameState_; 31666 31667 // Manage the tile queue 31668 // Image loads are expensive and a limited resource, so try to use them
31669 // efficiently: 31670 // * When the view is static we allow a large number of parallel tile loads 31671 // to complete the frame as quickly as possible. 31672 // * When animating or interacting, image loads can cause janks, so we reduce 31673 // the maximum number of loads per frame and limit the number of parallel 31674 // tile loads to remain reactive to view changes and to reduce the chance of 31675 // loading tiles that will quickly disappear from view. 31676 const tileQueue = this.tileQueue_; 31677 if (!tileQueue.isEmpty()) { 31678 let maxTotalLoading = this.maxTilesLoading_; 31679 let maxNewLoads = maxTotalLoading; 31680 if (frameState) { 31681 const hints = frameState.viewHints; 31682 if (hints[ViewHint.ANIMATING] || hints[ViewHint.INTERACTING]) { 31683 const lowOnFrameBudget = Date.now() - frameState.time > 8; 31684 maxTotalLoading = lowOnFrameBudget ? 0 : 8; 31685 maxNewLoads = lowOnFrameBudget ? 0 : 2; 31686 } 31687 } 31688 if (tileQueue.getTilesLoading() < maxTotalLoading) { 31689 tileQueue.reprioritize(); // FIXME only call if view has changed 31690 tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); 31691 } 31692 } 31693 31694 if (frameState && this.renderer_ && !frameState.animate) { 31695 if (this.renderComplete_ === true) { 31696 if (this.hasListener(render_EventType.RENDERCOMPLETE)) { 31697 this.renderer_.dispatchRenderEvent( 31698 render_EventType.RENDERCOMPLETE, 31699 frameState 31700 ); 31701 } 31702 if (this.loaded_ === false) { 31703 this.loaded_ = true; 31704 this.dispatchEvent( 31705 new ol_MapEvent(MapEventType.LOADEND, this, frameState) 31706 ); 31707 } 31708 } else if (this.loaded_ === true) { 31709 this.loaded_ = false; 31710 this.dispatchEvent( 31711 new ol_MapEvent(MapEventType.LOADSTART, this, frameState) 31712 ); 31713 } 31714 } 31715 31716 const postRenderFunctions = this.postRenderFunctions_; 31717 for (let i = 0, ii = postRenderFunctions.length; i < ii; ++i) { 31718 postRenderFunctions[i](this, frameState); 31719 } 31720 postRenderFunctions.length = 0; 31721 } 31722 31723 /** 31724 * @private 31725 */ 31726 handleSizeChanged_() { 31727 if (this.getView() && !this.getView().getAnimating()) { 31728 this.getView().resolveConstraints(0); 31729 } 31730 31731 this.render(); 31732 } 31733 31734 /** 31735 * @private 31736 */ 31737 handleTargetChanged_() { 31738 if (this.mapBrowserEventHandler_) { 31739 for (let i = 0, ii = this.targetChangeHandlerKeys_.length; i < ii; ++i) { 31740 unlistenByKey(this.targetChangeHandlerKeys_[i]); 31741 } 31742 this.targetChangeHandlerKeys_ = null; 31743 this.viewport_.removeEventListener( 31744 EventType.CONTEXTMENU, 31745 this.boundHandleBrowserEvent_ 31746 ); 31747 this.viewport_.removeEventListener( 31748 EventType.WHEEL, 31749 this.boundHandleBrowserEvent_ 31750 ); 31751 this.mapBrowserEventHandler_.dispose(); 31752 this.mapBrowserEventHandler_ = null; 31753 removeNode(this.viewport_); 31754 } 31755 31756 // target may be undefined, null, a string or an Element. 31757 // If it's a string we convert it to an Element before proceeding. 31758 // If it's not now an Element we remove the viewport from the DOM. 31759 // If it's an Element we append the viewport element to it. 31760 31761 const targetElement = this.getTargetElement(); 31762 if (!targetElement) { 31763 if (this.renderer_) { 31764 clearTimeout(this.postRenderTimeoutHandle_); 31765 this.postRenderTimeoutHandle_ = undefined; 31766 this.postRenderFunctions_.length = 0; 31767 this.renderer_.dispose(); 31768 this.renderer_ = null; 31769 } 31770 if (this.animationDelayKey_) { 31771 cancelAnimationFrame(this.animationDelayKey_); 31772 this.animationDelayKey_ = undefined; 31773 } 31774 } else { 31775 targetElement.appendChild(this.viewport_); 31776 if (!this.renderer_) { 31777 this.renderer_ = new Composite(this); 31778 } 31779 31780 this.mapBrowserEventHandler_ = new ol_MapBrowserEventHandler( 31781 this, 31782 this.moveTolerance_ 31783 ); 31784 for (const key in ol_MapBrowserEventType) { 31785 this.mapBrowserEventHandler_.addEventListener( 31786 ol_MapBrowserEventType[key], 31787 this.handleMapBrowserEvent.bind(this) 31788 ); 31789 } 31790 this.viewport_.addEventListener( 31791 EventType.CONTEXTMENU, 31792 this.boundHandleBrowserEvent_, 31793 false 31794 ); 31795 this.viewport_.addEventListener( 31796 EventType.WHEEL, 31797 this.boundHandleBrowserEvent_, 31798 PASSIVE_EVENT_LISTENERS ? {passive: false} : false 31799 ); 31800 31801 const defaultView = this.getOwnerDocument().defaultView;
vendor: 5,116 bytes, lines 31802-32002
31802 const keyboardEventTarget = !this.keyboardEventTarget_ 31803 ? targetElement 31804 : this.keyboardEventTarget_; 31805 this.targetChangeHandlerKeys_ = [ 31806 listen( 31807 keyboardEventTarget, 31808 EventType.KEYDOWN, 31809 this.handleBrowserEvent, 31810 this 31811 ), 31812 listen( 31813 keyboardEventTarget, 31814 EventType.KEYPRESS, 31815 this.handleBrowserEvent, 31816 this 31817 ), 31818 listen(defaultView, EventType.RESIZE, this.updateSize, this), 31819 ]; 31820 } 31821 31822 this.updateSize(); 31823 // updateSize calls setSize, so no need to call this.render 31824 // ourselves here. 31825 } 31826 31827 /** 31828 * @private 31829 */ 31830 handleTileChange_() { 31831 this.render(); 31832 } 31833 31834 /** 31835 * @private 31836 */ 31837 handleViewPropertyChanged_() { 31838 this.render(); 31839 } 31840 31841 /** 31842 * @private 31843 */ 31844 handleViewChanged_() { 31845 if (this.viewPropertyListenerKey_) { 31846 unlistenByKey(this.viewPropertyListenerKey_); 31847 this.viewPropertyListenerKey_ = null; 31848 } 31849 if (this.viewChangeListenerKey_) { 31850 unlistenByKey(this.viewChangeListenerKey_); 31851 this.viewChangeListenerKey_ = null; 31852 } 31853 const view = this.getView(); 31854 if (view) { 31855 this.updateViewportSize_(); 31856 31857 this.viewPropertyListenerKey_ = listen( 31858 view, 31859 ObjectEventType.PROPERTYCHANGE, 31860 this.handleViewPropertyChanged_, 31861 this 31862 ); 31863 this.viewChangeListenerKey_ = listen( 31864 view, 31865 EventType.CHANGE, 31866 this.handleViewPropertyChanged_, 31867 this 31868 ); 31869 31870 view.resolveConstraints(0); 31871 } 31872 this.render(); 31873 } 31874 31875 /** 31876 * @private 31877 */ 31878 handleLayerGroupChanged_() { 31879 if (this.layerGroupPropertyListenerKeys_) { 31880 this.layerGroupPropertyListenerKeys_.forEach(unlistenByKey); 31881 this.layerGroupPropertyListenerKeys_ = null; 31882 } 31883 const layerGroup = this.getLayerGroup(); 31884 if (layerGroup) { 31885 this.handleLayerAdd_(new GroupEvent('addlayer', layerGroup)); 31886 this.layerGroupPropertyListenerKeys_ = [ 31887 listen(layerGroup, ObjectEventType.PROPERTYCHANGE, this.render, this), 31888 listen(layerGroup, EventType.CHANGE, this.render, this), 31889 listen(layerGroup, 'addlayer', this.handleLayerAdd_, this), 31890 listen(layerGroup, 'removelayer', this.handleLayerRemove_, this), 31891 ]; 31892 } 31893 this.render(); 31894 } 31895 31896 /** 31897 * @return {boolean} Is rendered. 31898 */ 31899 isRendered() { 31900 return !!this.frameState_; 31901 } 31902 31903 /** 31904 * @private 31905 */ 31906 animationDelay_() { 31907 this.animationDelayKey_ = undefined; 31908 this.renderFrame_(Date.now()); 31909 } 31910 31911 /** 31912 * Requests an immediate render in a synchronous manner. 31913 * @api 31914 */ 31915 renderSync() { 31916 if (this.animationDelayKey_) { 31917 cancelAnimationFrame(this.animationDelayKey_); 31918 } 31919 this.animationDelay_(); 31920 } 31921 31922 /** 31923 * Redraws all text after new fonts have loaded 31924 */ 31925 redrawText() { 31926 const layerStates = this.getLayerGroup().getLayerStatesArray(); 31927 for (let i = 0, ii = layerStates.length; i < ii; ++i) { 31928 const layer = layerStates[i].layer; 31929 if (layer.hasRenderer()) { 31930 layer.getRenderer().handleFontsChanged(); 31931 } 31932 } 31933 } 31934 31935 /** 31936 * Request a map rendering (at the next animation frame). 31937 * @api 31938 */ 31939 render() { 31940 if (this.renderer_ && this.animationDelayKey_ === undefined) { 31941 this.animationDelayKey_ = requestAnimationFrame(this.animationDelay_); 31942 } 31943 } 31944 31945 /** 31946 * Remove the given control from the map. 31947 * @param {import("./control/Control.js").default} control Control. 31948 * @return {import("./control/Control.js").default|undefined} The removed control (or undefined 31949 * if the control was not found). 31950 * @api 31951 */ 31952 removeControl(control) { 31953 return this.getControls().remove(control); 31954 } 31955 31956 /** 31957 * Remove the given interaction from the map. 31958 * @param {import("./interaction/Interaction.js").default} interaction Interaction to remove. 31959 * @return {import("./interaction/Interaction.js").default|undefined} The removed interaction (or 31960 * undefined if the interaction was not found). 31961 * @api 31962 */ 31963 removeInteraction(interaction) { 31964 return this.getInteractions().remove(interaction); 31965 } 31966 31967 /** 31968 * Removes the given layer from the map. 31969 * @param {import("./layer/Base.js").default} layer Layer. 31970 * @return {import("./layer/Base.js").default|undefined} The removed layer (or undefined if the 31971 * layer was not found). 31972 * @api 31973 */ 31974 removeLayer(layer) { 31975 const layers = this.getLayerGroup().getLayers(); 31976 return layers.remove(layer); 31977 } 31978 31979 /** 31980 * @param {import("./layer/Group.js").GroupEvent} event The layer remove event. 31981 * @private 31982 */ 31983 handleLayerRemove_(event) { 31984 removeLayerMapProperty(event.layer); 31985 } 31986 31987 /** 31988 * Remove the given overlay from the map. 31989 * @param {import("./Overlay.js").default} overlay Overlay. 31990 * @return {import("./Overlay.js").default|undefined} The removed overlay (or undefined 31991 * if the overlay was not found). 31992 * @api 31993 */ 31994 removeOverlay(overlay) { 31995 return this.getOverlays().remove(overlay); 31996 } 31997 31998 /** 31999 * @param {number} time Time. 32000 * @private 32001 */ 32002 renderFrame_(time) {
32003 const size = this.getSize(); 32004 const view = this.getView(); 32005 const previousFrameState = this.frameState_; 32006 /** @type {?FrameState} */ 32007 let frameState = null; 32008 if (size !== undefined && hasArea(size) && view && view.isDef()) { 32009 const viewHints = view.getHints( 32010 this.frameState_ ? this.frameState_.viewHints : undefined 32011 ); 32012 const viewState = view.getState(); 32013 frameState = { 32014 animate: false, 32015 coordinateToPixelTransform: this.coordinateToPixelTransform_, 32016 declutterTree: null, 32017 extent: getForViewAndSize( 32018 viewState.center, 32019 viewState.resolution, 32020 viewState.rotation, 32021 size 32022 ), 32023 index: this.frameIndex_++, 32024 layerIndex: 0, 32025 layerStatesArray: this.getLayerGroup().getLayerStatesArray(), 32026 pixelRatio: this.pixelRatio_, 32027 pixelToCoordinateTransform: this.pixelToCoordinateTransform_, 32028 postRenderFunctions: [], 32029 size: size, 32030 tileQueue: this.tileQueue_, 32031 time: time, 32032 usedTiles: {}, 32033 viewState: viewState, 32034 viewHints: viewHints, 32035 wantedTiles: {}, 32036 mapId: getUid(this), 32037 renderTargets: {}, 32038 }; 32039 if (viewState.nextCenter && viewState.nextResolution) { 32040 const rotation = isNaN(viewState.nextRotation) 32041 ? viewState.rotation 32042 : viewState.nextRotation; 32043 32044 frameState.nextExtent = getForViewAndSize( 32045 viewState.nextCenter, 32046 viewState.nextResolution, 32047 rotation, 32048 size 32049 ); 32050 } 32051 } 32052 32053 this.frameState_ = frameState; 32054 this.renderer_.renderFrame(frameState); 32055 32056 if (frameState) { 32057 if (frameState.animate) { 32058 this.render(); 32059 } 32060 Array.prototype.push.apply( 32061 this.postRenderFunctions_, 32062 frameState.postRenderFunctions 32063 ); 32064 32065 if (previousFrameState) { 32066 const moveStart = 32067 !this.previousExtent_ || 32068 (!extent_isEmpty(this.previousExtent_) && 32069 !extent_equals(frameState.extent, this.previousExtent_)); 32070 if (moveStart) { 32071 this.dispatchEvent( 32072 new ol_MapEvent(MapEventType.MOVESTART, this, previousFrameState) 32073 ); 32074 this.previousExtent_ = createOrUpdateEmpty(this.previousExtent_); 32075 } 32076 } 32077 32078 const idle = 32079 this.previousExtent_ && 32080 !frameState.viewHints[ViewHint.ANIMATING] && 32081 !frameState.viewHints[ViewHint.INTERACTING] && 32082 !extent_equals(frameState.extent, this.previousExtent_); 32083 32084 if (idle) { 32085 this.dispatchEvent( 32086 new ol_MapEvent(MapEventType.MOVEEND, this, frameState) 32087 ); 32088 clone(frameState.extent, this.previousExtent_); 32089 } 32090 } 32091 32092 this.dispatchEvent(new ol_MapEvent(MapEventType.POSTRENDER, this, frameState)); 32093 32094 this.renderComplete_ = 32095 this.hasListener(MapEventType.LOADSTART) || 32096 this.hasListener(MapEventType.LOADEND) || 32097 this.hasListener(render_EventType.RENDERCOMPLETE) 32098 ? !this.tileQueue_.getTilesLoading() && 32099 !this.tileQueue_.getCount() && 32100 !this.getLoadingOrNotReady() 32101 : undefined; 32102 32103 if (!this.postRenderTimeoutHandle_) { 32104 this.postRenderTimeoutHandle_ = setTimeout(() => { 32105 this.postRenderTimeoutHandle_ = undefined; 32106 this.handlePostRender(); 32107 }, 0); 32108 } 32109 } 32110 32111 /** 32112 * Sets the layergroup of this map. 32113 * @param {LayerGroup} layerGroup A layer group containing the layers in this map. 32114 * @observable 32115 * @api 32116 */ 32117 setLayerGroup(layerGroup) { 32118 const oldLayerGroup = this.getLayerGroup(); 32119 if (oldLayerGroup) { 32120 this.handleLayerRemove_(new GroupEvent('removelayer', oldLayerGroup)); 32121 } 32122 this.set(MapProperty.LAYERGROUP, layerGroup); 32123 } 32124 32125 /** 32126 * Set the size of this map. 32127 * @param {import("./size.js").Size|undefined} size The size in pixels of the map in the DOM. 32128 * @observable 32129 * @api 32130 */ 32131 setSize(size) { 32132 this.set(MapProperty.SIZE, size); 32133 } 32134 32135 /** 32136 * Set the target element to render this map into. 32137 * @param {HTMLElement|string} [target] The Element or id of the Element 32138 * that the map is rendered in. 32139 * @observable 32140 * @api 32141 */ 32142 setTarget(target) { 32143 this.set(MapProperty.TARGET, target); 32144 } 32145 32146 /** 32147 * Set the view for this map. 32148 * @param {View|Promise<import("./View.js").ViewOptions>} view The view that controls this map. 32149 * It is also possible to pass a promise that resolves to options for c
32149onstructing a view. This 32150 * alternative allows view properties to be resolved by sources or other components that load 32151 * view-related metadata. 32152 * @observable 32153 * @api 32154 */ 32155 setView(view) { 32156 if (!view || view instanceof ol_View) { 32157 this.set(MapProperty.VIEW, view); 32158 return; 32159 } 32160 this.set(MapProperty.VIEW, new ol_View()); 32161 32162 const map = this; 32163 view.then(function (viewOptions) { 32164 map.setView(new ol_View(viewOptions)); 32165 }); 32166 } 32167 32168 /** 32169 * Force a recalculation of the map viewport size. This should be called when 32170 * third-party code changes the size of the map viewport. 32171 * @api 32172 */ 32173 updateSize() { 32174 const targetElement = this.getTargetElement(); 32175 32176 let size = undefined; 32177 if (targetElement) { 32178 const computedStyle = getComputedStyle(targetElement); 32179 const width = 32180 targetElement.offsetWidth - 32181 parseFloat(computedStyle['borderLeftWidth']) - 32182 parseFloat(computedStyle['paddingLeft']) - 32183 parseFloat(computedStyle['paddingRight']) - 32184 parseFloat(computedStyle['borderRightWidth']); 32185 const height = 32186 targetElement.offsetHeight - 32187 parseFloat(computedStyle['borderTopWidth']) - 32188 parseFloat(computedStyle['paddingTop']) - 32189 parseFloat(computedStyle['paddingBottom']) - 32190 parseFloat(computedStyle['borderBottomWidth']); 32191 if (!isNaN(width) && !isNaN(height)) { 32192 size = [width, height]; 32193 if ( 32194 !hasArea(size) && 32195 !!( 32196 targetElement.offsetWidth || 32197 targetElement.offsetHeight || 32198 targetElement.getClientRects().length 32199 ) 32200 ) { 32201 // eslint-disable-next-line 32202 console.warn( 32203 "No map visible because the map container's width or height are 0." 32204 ); 32205 } 32206 } 32207 } 32208 32209 this.setSize(size); 32210 this.updateViewportSize_(); 32211 } 32212 32213 /** 32214 * Recomputes the viewport size and save it on the view object (if any) 32215 * @private 32216 */ 32217 updateViewportSize_() { 32218 const view = this.getView(); 32219 if (view) { 32220 let size = undefined; 32221 const computedStyle = getComputedStyle(this.viewport_); 32222 if (computedStyle.width && computedStyle.height) { 32223 size = [ 32224 parseInt(computedStyle.width, 10), 32225 parseInt(computedStyle.height, 10), 32226 ]; 32227 } 32228 view.setViewportSize(size); 32229 } 32230 } 32231} 32232 32233/** 32234 * @param {MapOptions} options Map options. 32235 * @return {MapOptionsInternal} Internal map options. 32236 */ 32237function createOptionsInternal(options) { 32238 /** 32239 * @type {HTMLElement|Document} 32240 */ 32241 let keyboardEventTarget = null; 32242 if (options.keyboardEventTarget !== undefined) { 32243 keyboardEventTarget = 32244 typeof options.keyboardEventTarget === 'string' 32245 ? document.getElementById(options.keyboardEventTarget) 32246 : options.keyboardEventTarget; 32247 } 32248 32249 /** 32250 * @type {Object<string, *>} 32251 */ 32252 const values = {}; 32253 32254 const layerGroup = 32255 options.layers && 32256 typeof (/** @type {?} */ (options.layers).getLayers) === 'function' 32257 ? /** @type {LayerGroup} */ (options.layers) 32258 : new Group({ 32259 layers: 32260 /** @type {Collection<import("./layer/Base.js").default>|Array<import("./layer/Base.js").default>} */ ( 32261 options.layers 32262 ), 32263 }); 32264 values[MapProperty.LAYERGROUP] = layerGroup; 32265 32266 values[MapProperty.TARGET] = options.target; 32267 32268 values[MapProperty.VIEW] = 32269 options.view instanceof ol_View ? options.view : new ol_View(); 32270 32271 /** @type {Collection<import("./control/Control.js").default>} */ 32272 let controls; 32273 if (options.controls !== undefined) { 32274 if (Array.isArray(options.controls)) { 32275 controls = new ol_Collection(options.controls.slice()); 32276 } else { 32277 asserts_assert( 32278 typeof (/** @type {?} */ (options.controls).getArray) === 'function', 32279 47 32280 ); // Expected `controls` to be an array or an `import("./Collection.js").Collection` 32281 controls = options.controls; 32282 } 32283 } 32284 32285 /** @type {Collection<import("./interaction/Interaction").default>} */ 32286 let interactions; 32287 if (options.interactions !== undefined) { 32288 if (Array.isArray(options.interactions)) { 32289 interactions = new ol_Collection(options.interactions.slice()); 32290 } else { 32291 asserts_assert( 32292 typeof (/** @type {?} */ (options.interactions).getArray) === 32293 'function', 32294 48 32295 ); // Expected `interactions` to be an array or an `import("./Collection.js").Collection` 32296 interactions = options.interactions; 32297 } 32298 } 32299 32300 /** @type {Collection<import("./Overlay.js").default>} */ 32301 let overlays; 32302 if (options.overlays !== undefined) { 32303 if (Array.isArray(options.overlays)) { 32304 overlays = new ol_Collection(options.overlays.slice()); 32305 } else { 32306 asserts_assert( 32307 typeof (/** @type {?} */ (options.overlays).getArray) === 'function', 32308 49 32309 ); // Expected `overlays` to be an array or an `import("./Collection.js").Collection` 32310 overlays = options.overlays; 32311 } 32312 } else { 32313 overlays = new ol_Collection(); 32314 } 32315 32316 return { 32317 controls: controls, 32318 interactions: interactions, 32319 keyboardEventTarget: keyboardEventTarget, 32320 overlays: overlays, 32321 values: values, 32322 }; 32323} 32324/* harmony default export */ const ol_Map = (Map_Map); 32325 32326// EXTERNAL MODULE: ./node_modules/rbush/rbush.min.js 32327var rbush_min = __webpack_require__(582); 32328;// CONCATENATED MODULE: ./node_modules/ol/ImageState.js 32329/** 32330 * @module ol/ImageState 32331 */ 32332 32333/** 32334 * @enum {number} 32335 */ 32336/* harmony default export */ const ol_ImageState = ({ 32337 IDLE: 0, 32338 LOADING: 1, 32339 LOADED: 2, 32340 ERROR: 3, 32341 EMPTY: 4, 32342}); 32343 32344;// CONCATENATED MODULE: ./node_modules/ol/style/Image.js 32345/** 32346 * @module ol/style/Image 32347 */ 32348 32349 32350 32351/** 32352 * @typedef {Object} Options 32353 * @property {number} opacity Opacity. 32354 * @property {boolean} rotateWithView If the image should get rotated with the view. 32355 * @property {number} rotation Rotation. 32356 * @property {number|import("../size.js").Size} scale Scale. 32357 * @property {Array<number>} displacement Displacement. 32358 * @property {"declutter"|"obstacle"|"none"|undefined} declutterMode Declutter mode: `declutter`, `obstacle`, 'none */ 32359 32360/** 32361 * @classdesc 32362 * A base class used for creating subclasses and not instantiated in 32363 * apps. Base class for {@link module:ol/style/Icon~Icon}, {@link module:ol/style/Circle~CircleStyle} and 32364 * {@link module:ol/style/RegularShape~RegularShape}. 32365 * @abstract 32366 * @api 32367 */ 32368class ImageStyle { 32369 /** 32370 * @param {Options} options Options. 32371 */ 32372 constructor(options) { 32373 /** 32374 * @private 32375 * @type {number} 32376 */ 32377 this.opacity_ = options.opacity; 32378 32379 /** 32380 * @private 32381 * @type {boolean} 32382 */ 32383 this.rotateWithView_ = options.rotateWithView; 32384 32385 /** 32386 * @private 32387 * @type {number} 32388 */ 32389 this.rotation_ = options.rotation; 32390 32391 /** 32392 * @private 32393 * @type {number|import("../size.js").Size} 32394 */ 32395 this.scale_ = options.scale; 32396 32397 /** 32398 * @private 32399 * @type {import("../size.js").Size} 32400 */ 32401 this.scaleArray_ = toSize(options.scale); 32402 32403 /** 32404 * @private 32405 * @type {Array<number>} 32406 */ 32407 this.displacement_ = options.displacement; 32408 32409 /** 32410 * @private 32411 * @type {"declutter"|"obstacle"|"none"|undefined} 32412 */ 32413 this.declutterMode_ = options.declutterMode; 32414 } 32415 32416 /** 32417 * Clones the style. 32418 * @return {ImageStyle} The cloned style. 32419 * @api 32420 */ 32421 clone() {
32422 const scale = this.getScale(); 32423 return new ImageStyle({ 32424 opacity: this.getOpacity(), 32425 scale: Array.isArray(scale) ? scale.slice() : scale, 32426 rotation: this.getRotation(), 32427 rotateWithView: this.getRotateWithView(), 32428 displacement: this.getDisplacement().slice(), 32429 declutterMode: this.getDeclutterMode(), 32430 }); 32431 } 32432 32433 /** 32434 * Get the symbolizer opacity. 32435 * @return {number} Opacity. 32436 * @api 32437 */ 32438 getOpacity() { 32439 return this.opacity_; 32440 } 32441 32442 /** 32443 * Determine whether the symbolizer rotates with the map. 32444 * @return {boolean} Rotate with map. 32445 * @api 32446 */ 32447 getRotateWithView() { 32448 return this.rotateWithView_; 32449 } 32450 32451 /** 32452 * Get the symoblizer rotation. 32453 * @return {number} Rotation. 32454 * @api 32455 */ 32456 getRotation() { 32457 return this.rotation_; 32458 } 32459 32460 /** 32461 * Get the symbolizer scale. 32462 * @return {number|import("../size.js").Size} Scale. 32463 * @api 32464 */ 32465 getScale() { 32466 return this.scale_; 32467 } 32468 32469 /** 32470 * Get the symbolizer scale array. 32471 * @return {import("../size.js").Size} Scale array. 32472 */ 32473 getScaleArray() { 32474 return this.scaleArray_; 32475 } 32476 32477 /** 32478 * Get the displacement of the shape 32479 * @return {Array<number>} Shape's center displacement 32480 * @api 32481 */ 32482 getDisplacement() { 32483 return this.displacement_; 32484 } 32485 32486 /** 32487 * Get the declutter mode of the shape 32488 * @return {"declutter"|"obstacle"|"none"|undefined} Shape's declutter mode 32489 * @api 32490 */ 32491 getDeclutterMode() { 32492 return this.declutterMode_; 32493 } 32494 32495 /** 32496 * Get the anchor point in pixels. The anchor determines the center point for the 32497 * symbolizer. 32498 * @abstract 32499 * @return {Array<number>} Anchor. 32500 */ 32501 getAnchor() { 32502 return util_abstract(); 32503 } 32504 32505 /** 32506 * Get the image element for the symbolizer. 32507 * @abstract 32508 * @param {number} pixelRatio Pixel ratio. 32509 * @return {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} Image element. 32510 */ 32511 getImage(pixelRatio) { 32512 return util_abstract(); 32513 } 32514 32515 /** 32516 * @abstract 32517 * @return {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} Image element. 32518 */ 32519 getHitDetectionImage() { 32520 return util_abstract(); 32521 } 32522 32523 /** 32524 * Get the image pixel ratio. 32525 * @param {number} pixelRatio Pixel ratio. 32526 * @return {number} Pixel ratio. 32527 */ 32528 getPixelRatio(pixelRatio) { 32529 return 1; 32530 } 32531 32532 /** 32533 * @abstract 32534 * @return {import("../ImageState.js").default} Image state. 32535 */ 32536 getImageState() { 32537 return util_abstract(); 32538 } 32539 32540 /** 32541 * @abstract 32542 * @return {import("../size.js").Size} Image size. 32543 */ 32544 getImageSize() { 32545 return util_abstract(); 32546 } 32547 32548 /** 32549 * Get the origin of the symbolizer. 32550 * @abstract 32551 * @return {Array<number>} Origin. 32552 */ 32553 getOrigin() { 32554 return util_abstract(); 32555 } 32556 32557 /** 32558 * Get the size of the symbolizer (in pixels). 32559 * @abstract 32560 * @return {import("../size.js").Size} Size. 32561 */ 32562 getSize() { 32563 return util_abstract(); 32564 } 32565 32566 /** 32567 * Set the displacement. 32568 * 32569 * @param {Array<number>} displacement Displacement. 32570 * @api 32571 */ 32572 setDisplacement(displacement) { 32573 this.displacement_ = displacement; 32574 } 32575 32576 /** 32577 * Set the opacity. 32578 * 32579 * @param {number} opacity Opacity. 32580 * @api 32581 */ 32582 setOpacity(opacity) { 32583 this.opacity_ = opacity; 32584 } 32585 32586 /** 32587 * Set whether to rotate the style with the view. 32588 * 32589 * @param {boolean} rotateWithView Rotate with map. 32590 * @api 32591 */ 32592 setRotateWithView(rotateWithView) { 32593 this.rotateWithView_ = rotateWithView; 32594 } 32595 32596 /** 32597 * Set the rotation. 32598 * 32599 * @param {number} rotation Rotation. 32600 * @api 32601 */ 32602 setRotation(rotation) { 32603 this.rotation_ = rotation; 32604 } 32605 /** 32606 * Set the scale. 32607 * 32608 * @param {number|import("../size.js").Size} scale Scale. 32609 * @api 32610 */ 32611 setScale(scale) { 32612 this.scale_ = scale; 32613 this.scaleArray_ = toSize(scale); 32614 } 32615 32616 /** 32617 * @abstract 32618 * @param {function(import("../events/Event.js").default): void} listener Listener function. 32619 */ 32620 listenImageChange(listener) { 32621 util_abstract(); 32622 } 32623 32624 /** 32625 * Load not yet loaded URI. 32626 * @abstract 32627 */ 32628 load() { 32629 util_abstract(); 32630 } 32631 32632 /** 32633 * @abstract 32634 * @param {function(import("../events/Event.js").default): void} listener Listener function. 32635 */ 32636 unlistenImageChange(listener) { 32637 util_abstract(); 32638 } 32639} 32640 32641/* harmony default export */ const style_Image = (ImageStyle); 32642 32643;// CONCATENATED MODULE: ./node_modules/ol/colorlike.js 32644/** 32645 * @module ol/colorlike 32646 */ 32647 32648 32649/** 32650 * A type accepted by CanvasRenderingContext2D.fillStyle 32651 * or CanvasRenderingContext2D.strokeStyle. 32652 * Represents a color, pattern, or gradient. The origin for patterns and 32653 * gradients as fill style is an increment of 512 css pixels from map coordinate 32654 * `[0, 0]`. For seamless repeat patterns, width and height of the pattern image 32655 * must be a factor of two (2, 4, 8, ..., 512). 32656 * 32657 * @typedef {string|CanvasPattern|CanvasGradient} ColorLike 32658 * @api 32659 */ 32660 32661/** 32662 * @param {import("./color.js").Color|ColorLike} color Color. 32663 * @return {ColorLike} The color as an {@link ol/colorlike~ColorLike}. 32664 * @api 32665 */ 32666function asColorLike(color) { 32667 if (Array.isArray(color)) { 32668 return color_toString(color); 32669 } else { 32670 return color; 32671 } 32672} 32673 32674;// CONCATENATED MODULE: ./node_modules/ol/style/RegularShape.js 32675/** 32676 * @module ol/style/RegularShape 32677 */ 32678 32679 32680 32681 32682 32683 32684 32685 32686/** 32687 * Specify radius for regular polygons, or radius1 and radius2 for stars. 32688 * @typedef {Object} Options 32689 * @property {import("./Fill.js").default} [fill] Fill style. 32690 * @property {number} points Number of points for stars and regular polygons. In case of a polygon, the number of points 32691 * is the number of sides. 32692 * @property {number} [radius] Radius of a regular polygon. 32693 * @property {number} [radius1] First radius of a star. Ignored if radius is set. 32694 * @property {number} [radius2] Second radius of a star. 32695 * @property {number} [angle=0] Shape's angle in radians. A value of 0 will have one of the shape's points facing up. 32696 * @property {Array<number>} [displacement=[0, 0]] Displacement of the shape in pixels. 32697 * Positive values will shift the shape right and up. 32698 * @property {import("./Stroke.js").default} [stroke] Stroke style. 32699 * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise). 32700 * @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view. 32701 * @property {number|import("../size.js").Size} [scale=1] Scale. Unless two dimensional scaling is required a better 32702 * result may be obtained with appropriate settings for `radius`, `radius1` and `radius2`. 32703 * @property {"declutter"|"obstacle"|"none"|undefined} [declutterMode] Declutter mode. 32704 */ 32705 32706/** 32707 * @typedef {Object} RenderOptions 32708 * @property {import("../colorlike.js").ColorLike} [strokeStyle] StrokeStyle. 32709 * @property {number} strokeWidth StrokeWidth. 32710 * @property {number} size Size. 32711 * @property {Array<number>|null} lineDash LineDash. 32712 * @property {number} lineDashOffset LineDashOffset. 32713 * @property {CanvasLineJoin}
32713 lineJoin LineJoin. 32714 * @property {number} miterLimit MiterLimit. 32715 */ 32716 32717/** 32718 * @classdesc 32719 * Set regular shape style for vector features. The resulting shape will be 32720 * a regular polygon when `radius` is provided, or a star when `radius1` and 32721 * `radius2` are provided. 32722 * @api 32723 */ 32724class RegularShape extends style_Image { 32725 /** 32726 * @param {Options} options Options. 32727 */ 32728 constructor(options) { 32729 /** 32730 * @type {boolean} 32731 */ 32732 const rotateWithView = 32733 options.rotateWithView !== undefined ? options.rotateWithView : false; 32734 32735 super({ 32736 opacity: 1, 32737 rotateWithView: rotateWithView, 32738 rotation: options.rotation !== undefined ? options.rotation : 0, 32739 scale: options.scale !== undefined ? options.scale : 1, 32740 displacement: 32741 options.displacement !== undefined ? options.displacement : [0, 0], 32742 declutterMode: options.declutterMode, 32743 }); 32744 32745 /** 32746 * @private 32747 * @type {Object<number, HTMLCanvasElement>} 32748 */ 32749 this.canvas_ = undefined; 32750 32751 /** 32752 * @private 32753 * @type {HTMLCanvasElement} 32754 */ 32755 this.hitDetectionCanvas_ = null; 32756 32757 /** 32758 * @private 32759 * @type {import("./Fill.js").default} 32760 */ 32761 this.fill_ = options.fill !== undefined ? options.fill : null; 32762 32763 /** 32764 * @private 32765 * @type {Array<number>} 32766 */ 32767 this.origin_ = [0, 0]; 32768 32769 /** 32770 * @private 32771 * @type {number} 32772 */ 32773 this.points_ = options.points; 32774 32775 /** 32776 * @protected 32777 * @type {number} 32778 */ 32779 this.radius_ = 32780 options.radius !== undefined ? options.radius : options.radius1; 32781 32782 /** 32783 * @private 32784 * @type {number|undefined} 32785 */ 32786 this.radius2_ = options.radius2; 32787 32788 /** 32789 * @private 32790 * @type {number} 32791 */ 32792 this.angle_ = options.angle !== undefined ? options.angle : 0; 32793 32794 /** 32795 * @private 32796 * @type {import("./Stroke.js").default} 32797 */ 32798 this.stroke_ = options.stroke !== undefined ? options.stroke : null; 32799 32800 /** 32801 * @private 32802 * @type {import("../size.js").Size} 32803 */ 32804 this.size_ = null; 32805 32806 /** 32807 * @private 32808 * @type {RenderOptions} 32809 */ 32810 this.renderOptions_ = null; 32811 32812 this.render(); 32813 } 32814 32815 /** 32816 * Clones the style. 32817 * @return {RegularShape} The cloned style. 32818 * @api 32819 */ 32820 clone() { 32821 const scale = this.getScale(); 32822 const style = new RegularShape({ 32823 fill: this.getFill() ? this.getFill().clone() : undefined, 32824 points: this.getPoints(), 32825 radius: this.getRadius(), 32826 radius2: this.getRadius2(), 32827 angle: this.getAngle(), 32828 stroke: this.getStroke() ? this.getStroke().clone() : undefined, 32829 rotation: this.getRotation(), 32830 rotateWithView: this.getRotateWithView(), 32831 scale: Array.isArray(scale) ? scale.slice() : scale, 32832 displacement: this.getDisplacement().slice(), 32833 declutterMode: this.getDeclutterMode(), 32834 }); 32835 style.setOpacity(this.getOpacity()); 32836 return style; 32837 } 32838 32839 /** 32840 * Get the anchor point in pixels. The anchor determines the center point for the 32841 * symbolizer. 32842 * @return {Array<number>} Anchor. 32843 * @api 32844 */ 32845 getAnchor() { 32846 const size = this.size_; 32847 if (!size) { 32848 return null; 32849 } 32850 const displacement = this.getDisplacement(); 32851 const scale = this.getScaleArray(); 32852 // anchor is scaled by renderer but displacement should not be scaled 32853 // so divide by scale here 32854 return [ 32855 size[0] / 2 - displacement[0] / scale[0], 32856 size[1] / 2 + displacement[1] / scale[1], 32857 ]; 32858 } 32859 32860 /** 32861 * Get the angle used in generating the shape. 32862 * @return {number} Shape's rotation in radians. 32863 * @api 32864 */ 32865 getAngle() { 32866 return this.angle_; 32867 } 32868 32869 /** 32870 * Get the fill style for the shape. 32871 * @return {import("./Fill.js").default} Fill style. 32872 * @api 32873 */ 32874 getFill() { 32875 return this.fill_; 32876 } 32877 32878 /** 32879 * Set the fill style. 32880 * @param {import("./Fill.js").default} fill Fill style. 32881 * @api 32882 */ 32883 setFill(fill) { 32884 this.fill_ = fill; 32885 this.render(); 32886 } 32887 32888 /** 32889 * @return {HTMLCanvasElement} Image element. 32890 */ 32891 getHitDetectionImage() { 32892 if (!this.hitDetectionCanvas_) { 32893 this.createHitDetectionCanvas_(this.renderOptions_); 32894 } 32895 return this.hitDetectionCanvas_; 32896 } 32897 32898 /** 32899 * Get the image icon. 32900 * @param {number} pixelRatio Pixel ratio. 32901 * @return {HTMLCanvasElement} Image or Canvas element. 32902 * @api 32903 */ 32904 getImage(pixelRatio) { 32905 let image = this.canvas_[pixelRatio]; 32906 if (!image) { 32907 const renderOptions = this.renderOptions_; 32908 const context = createCanvasContext2D( 32909 renderOptions.size * pixelRatio, 32910 renderOptions.size * pixelRatio 32911 ); 32912 this.draw_(renderOptions, context, pixelRatio); 32913 32914 image = context.canvas; 32915 this.canvas_[pixelRatio] = image; 32916 } 32917 return image; 32918 } 32919 32920 /** 32921 * Get the image pixel ratio. 32922 * @param {number} pixelRatio Pixel ratio. 32923 * @return {number} Pixel ratio. 32924 */ 32925 getPixelRatio(pixelRatio) { 32926 return pixelRatio; 32927 } 32928 32929 /** 32930 * @return {import("../size.js").Size} Image size. 32931 */ 32932 getImageSize() { 32933 return this.size_; 32934 } 32935 32936 /** 32937 * @return {import("../ImageState.js").default} Image state. 32938 */ 32939 getImageState() { 32940 return ol_ImageState.LOADED; 32941 } 32942 32943 /** 32944 * Get the origin of the symbolizer. 32945 * @return {Array<number>} Origin. 32946 * @api 32947 */ 32948 getOrigin() { 32949 return this.origin_; 32950 } 32951 32952 /** 32953 * Get the number of points for generating the shape. 32954 * @return {number} Number of points for stars and regular polygons. 32955 * @api 32956 */ 32957 getPoints() { 32958 return this.points_; 32959 } 32960 32961 /**
32962 * Get the (primary) radius for the shape. 32963 * @return {number} Radius. 32964 * @api 32965 */ 32966 getRadius() { 32967 return this.radius_; 32968 } 32969 32970 /** 32971 * Get the secondary radius for the shape. 32972 * @return {number|undefined} Radius2. 32973 * @api 32974 */ 32975 getRadius2() { 32976 return this.radius2_; 32977 } 32978 32979 /** 32980 * Get the size of the symbolizer (in pixels). 32981 * @return {import("../size.js").Size} Size. 32982 * @api 32983 */ 32984 getSize() { 32985 return this.size_; 32986 } 32987 32988 /** 32989 * Get the stroke style for the shape. 32990 * @return {import("./Stroke.js").default} Stroke style. 32991 * @api 32992 */ 32993 getStroke() { 32994 return this.stroke_; 32995 } 32996 32997 /** 32998 * Set the stroke style. 32999 * @param {import("./Stroke.js").default} stroke Stroke style. 33000 * @api 33001 */ 33002 setStroke(stroke) { 33003 this.stroke_ = stroke; 33004 this.render(); 33005 } 33006 33007 /** 33008 * @param {function(import("../events/Event.js").default): void} listener Listener function. 33009 */ 33010 listenImageChange(listener) {} 33011 33012 /** 33013 * Load not yet loaded URI. 33014 */ 33015 load() {} 33016 33017 /** 33018 * @param {function(import("../events/Event.js").default): void} listener Listener function. 33019 */ 33020 unlistenImageChange(listener) {} 33021 33022 /** 33023 * Calculate additional canvas size needed for the miter. 33024 * @param {string}
33024 lineJoin Line join 33025 * @param {number} strokeWidth Stroke width 33026 * @param {number} miterLimit Miter limit 33027 * @return {number} Additional canvas size needed 33028 * @private 33029 */ 33030 calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit) { 33031 if ( 33032 strokeWidth === 0 || 33033 this.points_ === Infinity || 33034 (lineJoin !== 'bevel' && lineJoin !== 'miter') 33035 ) { 33036 return strokeWidth; 33037 } 33038 // m | ^ 33039 // i | |\ . 33040 // t >| #\ 33041 // e | |\ \ . 33042 // r \s\ 33043 // | \t\ . . 33044 // \r\ . . 33045 // | \o\ . . . . . 33046 // e \k\ . . . . 33047 // | \e\ . . . . . 33048 // d \ \ . . . . 33049 // | _ _a_ _\# . . . 33050 // r1 / ` . . 33051 // | . . 33052 // b / . . 33053 // | . . 33054 // / r2 . . 33055 // | . . 33056 // / . . 33057 // |α . . 33058 // / . . 33059 // ° center 33060 let r1 = this.radius_; 33061 let r2 = this.radius2_ === undefined ? r1 : this.radius2_; 33062 if (r1 < r2) { 33063 const tmp = r1; 33064 r1 = r2; 33065 r2 = tmp; 33066 } 33067 const points = 33068 this.radius2_ === undefined ? this.points_ : this.points_ * 2; 33069 const alpha = (2 * Math.PI) / points; 33070 const a = r2 * Math.sin(alpha); 33071 const b = Math.sqrt(r2 * r2 - a * a); 33072 const d = r1 - b; 33073 const e = Math.sqrt(a * a + d * d); 33074 const miterRatio = e / a; 33075 if (lineJoin === 'miter' && miterRatio <= miterLimit) { 33076 return miterRatio * strokeWidth; 33077 } 33078 // Calculate the distnce from center to the stroke corner where 33079 // it was cut short because of the miter limit. 33080 // l 33081 // ----+---- <= distance from center to here is maxr 33082 // /####|k ##\ 33083 // /#####^#####\ 33084 // /#### /+\# s #\ 33085 // /### h/+++\# t #\ 33086 // /### t/+++++\# r #\ 33087 // /### a/+++++++\# o #\ 33088 // /### p/++ fill +\# k #\ 33089 ///#### /+++++^+++++\# e #\ 33090 //#####/+++++/+\+++++\#####\ 33091 const k = strokeWidth / 2 / miterRatio; 33092 const l = (strokeWidth / 2) * (d / e); 33093 const maxr = Math.sqrt((r1 + k) * (r1 + k) + l * l); 33094 const bevelAdd = maxr - r1; 33095 if (this.radius2_ === undefined || lineJoin === 'bevel') { 33096 return bevelAdd * 2; 33097 } 33098 // If outer miter is over the miter limit the inner miter may reach through the 33099 // center and be longer than the bevel, same calculation as above but swap r1 / r2. 33100 const aa = r1 * Math.sin(alpha); 33101 const bb = Math.sqrt(r1 * r1 - aa * aa); 33102 const dd = r2 - bb; 33103 const ee = Math.sqrt(aa * aa + dd * dd); 33104 const innerMiterRatio = ee / aa; 33105 if (innerMiterRatio <= miterLimit) { 33106 const innerLength = (innerMiterRatio * strokeWidth) / 2 - r2 - r1; 33107 return 2 * Math.max(bevelAdd, innerLength); 33108 } 33109 return bevelAdd * 2; 33110 } 33111 33112 /** 33113 * @return {RenderOptions} The render options 33114 * @protected 33115 */ 33116 createRenderOptions() { 33117 let lineJoin = defaultLineJoin; 33118 let miterLimit = 0; 33119 let lineDash = null; 33120 let lineDashOffset = 0; 33121 let strokeStyle; 33122 let strokeWidth = 0; 33123 33124 if (this.stroke_) { 33125 strokeStyle = this.stroke_.getColor(); 33126 if (strokeStyle === null) { 33127 strokeStyle = defaultStrokeStyle; 33128 } 33129 strokeStyle = asColorLike(strokeStyle); 33130 strokeWidth = this.stroke_.getWidth(); 33131 if (strokeWidth === undefined) { 33132 strokeWidth = defaultLineWidth; 33133 } 33134 lineDash = this.stroke_.getLineDash(); 33135 lineDashOffset = this.stroke_.getLineDashOffset(); 33136 lineJoin = this.stroke_.getLineJoin(); 33137 if (lineJoin === undefined) { 33138 lineJoin = defaultLineJoin; 33139 } 33140 miterLimit = this.stroke_.getMiterLimit(); 33141 if (miterLimit === undefined) { 33142 miterLimit = defaultMiterLimit; 33143 } 33144 } 33145 33146 const add = this.calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit);
33147 const maxRadius = Math.max(this.radius_, this.radius2_ || 0); 33148 const size = Math.ceil(2 * maxRadius + add); 33149 33150 return { 33151 strokeStyle: strokeStyle, 33152 strokeWidth: strokeWidth, 33153 size: size, 33154 lineDash: lineDash, 33155 lineDashOffset: lineDashOffset, 33156 lineJoin: lineJoin, 33157 miterLimit: miterLimit, 33158 }; 33159 } 33160 33161 /** 33162 * @protected 33163 */ 33164 render() { 33165 this.renderOptions_ = this.createRenderOptions(); 33166 const size = this.renderOptions_.size; 33167 this.canvas_ = {}; 33168 this.size_ = [size, size]; 33169 } 33170 33171 /** 33172 * @private 33173 * @param {RenderOptions} renderOptions Render options. 33174 * @param {CanvasRenderingContext2D} context The rendering context. 33175 * @param {number} pixelRatio The pixel ratio. 33176 */ 33177 draw_(renderOptions, context, pixelRatio) { 33178 context.scale(pixelRatio, pixelRatio); 33179 // set origin to canvas center 33180 context.translate(renderOptions.size / 2, renderOptions.size / 2); 33181 33182 this.createPath_(context); 33183 33184 if (this.fill_) { 33185 let color = this.fill_.getColor(); 33186 if (color === null) { 33187 color = defaultFillStyle; 33188 } 33189 context.fillStyle = asColorLike(color); 33190 context.fill(); 33191 } 33192 if (this.stroke_) { 33193 context.strokeStyle = renderOptions.strokeStyle; 33194 context.lineWidth = renderOptions.strokeWidth; 33195 if (renderOptions.lineDash) { 33196 context.setLineDash(renderOptions.lineDash); 33197 context.lineDashOffset = renderOptions.lineDashOffset; 33198 } 33199 context.lineJoin = renderOptions.lineJoin; 33200 context.miterLimit = renderOptions.miterLimit; 33201 context.stroke(); 33202 } 33203 } 33204 33205 /** 33206 * @private 33207 * @param {RenderOptions} renderOptions Render options. 33208 */ 33209 createHitDetectionCanvas_(renderOptions) { 33210 if (this.fill_) { 33211 let color = this.fill_.getColor(); 33212 33213 // determine if fill is transparent (or pattern or gradient) 33214 let opacity = 0; 33215 if (typeof color === 'string') { 33216 color = asArray(color); 33217 } 33218 if (color === null) { 33219 opacity = 1; 33220 } else if (Array.isArray(color)) { 33221 opacity = color.length === 4 ? color[3] : 1; 33222 } 33223 if (opacity === 0) { 33224 // if a transparent fill style is set, create an extra hit-detection image 33225 // with a default fill style 33226 const context = createCanvasContext2D( 33227 renderOptions.size, 33228 renderOptions.size 33229 ); 33230 this.hitDetectionCanvas_ = context.canvas; 33231 33232 this.drawHitDetectionCanvas_(renderOptions, context); 33233 } 33234 } 33235 if (!this.hitDetectionCanvas_) { 33236 this.hitDetectionCanvas_ = this.getImage(1); 33237 } 33238 } 33239 33240 /** 33241 * @private 33242 * @param {CanvasRenderingContext2D} context The context to draw in. 33243 */ 33244 createPath_(context) { 33245 let points = this.points_; 33246 const radius = this.radius_; 33247 if (points === Infinity) { 33248 context.arc(0, 0, radius, 0, 2 * Math.PI); 33249 } else { 33250 const radius2 = this.radius2_ === undefined ? radius : this.radius2_; 33251 if (this.radius2_ !== undefined) { 33252 points *= 2; 33253 } 33254 const startAngle = this.angle_ - Math.PI / 2; 33255 const step = (2 * Math.PI) / points; 33256 for (let i = 0; i < points; i++) { 33257 const angle0 = startAngle + i * step; 33258 const radiusC = i % 2 === 0 ? radius : radius2; 33259 context.lineTo(radiusC * Math.cos(angle0), radiusC * Math.sin(angle0)); 33260 } 33261 context.closePath(); 33262 } 33263 } 33264 33265 /** 33266 * @private 33267 * @param {RenderOptions} renderOptions Render options. 33268 * @param {CanvasRenderingContext2D} context The context. 33269 */ 33270 drawHitDetectionCanvas_(renderOptions, context) { 33271 // set origin to canvas center 33272 context.translate(renderOptions.size / 2, renderOptions.size / 2); 33273 33274 this.createPath_(context); 33275 33276 context.fillStyle = defaultFillStyle; 33277 context.fill(); 33278 if (this.stroke_) { 33279 context.strokeStyle = renderOptions.strokeStyle; 33280 context.lineWidth = renderOptions.strokeWidth; 33281 if (renderOptions.lineDash) { 33282 context.setLineDash(renderOptions.lineDash); 33283 context.lineDashOffset = renderOptions.lineDashOffset; 33284 } 33285 context.lineJoin = renderOptions.lineJoin; 33286 context.miterLimit = renderOptions.miterLimit; 33287 context.stroke(); 33288 } 33289 } 33290} 33291 33292/* harmony default export */ const style_RegularShape = (RegularShape); 33293 33294;// CONCATENATED MODULE: ./node_modules/ol/style/Circle.js 33295/** 33296 * @module ol/style/Circle 33297 */ 33298 33299 33300 33301/** 33302 * @typedef {Object} Options 33303 * @property {import("./Fill.js").default} [fill] Fill style. 33304 * @property {number} radius Circle radius. 33305 * @property {import("./Stroke.js").default} [stroke] Stroke style. 33306 * @property {Array<number>} [displacement=[0,0]] displacement 33307 * @property {number|import("../size.js").Size} [scale=1] Scale. A two dimensional scale will produce an ellipse. 33308 * Unless two dimensional scaling is required a better result may be obtained with an appropriate setting for `radius`. 33309 * @property {number} [rotation=0] Rotation in radians 33310 * (positive rotation clockwise, meaningful only when used in conjunction with a two dimensional scale). 33311 * @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view 33312 * (meaningful only when used in conjunction with a two dimensional scale). 33313 * @property {"declutter"|"obstacle"|"none"|undefined} [declutterMode] Declutter mode 33314 */ 33315 33316/** 33317 * @classdesc 33318 * Set circle style for vector features. 33319 * @api 33320 */ 33321class Circle_CircleStyle extends style_RegularShape { 33322 /** 33323 * @param {Options} [options] Options. 33324 */ 33325 constructor(options) { 33326 options = options ? options : {radius: 5}; 33327 33328 super({ 33329 points: Infinity, 33330 fill: options.fill, 33331 radius: options.radius, 33332 stroke: options.stroke, 33333 scale: options.scale !== undefined ? options.scale : 1, 33334 rotation: options.rotation !== undefined ? options.rotation : 0, 33335 rotateWithView: 33336 options.rotateWithView !== undefined ? options.rotateWithView : false, 33337 displacement: 33338 options.displacement !== undefined ? options.displacement : [0, 0], 33339 declutterMode: options.declutterMode, 33340 }); 33341 } 33342 33343 /** 33344 * Clones the style. 33345 * @return {CircleStyle} The cloned style. 33346 * @api 33347 */ 33348 clone() {
33349 const scale = this.getScale(); 33350 const style = new Circle_CircleStyle({ 33351 fill: this.getFill() ? this.getFill().clone() : undefined, 33352 stroke: this.getStroke() ? this.getStroke().clone() : undefined, 33353 radius: this.getRadius(), 33354 scale: Array.isArray(scale) ? scale.slice() : scale, 33355 rotation: this.getRotation(), 33356 rotateWithView: this.getRotateWithView(), 33357 displacement: this.getDisplacement().slice(), 33358 declutterMode: this.getDeclutterMode(), 33359 }); 33360 style.setOpacity(this.getOpacity()); 33361 return style; 33362 } 33363 33364 /** 33365 * Set the circle radius. 33366 * 33367 * @param {number} radius Circle radius. 33368 * @api 33369 */ 33370 setRadius(radius) { 33371 this.radius_ = radius; 33372 this.render(); 33373 } 33374} 33375 33376/* harmony default export */ const Circle = (Circle_CircleStyle); 33377 33378;// CONCATENATED MODULE: ./node_modules/ol/style/Fill.js 33379/** 33380 * @module ol/style/Fill 33381 */ 33382 33383/** 33384 * @typedef {Object} Options 33385 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike|null} [color=null] A color, gradient or pattern. 33386 * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats. 33387 * Default null; if null, the Canvas/renderer default black will be used. 33388 */ 33389 33390/** 33391 * @classdesc 33392 * Set fill style for vector features. 33393 * @api 33394 */ 33395class Fill_Fill { 33396 /** 33397 * @param {Options} [options] Options. 33398 */ 33399 constructor(options) { 33400 options = options || {}; 33401 33402 /** 33403 * @private 33404 * @type {import("../color.js").Color|import("../colorlike.js").ColorLike|null} 33405 */ 33406 this.color_ = options.color !== undefined ? options.color : null; 33407 } 33408 33409 /** 33410 * Clones the style. The color is not cloned if it is an {@link module:ol/colorlike~ColorLike}. 33411 * @return {Fill} The cloned style. 33412 * @api 33413 */ 33414 clone() { 33415 const color = this.getColor(); 33416 return new Fill_Fill({ 33417 color: Array.isArray(color) ? color.slice() : color || undefined, 33418 }); 33419 } 33420 33421 /** 33422 * Get the fill color. 33423 * @return {import("../color.js").Color|import("../colorlike.js").ColorLike|null} Color. 33424 * @api 33425 */ 33426 getColor() { 33427 return this.color_; 33428 } 33429 33430 /** 33431 * Set the color. 33432 * 33433 * @param {import("../color.js").Color|import("../colorlike.js").ColorLike|null} color Color. 33434 * @api 33435 */ 33436 setColor(color) { 33437 this.color_ = color; 33438 } 33439} 33440 33441/* harmony default export */ const style_Fill = (Fill_Fill); 33442 33443;// CONCATENATED MODULE: ./node_modules/ol/style/Stroke.js 33444/** 33445 * @module ol/style/Stroke 33446 */ 33447 33448/** 33449 * @typedef {Object} Options 33450 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [color] A color, gradient or pattern. 33451 * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats. 33452 * Default null; if null, the Canvas/renderer default black will be used. 33453 * @property {CanvasLineCap} [lineCap='round'] Line cap style: `butt`, `round`, or `square`. 33454 * @property {CanvasLineJoin} [lineJoin='round'] Line join style: `bevel`, `round`, or `miter`. 33455 * @property {Array<number>} [lineDash] Line dash pattern. Default is `null` (no dash). 33456 * @property {number} [lineDashOffset=0] Line dash offset. 33457 * @property {number} [miterLimit=10] Miter limit. 33458 * @property {number} [width] Width. 33459 */ 33460 33461/** 33462 * @classdesc 33463 * Set stroke style for vector features. 33464 * Note that the defaults given are the Canvas defaults, which will be used if 33465 * option is not defined. The `get` functions return whatever was entered in 33466 * the options; they will not return the default. 33467 * @api 33468 */ 33469class Stroke_Stroke { 33470 /** 33471 * @param {Options} [options] Options. 33472 */ 33473 constructor(options) { 33474 options = options || {}; 33475 33476 /** 33477 * @private 33478 * @type {import("../color.js").Color|import("../colorlike.js").ColorLike} 33479 */ 33480 this.color_ = options.color !== undefined ? options.color : null; 33481 33482 /** 33483 * @private 33484 * @type {CanvasLineCap|undefined} 33485 */ 33486 this.lineCap_ = options.lineCap; 33487 33488 /** 33489 * @private 33490 * @type {Array<number>|null} 33491 */ 33492 this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null; 33493 33494 /** 33495 * @private 33496 * @type {number|undefined} 33497 */ 33498 this.lineDashOffset_ = options.lineDashOffset; 33499 33500 /** 33501 * @private 33502 * @type {CanvasLineJoin|undefined} 33503 */ 33504 this.lineJoin_ = options.lineJoin; 33505 33506 /** 33507 * @private 33508 * @type {number|undefined} 33509 */ 33510 this.miterLimit_ = options.miterLimit; 33511 33512 /** 33513 * @private 33514 * @type {number|undefined} 33515 */ 33516 this.width_ = options.width; 33517 } 33518 33519 /** 33520 * Clones the style. 33521 * @return {Stroke} The cloned style. 33522 * @api 33523 */ 33524 clone() { 33525 const color = this.getColor(); 33526 return new Stroke_Stroke({
33527 color: Array.isArray(color) ? color.slice() : color || undefined, 33528 lineCap: this.getLineCap(), 33529 lineDash: this.getLineDash() ? this.getLineDash().slice() : undefined, 33530 lineDashOffset: this.getLineDashOffset(), 33531 lineJoin: this.getLineJoin(), 33532 miterLimit: this.getMiterLimit(), 33533 width: this.getWidth(), 33534 }); 33535 } 33536 33537 /** 33538 * Get the stroke color. 33539 * @return {import("../color.js").Color|import("../colorlike.js").ColorLike} Color. 33540 * @api 33541 */ 33542 getColor() { 33543 return this.color_; 33544 } 33545 33546 /** 33547 * Get the line cap type for the stroke. 33548 * @return {CanvasLineCap|undefined} Line cap. 33549 * @api 33550 */ 33551 getLineCap() { 33552 return this.lineCap_; 33553 } 33554 33555 /** 33556 * Get the line dash style for the stroke. 33557 * @return {Array<number>|null} Line dash. 33558 * @api 33559 */ 33560 getLineDash() { 33561 return this.lineDash_; 33562 } 33563 33564 /** 33565 * Get the line dash offset for the stroke. 33566 * @return {number|undefined} Line dash offset. 33567 * @api 33568 */ 33569 getLineDashOffset() { 33570 return this.lineDashOffset_; 33571 } 33572 33573 /** 33574 * Get the line join type for the stroke. 33575 * @return {CanvasLineJoin|undefined} Line join. 33576 * @api 33577 */ 33578 getLineJoin() { 33579 return this.lineJoin_; 33580 } 33581 33582 /** 33583 * Get the miter limit for the stroke. 33584 * @return {number|undefined} Miter limit. 33585 * @api 33586 */ 33587 getMiterLimit() { 33588 return this.miterLimit_; 33589 } 33590 33591 /** 33592 * Get the stroke width. 33593 * @return {number|undefined} Width. 33594 * @api 33595 */ 33596 getWidth() { 33597 return this.width_; 33598 } 33599 33600 /** 33601 * Set the color. 33602 * 33603 * @param {import("../color.js").Color|import("../colorlike.js").ColorLike} color Color. 33604 * @api 33605 */ 33606 setColor(color) { 33607 this.color_ = color; 33608 } 33609 33610 /** 33611 * Set the line cap. 33612 * 33613 * @param {CanvasLineCap|undefined} lineCap Line cap. 33614 * @api 33615 */ 33616 setLineCap(lineCap) { 33617 this.lineCap_ = lineCap; 33618 } 33619 33620 /** 33621 * Set the line dash. 33622 * 33623 * @param {Array<number>|null} lineDash Line dash. 33624 * @api 33625 */ 33626 setLineDash(lineDash) { 33627 this.lineDash_ = lineDash; 33628 } 33629 33630 /** 33631 * Set the line dash offset. 33632 * 33633 * @param {number|undefined} lineDashOffset Line dash offset. 33634 * @api 33635 */ 33636 setLineDashOffset(lineDashOffset) { 33637 this.lineDashOffset_ = lineDashOffset; 33638 } 33639 33640 /** 33641 * Set the line join. 33642 * 33643 * @param {CanvasLineJoin|undefined} lineJoin Line join. 33644 * @api 33645 */ 33646 setLineJoin(lineJoin) { 33647 this.lineJoin_ = lineJoin; 33648 } 33649 33650 /** 33651 * Set the miter limit. 33652 * 33653 * @param {number|undefined} miterLimit Miter limit. 33654 * @api 33655 */ 33656 setMiterLimit(miterLimit) {
33657 this.miterLimit_ = miterLimit; 33658 } 33659 33660 /** 33661 * Set the width. 33662 * 33663 * @param {number|undefined} width Width. 33664 * @api 33665 */ 33666 setWidth(width) { 33667 this.width_ = width; 33668 } 33669} 33670 33671/* harmony default export */ const style_Stroke = (Stroke_Stroke); 33672 33673;// CONCATENATED MODULE: ./node_modules/ol/style/Style.js 33674/** 33675 * @module ol/style/Style 33676 */ 33677 33678 33679 33680 33681 33682 33683/** 33684 * A function that takes an {@link module:ol/Feature~Feature} and a `{number}` 33685 * representing the view's resolution. The function should return a 33686 * {@link module:ol/style/Style~Style} or an array of them. This way e.g. a 33687 * vector layer can be styled. If the function returns `undefined`, the 33688 * feature will not be rendered. 33689 * 33690 * @typedef {function(import("../Feature.js").FeatureLike, number):(Style|Array<Style>|void)} StyleFunction 33691 */ 33692 33693/** 33694 * A {@link Style}, an array of {@link Style}, or a {@link StyleFunction}. 33695 * @typedef {Style|Array<Style>|StyleFunction} StyleLike 33696 */ 33697 33698/** 33699 * A function that takes an {@link module:ol/Feature~Feature} as argument and returns an 33700 * {@link module:ol/geom/Geometry~Geometry} that will be rendered and styled for the feature. 33701 * 33702 * @typedef {function(import("../Feature.js").FeatureLike): 33703 * (import("../geom/Geometry.js").default|import("../render/Feature.js").default|undefined)} GeometryFunction 33704 */ 33705 33706/** 33707 * Custom renderer function. Takes two arguments: 33708 * 33709 * 1. The pixel coordinates of the geometry in GeoJSON notation. 33710 * 2. The {@link module:ol/render~State} of the layer renderer. 33711 * 33712 * @typedef {function((import("../coordinate.js").Coordinate|Array<import("../coordinate.js").Coordinate>|Array<Array<import("../coordinate.js").Coordinate>>),import("../render.js").State): void} RenderFunction 33713 */ 33714 33715/** 33716 * @typedef {Object} Options 33717 * @property {string|import("../geom/Geometry.js").default|GeometryFunction} [geometry] Feature property or geometry 33718 * or function returning a geometry to render for this style. 33719 * @property {import("./Fill.js").default} [fill] Fill style. 33720 * @property {import("./Image.js").default} [image] Image style. 33721 * @property {RenderFunction} [renderer] Custom renderer. When configured, `fill`, `stroke` and `image` will be 33722 * ignored, and the provided function will be called with each render frame for each geometry. 33723 * @property {RenderFunction} [hitDetectionRenderer] Custom renderer for hit detection. If provided will be used 33724 * in hit detection rendering. 33725 * @property {import("./Stroke.js").default} [stroke] Stroke style. 33726 * @property {import("./Text.js").default} [text] Text style. 33727 * @property {number} [zIndex] Z index. 33728 */ 33729 33730/** 33731 * @classdesc 33732 * Container for vector feature rendering styles. Any changes made to the style 33733 * or its children through `set*()` methods will not take effect until the 33734 * feature or layer that uses the style is re-rendered. 33735 * 33736 * ## Feature styles 33737 * 33738 * If no style is defined, the following default style is used: 33739 * ```js 33740 * import {Circle, Fill, Stroke, Style} from 'ol/style'; 33741 * 33742 * const fill = new Fill({ 33743 * color: 'rgba(255,255,255,0.4)', 33744 * }); 33745 * const stroke = new Stroke({ 33746 * color: '#3399CC', 33747 * width: 1.25, 33748 * }); 33749 * const styles = [ 33750 * new Style({ 33751 * image: new Circle({ 33752 * fill: fill, 33753 * stroke: stroke, 33754 * radius: 5, 33755 * }), 33756 * fill: fill, 33757 * stroke: stroke, 33758 * }), 33759 * ]; 33760 * ``` 33761 * 33762 * A separate editing style has the following defaults: 33763 * ```js 33764 * import {Circle, Fill, Stroke, Style} from 'ol/style'; 33765 * 33766 * const styles = {}; 33767 * const white = [255, 255, 255, 1]; 33768 * const blue = [0, 153, 255, 1]; 33769 * const width = 3; 33770 * styles['Polygon'] = [ 33771 * new Style({ 33772 * fill: new Fill({ 33773 * color: [255, 255, 255, 0.5], 33774 * }), 33775 * }), 33776 * ]; 33777 * styles['MultiPolygon'] = 33778 * styles['Polygon']; 33779 * styles['LineString'] = [ 33780 * new Style({ 33781 * stroke: new Stroke({ 33782 * color: white, 33783 * width: width + 2, 33784 * }), 33785 * }), 33786 * new Style({ 33787 * stroke: new Stroke({ 33788 * color: blue, 33789 * width: width, 33790 * }), 33791 * }), 33792 * ]; 33793 * styles['MultiLineString'] = styles['LineString']; 33794 * 33795 * styles['Circle'] = styles['Polygon'].concat( 33796 * styles['LineString'] 33797 * ); 33798 * 33799 * styles['Point'] = [ 33800 * new Style({ 33801 * image: new Circle({ 33802 * radius: width * 2, 33803 * fill: new Fill({ 33804 * color: blue, 33805 * }), 33806 * stroke: new Stroke({ 33807 * color: white, 33808 * width: width / 2, 33809 * }), 33810 * }), 33811 * zIndex: Infinity, 33812 * }), 33813 * ]; 33814 * styles['MultiPoint'] = 33815 * styles['Point']; 33816 * styles['GeometryCollection'] = 33817 * styles['Polygon'].concat( 33818 * styles['LineString'], 33819 * styles['Point'] 33820 * ); 33821 * ``` 33822 * 33823 * @api 33824 */ 33825class Style { 33826 /** 33827 * @param {Options} [options] Style options. 33828 */ 33829 constructor(options) { 33830 options = options || {}; 33831 33832 /** 33833 * @private 33834 * @type {string|import("../geom/Geometry.js").default|GeometryFunction} 33835 */ 33836 this.geometry_ = null; 33837 33838 /** 33839 * @private
33840 * @type {!GeometryFunction} 33841 */ 33842 this.geometryFunction_ = defaultGeometryFunction; 33843 33844 if (options.geometry !== undefined) { 33845 this.setGeometry(options.geometry); 33846 } 33847 33848 /** 33849 * @private 33850 * @type {import("./Fill.js").default} 33851 */ 33852 this.fill_ = options.fill !== undefined ? options.fill : null; 33853 33854 /** 33855 * @private 33856 * @type {import("./Image.js").default} 33857 */ 33858 this.image_ = options.image !== undefined ? options.image : null; 33859 33860 /** 33861 * @private 33862 * @type {RenderFunction|null} 33863 */ 33864 this.renderer_ = options.renderer !== undefined ? options.renderer : null; 33865 33866 /** 33867 * @private 33868 * @type {RenderFunction|null} 33869 */ 33870 this.hitDetectionRenderer_ = 33871 options.hitDetectionRenderer !== undefined 33872 ? options.hitDetectionRenderer 33873 : null; 33874 33875 /** 33876 * @private 33877 * @type {import("./Stroke.js").default} 33878 */ 33879 this.stroke_ = options.stroke !== undefined ? options.stroke : null; 33880 33881 /** 33882 * @private 33883 * @type {import("./Text.js").default} 33884 */ 33885 this.text_ = options.text !== undefined ? options.text : null; 33886 33887 /** 33888 * @private 33889 * @type {number|undefined} 33890 */ 33891 this.zIndex_ = options.zIndex; 33892 } 33893 33894 /** 33895 * Clones the style. 33896 * @return {Style} The cloned style. 33897 * @api 33898 */ 33899 clone() { 33900 let geometry = this.getGeometry(); 33901 if (geometry && typeof geometry === 'object') { 33902 geometry = /** @type {import("../geom/Geometry.js").default} */ ( 33903 geometry 33904 ).clone(); 33905 } 33906 return new Style({ 33907 geometry: geometry, 33908 fill: this.getFill() ? this.getFill().clone() : undefined, 33909 image: this.getImage() ? this.getImage().clone() : undefined, 33910 renderer: this.getRenderer(), 33911 stroke: this.getStroke() ? this.getStroke().clone() : undefined, 33912 text: this.getText() ? this.getText().clone() : undefined, 33913 zIndex: this.getZIndex(), 33914 }); 33915 } 33916 33917 /** 33918 * Get the custom renderer function that was configured with 33919 * {@link #setRenderer} or the `renderer` constructor option. 33920 * @return {RenderFunction|null} Custom renderer function. 33921 * @api 33922 */ 33923 getRenderer() { 33924 return this.renderer_; 33925 } 33926 33927 /** 33928 * Sets a custom renderer function for this style. When set, `fill`, `stroke` 33929 * and `image` options of the style will be ignored. 33930 * @param {RenderFunction|null} renderer Custom renderer function. 33931 * @api 33932 */ 33933 setRenderer(renderer) { 33934 this.renderer_ = renderer; 33935 } 33936 33937 /** 33938 * Sets a custom renderer function for this style used 33939 * in hit detection. 33940 * @param {RenderFunction|null} renderer Custom renderer function. 33941 * @api 33942 */ 33943 setHitDetectionRenderer(renderer) { 33944 this.hitDetectionRenderer_ = renderer; 33945 } 33946 33947 /** 33948 * Get the custom renderer function that was configured with 33949 * {@link #setHitDetectionRenderer} or the `hitDetectionRenderer` constructor option. 33950 * @return {RenderFunction|null} Custom renderer function. 33951 * @api 33952 */ 33953 getHitDetectionRenderer() { 33954 return this.hitDetectionRenderer_; 33955 } 33956 33957 /** 33958 * Get the geometry to be rendered. 33959 * @return {string|import("../geom/Geometry.js").default|GeometryFunction} 33960 * Feature property or geometry or function that returns the geometry that will 33961 * be rendered with this style. 33962 * @api 33963 */ 33964 getGeometry() { 33965 return this.geometry_; 33966 } 33967 33968 /** 33969 * Get the function used to generate a geometry for rendering. 33970 * @return {!GeometryFunction} Function that is called with a feature 33971 * and returns the geometry to render instead of the feature's geometry. 33972 * @api 33973 */ 33974 getGeometryFunction() { 33975 return this.geometryFunction_; 33976 } 33977 33978 /** 33979 * Get the fill style. 33980 * @return {import("./Fill.js").default} Fill style. 33981 * @api 33982 */ 33983 getFill() { 33984 return this.fill_; 33985 } 33986 33987 /** 33988 * Set the fill style. 33989 * @param {import("./Fill.js").default} fill Fill style. 33990 * @api 33991 */ 33992 setFill(fill) { 33993 this.fill_ = fill; 33994 } 33995 33996 /** 33997 * Get the image style. 33998 * @return {import("./Image.js").default} Image style. 33999 * @api 34000 */ 34001 getImage() { 34002 return this.image_; 34003 } 34004 34005 /** 34006 * Set the image style. 34007 * @param {import("./Image.js").default} image Image style. 34008 * @api 34009 */ 34010 setImage(image) { 34011 this.image_ = image; 34012 } 34013 34014 /** 34015 * Get the stroke style. 34016 * @return {import("./Stroke.js").default} Stroke style. 34017 * @api 34018 */ 34019 getStroke() { 34020 return this.stroke_; 34021 } 34022 34023 /** 34024 * Set the stroke style. 34025 * @param {import("./Stroke.js").default} stroke Stroke style. 34026 * @api 34027 */ 34028 setStroke(stroke) { 34029 this.stroke_ = stroke; 34030 } 34031 34032 /** 34033 * Get the text style. 34034 * @return {import("./Text.js").default} Text style. 34035 * @api 34036 */ 34037 getText() { 34038 return this.text_; 34039 } 34040 34041 /** 34042 * Set the text style. 34043 * @param {import("./Text.js").default} text Text style. 34044 * @api 34045 */ 34046 setText(text) { 34047 this.text_ = text; 34048 } 34049 34050 /** 34051 * Get the z-index for the style. 34052 * @return {number|undefined} ZIndex. 34053 * @api 34054 */ 34055 getZIndex() { 34056 return this.zIndex_; 34057 } 34058 34059 /** 34060 * Set a geometry that is rendered instead of the feature's geometry. 34061 * 34062 * @param {string|import("../geom/Geometry.js").default|GeometryFunction} geometry 34063 * Feature property or geometry or function returning a geometry to render 34064 * for this style. 34065 * @api 34066 */ 34067 setGeometry(geometry) { 34068 if (typeof geometry === 'function') { 34069 this.geometryFunction_ = geometry; 34070 } else if (typeof geometry === 'string') { 34071 this.geometryFunction_ = function (feature) { 34072 return /** @type {import("../geom/Geometry.js").default} */ ( 34073 feature.get(geometry) 34074 ); 34075 }; 34076 } else if (!geometry) { 34077 this.geometryFunction_ = defaultGeometryFunction; 34078 } else if (geometry !== undefined) { 34079 this.geometryFunction_ = function () { 34080 return /** @type {import("../geom/Geometry.js").default} */ (geometry); 34081 }; 34082 } 34083 this.geometry_ = geometry; 34084 } 34085 34086 /** 34087 * Set the z-index. 34088 * 34089 * @param {number|undefined} zIndex ZIndex. 34090 * @api 34091 */ 34092 setZIndex(zIndex) { 34093 this.zIndex_ = zIndex; 34094 } 34095} 34096 34097/** 34098 * Convert the provided object into a style function. Functions passed through 34099 * unchanged. Arrays of Style or single style objects wrapped in a 34100 * new style function. 34101 * @param {StyleFunction|Array<Style>|Style} obj 34102 * A style function, a single style, or an array of styles. 34103 * @return {StyleFunction} A style function. 34104 */ 34105function toFunction(obj) { 34106 let styleFunction; 34107 34108 if (typeof obj === 'function') { 34109 styleFunction = obj; 34110 } else { 34111 /** 34112 * @type {Array<Style>} 34113 */ 34114 let styles; 34115 if (Array.isArray(obj)) { 34116 styles = obj; 34117 } else { 34118 asserts_assert(typeof (/** @type {?} */ (obj).getZIndex) === 'function', 41); // Expected an `Style` or an array of `Style` 34119 const style = /** @type {Style} */ (obj); 34120 styles = [style]; 34121 } 34122 styleFunction = function () { 34123 return styles; 34124 }; 34125 } 34126 return styleFunction; 34127} 34128 34129/** 34130 * @type {Array<Style>|null} 34131 */ 34132let defaultStyles = null; 34133 34134/** 34135 * @param {import("../Feature.js").FeatureLike} feature Feature. 34136 * @param {number} resolution Resolution. 34137 * @return {Array<Style>} Style. 34138 */ 34139function createDefaultStyle(feature, resolution) { 34140 // We don't use an immediately-invoked function 34141 // and a closure so we don't get an error at script evaluation time in 34142 // browsers that do not support Canvas. (import("./Circle.js").CircleStyle does 34143 // canvas.getContext('2d') at construction time, which will cause an.error 34144 // in such browsers.) 34145 if (!defaultStyles) { 34146 const fill = new style_Fill({ 34147 color: 'rgba(255,255,255,0.4)', 34148 }); 34149 const stroke = new style_Stroke({ 34150 color: '#3399CC', 34151 width: 1.25, 34152 }); 34153 defaultStyles = [ 34154 new Style({ 34155 image: new Circle({ 34156 fill: fill, 34157 stroke: stroke, 34158 radius: 5, 34159 }), 34160 fill: fill, 34161 stroke: stroke, 34162 }), 34163 ]; 34164 } 34165 return defaultStyles; 34166} 34167 34168/** 34169 * Default styles for editing features. 34170 * @return {Object<import("../geom/Geometry.js").Type, Array<Style>>}
34170 Styles 34171 */ 34172function createEditingStyle() { 34173 /** @type {Object<import("../geom/Geometry.js").Type, Array<Style>>} */ 34174 const styles = {}; 34175 const white = [255, 255, 255, 1]; 34176 const blue = [0, 153, 255, 1]; 34177 const width = 3; 34178 styles['Polygon'] = [ 34179 new Style({ 34180 fill: new Fill({ 34181 color: [255, 255, 255, 0.5], 34182 }), 34183 }), 34184 ]; 34185 styles['MultiPolygon'] = styles['Polygon']; 34186 34187 styles['LineString'] = [ 34188 new Style({ 34189 stroke: new Stroke({ 34190 color: white, 34191 width: width + 2, 34192 }), 34193 }), 34194 new Style({ 34195 stroke: new Stroke({ 34196 color: blue, 34197 width: width, 34198 }), 34199 }), 34200 ]; 34201 styles['MultiLineString'] = styles['LineString']; 34202 34203 styles['Circle'] = styles['Polygon'].concat(styles['LineString']); 34204 34205 styles['Point'] = [ 34206 new Style({ 34207 image: new CircleStyle({ 34208 radius: width * 2, 34209 fill: new Fill({ 34210 color: blue, 34211 }), 34212 stroke: new Stroke({ 34213 color: white, 34214 width: width / 2, 34215 }), 34216 }), 34217 zIndex: Infinity, 34218 }), 34219 ]; 34220 styles['MultiPoint'] = styles['Point']; 34221 34222 styles['GeometryCollection'] = styles['Polygon'].concat( 34223 styles['LineString'], 34224 styles['Point'] 34225 ); 34226 34227 return styles; 34228} 34229 34230/** 34231 * Function that is called with a feature and returns its default geometry. 34232 * @param {import("../Feature.js").FeatureLike} feature Feature to get the geometry for. 34233 * @return {import("../geom/Geometry.js").default|import("../render/Feature.js").default|undefined} Geometry to render. 34234 */ 34235function defaultGeometryFunction(feature) { 34236 return feature.getGeometry(); 34237} 34238 34239/* harmony default export */ const style_Style = (Style); 34240 34241;// CONCATENATED MODULE: ./node_modules/ol/Image.js 34242/** 34243 * @module ol/Image 34244 */ 34245 34246 34247 34248 34249 34250 34251 34252/** 34253 * A function that takes an {@link module:ol/Image~ImageWrapper} for the image and a 34254 * `{string}` for the src as arguments. It is supposed to make it so the 34255 * underlying image {@link module:ol/Image~ImageWrapper#getImage} is assigned the 34256 * content specified by the src. If not specified, the default is 34257 * 34258 * function(image, src) { 34259 * image.getImage().src = src; 34260 * } 34261 * 34262 * Providing a custom `imageLoadFunction` can be useful to load images with 34263 * post requests or - in general - through XHR requests, where the src of the 34264 * image element would be set to a data URI when the content is loaded. 34265 * 34266 * @typedef {function(ImageWrapper, string): void} LoadFunction 34267 * @api 34268 */ 34269 34270class ImageWrapper extends (/* unused pure expression or super */ null && (ImageBase)) { 34271 /** 34272 * @param {import("./extent.js").Extent} extent Extent. 34273 * @param {number|undefined} resolution Resolution. 34274 * @param {number} pixelRatio Pixel ratio. 34275 * @param {string} src Image source URI. 34276 * @param {?string} crossOrigin Cross origin. 34277 * @param {LoadFunction} imageLoadFunction Image load function. 34278 */ 34279 constructor( 34280 extent, 34281 resolution, 34282 pixelRatio, 34283 src, 34284 crossOrigin, 34285 imageLoadFunction 34286 ) { 34287 super(extent, resolution, pixelRatio, ImageState.IDLE); 34288 34289 /** 34290 * @private 34291 * @type {string} 34292 */ 34293 this.src_ = src; 34294 34295 /** 34296 * @private 34297 * @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} 34298 */ 34299 this.image_ = new Image(); 34300 if (crossOrigin !== null) { 34301 this.image_.crossOrigin = crossOrigin; 34302 } 34303 34304 /** 34305 * @private 34306 * @type {?function():void} 34307 */ 34308 this.unlisten_ = null; 34309 34310 /** 34311 * @protected 34312 * @type {import("./ImageState.js").default} 34313 */ 34314 this.state = ImageState.IDLE; 34315 34316 /** 34317 * @private 34318 * @type {LoadFunction} 34319 */ 34320 this.imageLoadFunction_ = imageLoadFunction; 34321 } 34322 34323 /** 34324 * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image. 34325 * @api 34326 */ 34327 getImage() { 34328 return this.image_; 34329 } 34330 34331 /** 34332 * Tracks loading or read errors. 34333 * 34334 * @private 34335 */ 34336 handleImageError_() { 34337 this.state = ImageState.ERROR; 34338 this.unlistenImage_(); 34339 this.changed(); 34340 } 34341 34342 /** 34343 * Tracks successful image load. 34344 * 34345 * @private 34346 */ 34347 handleImageLoad_() { 34348 if (this.resolution === undefined) { 34349 this.resolution = getHeight(this.extent) / this.image_.height; 34350 } 34351 this.state = ImageState.LOADED; 34352 this.unlistenImage_(); 34353 this.changed(); 34354 } 34355 34356 /** 34357 * Load the image or retry if loading previously failed.
34358 * Loading is taken care of by the tile queue, and calling this method is 34359 * only needed for preloading or for reloading in case of an error. 34360 * @api 34361 */ 34362 load() { 34363 if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) { 34364 this.state = ImageState.LOADING; 34365 this.changed(); 34366 this.imageLoadFunction_(this, this.src_); 34367 this.unlisten_ = listenImage( 34368 this.image_, 34369 this.handleImageLoad_.bind(this), 34370 this.handleImageError_.bind(this) 34371 ); 34372 } 34373 } 34374 34375 /** 34376 * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image. 34377 */ 34378 setImage(image) { 34379 this.image_ = image; 34380 this.resolution = getHeight(this.extent) / this.image_.height; 34381 } 34382 34383 /** 34384 * Discards event handlers which listen for load completion or errors. 34385 * 34386 * @private 34387 */ 34388 unlistenImage_() { 34389 if (this.unlisten_) { 34390 this.unlisten_(); 34391 this.unlisten_ = null; 34392 } 34393 } 34394} 34395 34396/** 34397 * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image element. 34398 * @param {function():any} loadHandler Load callback function. 34399 * @param {function():any} errorHandler Error callback function. 34400 * @return {function():void} Callback to stop listening. 34401 */ 34402function listenImage(image, loadHandler, errorHandler) { 34403 const img = /** @type {HTMLImageElement} */ (image); 34404 let listening = true; 34405 let decoding = false; 34406 let loaded = false; 34407 34408 const listenerKeys = [ 34409 listenOnce(img, EventType.LOAD, function () { 34410 loaded = true; 34411 if (!decoding) { 34412 loadHandler(); 34413 } 34414 }), 34415 ]; 34416 34417 if (img.src && IMAGE_DECODE) { 34418 decoding = true; 34419 img 34420 .decode() 34421 .then(function () { 34422 if (listening) { 34423 loadHandler(); 34424 } 34425 }) 34426 .catch(function (error) { 34427 if (listening) { 34428 if (loaded) { 34429 loadHandler(); 34430 } else { 34431 errorHandler(); 34432 } 34433 } 34434 }); 34435 } else { 34436 listenerKeys.push(listenOnce(img, EventType.ERROR, errorHandler)); 34437 } 34438 34439 return function unlisten() { 34440 listening = false; 34441 listenerKeys.forEach(unlistenByKey); 34442 }; 34443} 34444 34445/* harmony default export */ const ol_Image = ((/* unused pure expression or super */ null && (ImageWrapper))); 34446 34447;// CONCATENATED MODULE: ./node_modules/ol/style/IconImage.js 34448/** 34449 * @module ol/style/IconImage 34450 */ 34451 34452 34453 34454 34455 34456 34457 34458 34459 34460/** 34461 * @type {CanvasRenderingContext2D} 34462 */ 34463let taintedTestContext = null; 34464 34465class IconImage extends events_Target { 34466 /** 34467 * @param {HTMLImageElement|HTMLCanvasElement} image Image. 34468 * @param {string|undefined} src Src. 34469 * @param {import("../size.js").Size} size Size. 34470 * @param {?string} crossOrigin Cross origin. 34471 * @param {import("../ImageState.js").default} imageState Image state. 34472 * @param {import("../color.js").Color} color Color. 34473 */ 34474 constructor(image, src, size, crossOrigin, imageState, color) { 34475 super(); 34476 34477 /** 34478 * @private 34479 * @type {HTMLImageElement|HTMLCanvasElement} 34480 */ 34481 this.hitDetectionImage_ = null; 34482 34483 /** 34484 * @private 34485 * @type {HTMLImageElement|HTMLCanvasElement} 34486 */ 34487 this.image_ = image; 34488 34489 /** 34490 * @private 34491 * @type {string|null} 34492 */ 34493 this.crossOrigin_ = crossOrigin; 34494 34495 /** 34496 * @private 34497 * @type {Object<number, HTMLCanvasElement>} 34498 */ 34499 this.canvas_ = {}; 34500 34501 /** 34502 * @private 34503 * @type {import("../color.js").Color} 34504 */ 34505 this.color_ = color; 34506 34507 /** 34508 * @private 34509 * @type {?function():void} 34510 */ 34511 this.unlisten_ = null; 34512 34513 /** 34514 * @private 34515 * @type {import("../ImageState.js").default} 34516 */ 34517 this.imageState_ = imageState; 34518 34519 /** 34520 * @private 34521 * @type {import("../size.js").Size} 34522 */ 34523 this.size_ = size; 34524 34525 /** 34526 * @private 34527 * @type {string|undefined} 34528 */ 34529 this.src_ = src; 34530 34531 /** 34532 * @private 34533 */ 34534 this.tainted_; 34535 } 34536 34537 /** 34538 * @private 34539 */ 34540 initializeImage_() { 34541 this.image_ = new Image(); 34542 if (this.crossOrigin_ !== null) { 34543 this.image_.crossOrigin = this.crossOrigin_; 34544 } 34545 } 34546 34547 /** 34548 * @private 34549 * @return {boolean} The image canvas is tainted. 34550 */ 34551 isTainted_() { 34552 if (this.tainted_ === undefined && this.imageState_ === ol_ImageState.LOADED) { 34553 if (!taintedTestContext) { 34554 taintedTestContext = createCanvasContext2D(1, 1); 34555 }
34556 taintedTestContext.drawImage(this.image_, 0, 0); 34557 try { 34558 taintedTestContext.getImageData(0, 0, 1, 1); 34559 this.tainted_ = false; 34560 } catch (e) { 34561 taintedTestContext = null; 34562 this.tainted_ = true; 34563 } 34564 } 34565 return this.tainted_ === true; 34566 } 34567 34568 /** 34569 * @private 34570 */ 34571 dispatchChangeEvent_() { 34572 this.dispatchEvent(EventType.CHANGE); 34573 } 34574 34575 /** 34576 * @private 34577 */ 34578 handleImageError_() { 34579 this.imageState_ = ol_ImageState.ERROR; 34580 this.unlistenImage_(); 34581 this.dispatchChangeEvent_(); 34582 } 34583 34584 /** 34585 * @private 34586 */ 34587 handleImageLoad_() { 34588 this.imageState_ = ol_ImageState.LOADED; 34589 if (this.size_) { 34590 this.image_.width = this.size_[0]; 34591 this.image_.height = this.size_[1]; 34592 } else { 34593 this.size_ = [this.image_.width, this.image_.height]; 34594 } 34595 this.unlistenImage_(); 34596 this.dispatchChangeEvent_(); 34597 } 34598 34599 /** 34600 * @param {number} pixelRatio Pixel ratio. 34601 * @return {HTMLImageElement|HTMLCanvasElement} Image or Canvas element. 34602 */ 34603 getImage(pixelRatio) { 34604 if (!this.image_) { 34605 this.initializeImage_(); 34606 } 34607 this.replaceColor_(pixelRatio); 34608 return this.canvas_[pixelRatio] ? this.canvas_[pixelRatio] : this.image_; 34609 } 34610 34611 /** 34612 * @param {number} pixelRatio Pixel ratio. 34613 * @return {number} Image or Canvas element. 34614 */ 34615 getPixelRatio(pixelRatio) { 34616 this.replaceColor_(pixelRatio); 34617 return this.canvas_[pixelRatio] ? pixelRatio : 1; 34618 } 34619 34620 /** 34621 * @return {import("../ImageState.js").default} Image state. 34622 */ 34623 getImageState() { 34624 return this.imageState_; 34625 } 34626 34627 /** 34628 * @return {HTMLImageElement|HTMLCanvasElement} Image element. 34629 */ 34630 getHitDetectionImage() { 34631 if (!this.image_) { 34632 this.initializeImage_(); 34633 } 34634 if (!this.hitDetectionImage_) { 34635 if (this.isTainted_()) { 34636 const width = this.size_[0]; 34637 const height = this.size_[1]; 34638 const context = createCanvasContext2D(width, height); 34639 context.fillRect(0, 0, width, height); 34640 this.hitDetectionImage_ = context.canvas; 34641 } else { 34642 this.hitDetectionImage_ = this.image_; 34643 } 34644 } 34645 return this.hitDetectionImage_; 34646 } 34647 34648 /** 34649 * Get the size of the icon (in pixels). 34650 * @return {import("../size.js").Size} Image size. 34651 */ 34652 getSize() { 34653 return this.size_; 34654 } 34655 34656 /** 34657 * @return {string|undefined} Image src. 34658 */ 34659 getSrc() { 34660 return this.src_; 34661 } 34662 34663 /** 34664 * Load not yet loaded URI. 34665 */ 34666 load() { 34667 if (this.imageState_ !== ol_ImageState.IDLE) { 34668 return; 34669 } 34670 if (!this.image_) { 34671 this.initializeImage_(); 34672 } 34673 34674 this.imageState_ = ol_ImageState.LOADING; 34675 try { 34676 /** @type {HTMLImageElement} */ (this.image_).src = this.src_; 34677 } catch (e) { 34678 this.handleImageError_(); 34679 } 34680 this.unlisten_ = listenImage( 34681 this.image_, 34682 this.handleImageLoad_.bind(this), 34683 this.handleImageError_.bind(this) 34684 ); 34685 } 34686 34687 /** 34688 * @param {number} pixelRatio Pixel ratio. 34689 * @private 34690 */ 34691 replaceColor_(pixelRatio) { 34692 if ( 34693 !this.color_ || 34694 this.canvas_[pixelRatio] || 34695 this.imageState_ !== ol_ImageState.LOADED 34696 ) { 34697 return; 34698 } 34699 34700 const image = this.image_; 34701 const canvas = document.createElement('canvas'); 34702 canvas.width = Math.ceil(image.width * pixelRatio); 34703 canvas.height = Math.ceil(image.height * pixelRatio); 34704 34705 const ctx = canvas.getContext('2d'); 34706 ctx.scale(pixelRatio, pixelRatio); 34707 ctx.drawImage(image, 0, 0); 34708 34709 ctx.globalCompositeOperation = 'multiply'; 34710 ctx.fillStyle = asString(this.color_); 34711 ctx.fillRect(0, 0, canvas.width / pixelRatio, canvas.height / pixelRatio); 34712 34713 ctx.globalCompositeOperation = 'destination-in'; 34714 ctx.drawImage(image, 0, 0); 34715 34716 this.canvas_[pixelRatio] = canvas; 34717 } 34718 34719 /** 34720 * Discards event handlers which listen for load completion or errors. 34721 * 34722 * @private 34723 */ 34724 unlistenImage_() { 34725 if (this.unlisten_) { 34726 this.unlisten_(); 34727 this.unlisten_ = null; 34728 } 34729 } 34730} 34731 34732/** 34733 * @param {HTMLImageElement|HTMLCanvasElement} image Image. 34734 * @param {string} src Src. 34735 * @param {import("../size.js").Size} size Size. 34736 * @param {?string} crossOrigin Cross origin. 34737 * @param {import("../ImageState.js").default} imageState Image state. 34738 * @param {import("../color.js").Color} color Color. 34739 * @return {IconImage} Icon image. 34740 */ 34741function IconImage_get(image, src, size, crossOrigin, imageState, color) { 34742 let iconImage = shared.get(src, crossOrigin, color); 34743 if (!iconImage) { 34744 iconImage = new IconImage(image, src, size, crossOrigin, imageState, color); 34745 shared.set(src, crossOrigin, color, iconImage); 34746 } 34747 return iconImage; 34748} 34749 34750/* harmony default export */ const style_IconImage = ((/* unused pure expression or super */ null && (IconImage))); 34751 34752;// CONCATENATED MODULE: ./node_modules/ol/style/Icon.js 34753/** 34754 * @module ol/style/Icon 34755 */ 34756 34757 34758 34759 34760 34761 34762 34763 34764/** 34765 * @typedef {'fraction' | 'pixels'} IconAnchorUnits 34766 * Anchor unit can be either a fraction of the icon size or in pixels. 34767 */ 34768 34769/** 34770 * @typedef {'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'} IconOrigin 34771 * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'. 34772 */ 34773 34774/** 34775 * @typedef {Object} Options 34776 * @property {Array<number>} [anchor=[0.5, 0.5]] Anchor. Default value is the icon center. 34777 * @property {IconOrigin}
34777 [anchorOrigin='top-left'] Origin of the anchor: `bottom-left`, `bottom-right`, 34778 * `top-left` or `top-right`. 34779 * @property {IconAnchorUnits} [anchorXUnits='fraction'] Units in which the anchor x value is 34780 * specified. A value of `'fraction'` indicates the x value is a fraction of the icon. A value of `'pixels'` indicates 34781 * the x value in pixels. 34782 * @property {IconAnchorUnits} [anchorYUnits='fraction'] Units in which the anchor y value is 34783 * specified. A value of `'fraction'` indicates the y value is a fraction of the icon. A value of `'pixels'` indicates 34784 * the y value in pixels. 34785 * @property {import("../color.js").Color|string} [color] Color to tint the icon. If not specified, 34786 * the icon will be left as is. 34787 * @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that you must provide a 34788 * `crossOrigin` value if you want to access pixel data with the Canvas renderer. 34789 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail. 34790 * @property {HTMLImageElement|HTMLCanvasElement} [img] Image object for the icon. If the `src` option is not provided then the 34791 * provided image must already be loaded. And in that case, it is required 34792 * to provide the size of the image, with the `imgSize` option. 34793 * @property {import("../size.js").Size} [imgSize] Image size in pixels. Only required if `img` is set and `src` is not. 34794 * The provided `imgSize` needs to match the actual size of the image. 34795 * @property {Array<number>} [displacement=[0, 0]] Displacement of the icon in pixels. 34796 * Positive values will shift the icon right and up. 34797 * @property {number} [opacity=1] Opacity of the icon. 34798 * @property {number|import("../size.js").Size} [scale=1] Scale. 34799 * @property {boolean} [rotateWithView=false] Whether to rotate the icon with the view. 34800 * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise). 34801 * @property {Array<number>} [offset=[0, 0]] Offset which, together with `size` and `offsetOrigin`, defines the 34802 * sub-rectangle to use from the original (sprite) image. 34803 * @property {IconOrigin} [offsetOrigin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`, 34804 * `top-left` or `top-right`. 34805 * @property {import("../size.js").Size} [size] Icon size in pixels. Used together with `offset` to define the 34806 * sub-rectangle to use from the original (sprite) image. 34807 * @property {string} [src] Image source URI. 34808 * @property {"declutter"|"obstacle"|"none"|undefined} [declutterMode] Declutter mode. 34809 */ 34810 34811/** 34812 * @classdesc 34813 * Set icon style for vector features. 34814 * @api 34815 */ 34816class Icon extends style_Image { 34817 /** 34818 * @param {Options} [options] Options. 34819 */ 34820 constructor(options) { 34821 options = options || {}; 34822 34823 /** 34824 * @type {number} 34825 */ 34826 const opacity = options.opacity !== undefined ? options.opacity : 1; 34827 34828 /** 34829 * @type {number} 34830 */ 34831 const rotation = options.rotation !== undefined ? options.rotation : 0; 34832 34833 /** 34834 * @type {number|import("../size.js").Size} 34835 */ 34836 const scale = options.scale !== undefined ? options.scale : 1; 34837 34838 /** 34839 * @type {boolean} 34840 */ 34841 const rotateWithView = 34842 options.rotateWithView !== undefined ? options.rotateWithView : false; 34843 34844 super({ 34845 opacity: opacity, 34846 rotation: rotation, 34847 scale: scale, 34848 displacement: 34849 options.displacement !== undefined ? options.displacement : [0, 0], 34850 rotateWithView: rotateWithView, 34851 declutterMode: options.declutterMode, 34852 }); 34853 34854 /** 34855 * @private 34856 * @type {Array<number>} 34857 */ 34858 this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5]; 34859 34860 /** 34861 * @private 34862 * @type {Array<number>} 34863 */ 34864 this.normalizedAnchor_ = null; 34865 34866 /** 34867 * @private 34868 * @type {IconOrigin} 34869 */ 34870 this.anchorOrigin_ = 34871 options.anchorOrigin !== undefined ? options.anchorOrigin : 'top-left'; 34872 34873 /** 34874 * @private 34875 * @type {IconAnchorUnits} 34876 */ 34877 this.anchorXUnits_ = 34878 options.anchorXUnits !== undefined ? options.anchorXUnits : 'fraction'; 34879 34880 /** 34881 * @private 34882 * @type {IconAnchorUnits} 34883 */ 34884 this.anchorYUnits_ = 34885 options.anchorYUnits !== undefined ? options.anchorYUnits : 'fraction'; 34886 34887 /** 34888 * @private 34889 * @type {?string} 34890 */ 34891 this.crossOrigin_ = 34892 options.crossOrigin !== undefined ? options.crossOrigin : null; 34893 34894 /** 34895 * @type {HTMLImageElement|HTMLCanvasElement} 34896 */ 34897 const image = options.img !== undefined ? options.img : null; 34898 34899 /** 34900 * @private 34901 * @type {import("../size.js").Size|undefined} 34902 */ 34903 this.imgSize_ = options.imgSize; 34904 34905 /** 34906 * @type {string|undefined} 34907 */ 34908 let src = options.src; 34909 34910 asserts_assert(!(src !== undefined && image), 4); // `image` and `src` cannot be provided at the same time 34911 asserts_assert(!image || (image && this.imgSize_), 5); // `imgSize` must be set when `image` is provided 34912 34913 if ((src === undefined || src.length === 0) && image) { 34914 src = /** @type {HTMLImageElement} */ (image).src || getUid(image); 34915 } 34916 asserts_assert(src !== undefined && src.length > 0, 6); // A defined and non-empty `src` or `image` must be provided 34917 34918 /** 34919 * @type {import("../ImageState.js").default} 34920 */ 34921 const imageState = 34922 options.src !== undefined ? ol_ImageState.IDLE : ol_ImageState.LOADED; 34923 34924 /** 34925 * @private 34926 * @type {import("../color.js").Color} 34927 */ 34928 this.color_ = options.color !== undefined ? asArray(options.color) : null; 34929 34930 /** 34931 * @private 34932 * @type {import("./IconImage.js").default} 34933 */ 34934 this.iconImage_ = IconImage_get( 34935 image, 34936 /** @type {string} */ (src), 34937 this.imgSize_ !== undefined ? this.imgSize_ : null, 34938 this.crossOrigin_, 34939 imageState, 34940 this.color_ 34941 ); 34942 34943 /** 34944 * @private 34945 * @type {Array<number>} 34946 */ 34947 this.offset_ = options.offset !== undefined ? options.offset : [0, 0]; 34948 /** 34949 * @private 34950 * @type {IconOrigin} 34951 */ 34952 this.offsetOrigin_ = 34953 options.offsetOrigin !== undefined ? options.offsetOrigin : 'top-left'; 34954 34955 /** 34956 * @private 34957 * @type {Array<number>} 34958 */ 34959 this.origin_ = null; 34960 34961 /** 34962 * @private 34963 * @type {import("../size.js").Size} 34964 */ 34965 this.size_ = options.size !== undefined ? options.size : null; 34966 } 34967 34968 /** 34969 * Clones the style. The underlying Image/HTMLCanvasElement is not cloned. 34970 * @return {Icon} The cloned style. 34971 * @api 34972 */ 34973 clone() {
34974 const scale = this.getScale(); 34975 return new Icon({ 34976 anchor: this.anchor_.slice(), 34977 anchorOrigin: this.anchorOrigin_, 34978 anchorXUnits: this.anchorXUnits_, 34979 anchorYUnits: this.anchorYUnits_, 34980 color: 34981 this.color_ && this.color_.slice 34982 ? this.color_.slice() 34983 : this.color_ || undefined, 34984 crossOrigin: this.crossOrigin_, 34985 imgSize: this.imgSize_, 34986 offset: this.offset_.slice(), 34987 offsetOrigin: this.offsetOrigin_, 34988 opacity: this.getOpacity(), 34989 rotateWithView: this.getRotateWithView(), 34990 rotation: this.getRotation(), 34991 scale: Array.isArray(scale) ? scale.slice() : scale, 34992 size: this.size_ !== null ? this.size_.slice() : undefined, 34993 src: this.getSrc(), 34994 displacement: this.getDisplacement().slice(), 34995 declutterMode: this.getDeclutterMode(), 34996 }); 34997 } 34998 34999 /** 35000 * Get the anchor point in pixels. The anchor determines the center point for the 35001 * symbolizer. 35002 * @return {Array<number>} Anchor. 35003 * @api 35004 */ 35005 getAnchor() { 35006 let anchor = this.normalizedAnchor_; 35007 if (!anchor) { 35008 anchor = this.anchor_; 35009 const size = this.getSize(); 35010 if ( 35011 this.anchorXUnits_ == 'fraction' || 35012 this.anchorYUnits_ == 'fraction' 35013 ) { 35014 if (!size) { 35015 return null; 35016 } 35017 anchor = this.anchor_.slice(); 35018 if (this.anchorXUnits_ == 'fraction') { 35019 anchor[0] *= size[0]; 35020 } 35021 if (this.anchorYUnits_ == 'fraction') { 35022 anchor[1] *= size[1]; 35023 } 35024 } 35025 35026 if (this.anchorOrigin_ != 'top-left') { 35027 if (!size) { 35028 return null; 35029 } 35030 if (anchor === this.anchor_) { 35031 anchor = this.anchor_.slice(); 35032 } 35033 if ( 35034 this.anchorOrigin_ == 'top-right' || 35035 this.anchorOrigin_ == 'bottom-right' 35036 ) { 35037 anchor[0] = -anchor[0] + size[0]; 35038 } 35039 if ( 35040 this.anchorOrigin_ == 'bottom-left' || 35041 this.anchorOrigin_ == 'bottom-right' 35042 ) { 35043 anchor[1] = -anchor[1] + size[1]; 35044 } 35045 } 35046 this.normalizedAnchor_ = anchor; 35047 } 35048 const displacement = this.getDisplacement(); 35049 const scale = this.getScaleArray(); 35050 // anchor is scaled by renderer but displacement should not be scaled 35051 // so divide by scale here 35052 return [ 35053 anchor[0] - displacement[0] / scale[0], 35054 anchor[1] + displacement[1] / scale[1], 35055 ]; 35056 } 35057 35058 /** 35059 * Set the anchor point. The anchor determines the center point for the 35060 * symbolizer. 35061 * 35062 * @param {Array<number>} anchor Anchor. 35063 * @api 35064 */ 35065 setAnchor(anchor) { 35066 this.anchor_ = anchor; 35067 this.normalizedAnchor_ = null; 35068 } 35069 35070 /** 35071 * Get the icon color. 35072 * @return {import("../color.js").Color} Color. 35073 * @api 35074 */ 35075 getColor() { 35076 return this.color_; 35077 } 35078 35079 /** 35080 * Get the image icon. 35081 * @param {number} pixelRatio Pixel ratio. 35082 * @return {HTMLImageElement|HTMLCanvasElement} Image or Canvas element. 35083 * @api 35084 */ 35085 getImage(pixelRatio) { 35086 return this.iconImage_.getImage(pixelRatio); 35087 } 35088 35089 /** 35090 * Get the pixel ratio. 35091 * @param {number} pixelRatio Pixel ratio. 35092 * @return {number} The pixel ratio of the image. 35093 * @api 35094 */ 35095 getPixelRatio(pixelRatio) { 35096 return this.iconImage_.getPixelRatio(pixelRatio); 35097 } 35098 35099 /** 35100 * @return {import("../size.js").Size} Image size. 35101 */ 35102 getImageSize() { 35103 return this.iconImage_.getSize(); 35104 } 35105 35106 /** 35107 * @return {import("../ImageState.js").default} Image state. 35108 */ 35109 getImageState() { 35110 return this.iconImage_.getImageState(); 35111 } 35112 35113 /** 35114 * @return {HTMLImageElement|HTMLCanvasElement} Image element. 35115 */ 35116 getHitDetectionImage() { 35117 return this.iconImage_.getHitDetectionImage(); 35118 } 35119 35120 /** 35121 * Get the origin of the symbolizer. 35122 * @return {Array<number>} Origin. 35123 * @api 35124 */ 35125 getOrigin() { 35126 if (this.origin_) { 35127 return this.origin_; 35128 } 35129 let offset = this.offset_; 35130 35131 if (this.offsetOrigin_ != 'top-left') { 35132 const size = this.getSize(); 35133 const iconImageSize = this.iconImage_.getSize(); 35134 if (!size || !iconImageSize) { 35135 return null; 35136 } 35137 offset = offset.slice(); 35138 if (
35139 this.offsetOrigin_ == 'top-right' || 35140 this.offsetOrigin_ == 'bottom-right' 35141 ) { 35142 offset[0] = iconImageSize[0] - size[0] - offset[0]; 35143 } 35144 if ( 35145 this.offsetOrigin_ == 'bottom-left' || 35146 this.offsetOrigin_ == 'bottom-right' 35147 ) { 35148 offset[1] = iconImageSize[1] - size[1] - offset[1]; 35149 } 35150 } 35151 this.origin_ = offset; 35152 return this.origin_; 35153 } 35154 35155 /** 35156 * Get the image URL. 35157 * @return {string|undefined} Image src. 35158 * @api 35159 */ 35160 getSrc() { 35161 return this.iconImage_.getSrc(); 35162 } 35163 35164 /** 35165 * Get the size of the icon (in pixels). 35166 * @return {import("../size.js").Size} Image size. 35167 * @api 35168 */ 35169 getSize() { 35170 return !this.size_ ? this.iconImage_.getSize() : this.size_; 35171 } 35172 35173 /** 35174 * @param {function(import("../events/Event.js").default): void} listener Listener function. 35175 */ 35176 listenImageChange(listener) { 35177 this.iconImage_.addEventListener(EventType.CHANGE, listener); 35178 } 35179 35180 /** 35181 * Load not yet loaded URI. 35182 * When rendering a feature with an icon style, the vector renderer will 35183 * automatically call this method. However, you might want to call this 35184 * method yourself for preloading or other purposes. 35185 * @api 35186 */ 35187 load() { 35188 this.iconImage_.load(); 35189 } 35190 35191 /** 35192 * @param {function(import("../events/Event.js").default): void} listener Listener function. 35193 */ 35194 unlistenImageChange(listener) { 35195 this.iconImage_.removeEventListener(EventType.CHANGE, listener); 35196 } 35197} 35198 35199/* harmony default export */ const style_Icon = (Icon); 35200 35201;// CONCATENATED MODULE: ./node_modules/ol/style/Text.js 35202/** 35203 * @module ol/style/Text 35204 */ 35205 35206 35207 35208/** 35209 * @typedef {'point' | 'line'} TextPlacement 35210 * Default text placement is `'point'`. Note that 35211 * `'line'` requires the underlying geometry to be a {@link module:ol/geom/LineString~LineString}, 35212 * {@link module:ol/geom/Polygon~Polygon}, {@link module:ol/geom/MultiLineString~MultiLineString} or 35213 * {@link module:ol/geom/MultiPolygon~MultiPolygon}. 35214 */ 35215 35216/** 35217 * @typedef {'left' | 'center' | 'right'} TextJustify 35218 */ 35219 35220/** 35221 * The default fill color to use if no fill was set at construction time; a 35222 * blackish `#333`. 35223 * 35224 * @const {string} 35225 */ 35226const DEFAULT_FILL_COLOR = '#333'; 35227 35228/** 35229 * @typedef {Object} Options 35230 * @property {string} [font] Font style as CSS `font` value, see: 35231 * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font. Default is `'10px sans-serif'` 35232 * @property {number} [maxAngle=Math.PI/4] When `placement` is set to `'line'`, allow a maximum angle between adjacent characters. 35233 * The expected value is in radians, and the default is 45° (`Math.PI / 4`). 35234 * @property {number} [offsetX=0] Horizontal text offset in pixels. A positive will shift the text right. 35235 * @property {number} [offsetY=0] Vertical text offset in pixels. A positive will shift the text down. 35236 * @property {boolean} [overflow=false] For polygon labels or when `placement` is set to `'line'`, allow text to exceed 35237 * the width of the polygon at the label position or the length of the path that it follows. 35238 * @property {TextPlacement} [placement='point'] Text placement. 35239 * @property {number|import("../size.js").Size} [scale] Scale. 35240 * @property {boolean} [rotateWithView=false] Whether to rotate the text with the view. 35241 * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise). 35242 * @property {string|Array<string>} [text] Text content or rich text content. For plain text provide a string, which can 35243 * contain line breaks (`\n`). For rich text provide an array of text/font tuples. A tuple consists of the text to 35244 * render and the font to use (or `''` to use the text style's font). A line break has to be a separate tuple (i.e. `'\n', ''`). 35245 * **Example:** `['foo', 'bold 10px sans-serif', ' bar', 'italic 10px sans-serif', ' baz', '']` will yield "**foo** *bar* baz". 35246 * **Note:** Rich text is not supported for the immediate rendering API. 35247 * @property {CanvasTextAlign} [textAlign] Text alignment. Possible values: `'left'`, `'right'`, `'center'`, `'end'` or `'start'`. 35248 * Default is `'center'` for `placement: 'point'`. For `placement: 'line'`, the default is to let the renderer choose a 35249 * placement where `maxAngle` is not exceeded. 35250 * @property {TextJustify} [justify] Text justification within the text box. 35251 * If not set, text is justified towards the `textAlign` anchor. 35252 * Otherwise, use options `'left'`, `'center'`, or `'right'` to justify the text within the text box. 35253 * **Note:** `justify` is ignored for immediate rendering and also for `placement: 'line'`. 35254 * @property {CanvasTextBaseline} [textBaseline='middle'] Text base line. Possible values: `'bottom'`, `'top'`, `'middle'`, `'alphabetic'`, 35255 * `'hanging'`, `'ideographic'`. 35256 * @property {import("./Fill.js").default}
35256 [fill] Fill style. If none is provided, we'll use a dark fill-style (#333). 35257 * @property {import("./Stroke.js").default} [stroke] Stroke style. 35258 * @property {import("./Fill.js").default} [backgroundFill] Fill style for the text background when `placement` is 35259 * `'point'`. Default is no fill. 35260 * @property {import("./Stroke.js").default} [backgroundStroke] Stroke style for the text background when `placement` 35261 * is `'point'`. Default is no stroke. 35262 * @property {Array<number>} [padding=[0, 0, 0, 0]] Padding in pixels around the text for decluttering and background. The order of 35263 * values in the array is `[top, right, bottom, left]`. 35264 */ 35265 35266/** 35267 * @classdesc 35268 * Set text style for vector features. 35269 * @api 35270 */ 35271class Text { 35272 /** 35273 * @param {Options} [options] Options. 35274 */ 35275 constructor(options) { 35276 options = options || {}; 35277 35278 /** 35279 * @private 35280 * @type {string|undefined} 35281 */ 35282 this.font_ = options.font; 35283 35284 /** 35285 * @private 35286 * @type {number|undefined} 35287 */ 35288 this.rotation_ = options.rotation; 35289 35290 /** 35291 * @private 35292 * @type {boolean|undefined} 35293 */ 35294 this.rotateWithView_ = options.rotateWithView; 35295 35296 /** 35297 * @private 35298 * @type {number|import("../size.js").Size|undefined} 35299 */ 35300 this.scale_ = options.scale; 35301 35302 /** 35303 * @private 35304 * @type {import("../size.js").Size} 35305 */ 35306 this.scaleArray_ = toSize(options.scale !== undefined ? options.scale : 1); 35307 35308 /** 35309 * @private 35310 * @type {string|Array<string>|undefined} 35311 */ 35312 this.text_ = options.text; 35313 35314 /** 35315 * @private 35316 * @type {CanvasTextAlign|undefined} 35317 */ 35318 this.textAlign_ = options.textAlign; 35319 35320 /** 35321 * @private 35322 * @type {TextJustify|undefined} 35323 */ 35324 this.justify_ = options.justify; 35325 35326 /** 35327 * @private 35328 * @type {CanvasTextBaseline|undefined} 35329 */ 35330 this.textBaseline_ = options.textBaseline; 35331 35332 /** 35333 * @private 35334 * @type {import("./Fill.js").default} 35335 */ 35336 this.fill_ = 35337 options.fill !== undefined 35338 ? options.fill 35339 : new style_Fill({color: DEFAULT_FILL_COLOR}); 35340 35341 /** 35342 * @private 35343 * @type {number} 35344 */ 35345 this.maxAngle_ = 35346 options.maxAngle !== undefined ? options.maxAngle : Math.PI / 4; 35347 35348 /** 35349 * @private 35350 * @type {TextPlacement} 35351 */ 35352 this.placement_ = 35353 options.placement !== undefined ? options.placement : 'point'; 35354 35355 /** 35356 * @private 35357 * @type {boolean} 35358 */ 35359 this.overflow_ = !!options.overflow; 35360 35361 /** 35362 * @private 35363 * @type {import("./Stroke.js").default} 35364 */ 35365 this.stroke_ = options.stroke !== undefined ? options.stroke : null; 35366 35367 /** 35368 * @private 35369 * @type {number} 35370 */ 35371 this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0; 35372 35373 /** 35374 * @private 35375 * @type {number} 35376 */ 35377 this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0; 35378 35379 /** 35380 * @private 35381 * @type {import("./Fill.js").default} 35382 */ 35383 this.backgroundFill_ = options.backgroundFill 35384 ? options.backgroundFill 35385 : null; 35386 35387 /** 35388 * @private 35389 * @type {import("./Stroke.js").default} 35390 */ 35391 this.backgroundStroke_ = options.backgroundStroke 35392 ? options.backgroundStroke 35393 : null; 35394 35395 /** 35396 * @private 35397 * @type {Array<number>|null} 35398 */ 35399 this.padding_ = options.padding === undefined ? null : options.padding; 35400 } 35401 35402 /** 35403 * Clones the style. 35404 * @return {Text} The cloned style. 35405 * @api 35406 */ 35407 clone() { 35408 const scale = this.getScale(); 35409 return new Text({ 35410 font: this.getFont(), 35411 placement: this.getPlacement(), 35412 maxAngle: this.getMaxAngle(), 35413 overflow: this.getOverflow(), 35414 rotation: this.getRotation(), 35415 rotateWithView: this.getRotateWithView(), 35416 scale: Array.isArray(scale) ? scale.slice() : scale, 35417 text: this.getText(), 35418 textAlign: this.getTextAlign(), 35419 justify: this.getJustify(), 35420 textBaseline: this.getTextBaseline(), 35421 fill: this.getFill() ? this.getFill().clone() : undefined, 35422 stroke: this.getStroke() ? this.getStroke().clone() : undefined, 35423 offsetX: this.getOffsetX(), 35424 offsetY: this.getOffsetY(),
35425 backgroundFill: this.getBackgroundFill() 35426 ? this.getBackgroundFill().clone() 35427 : undefined, 35428 backgroundStroke: this.getBackgroundStroke() 35429 ? this.getBackgroundStroke().clone() 35430 : undefined, 35431 padding: this.getPadding() || undefined, 35432 }); 35433 } 35434 35435 /** 35436 * Get the `overflow` configuration. 35437 * @return {boolean} Let text overflow the length of the path they follow. 35438 * @api 35439 */ 35440 getOverflow() { 35441 return this.overflow_; 35442 } 35443 35444 /** 35445 * Get the font name. 35446 * @return {string|undefined} Font. 35447 * @api 35448 */ 35449 getFont() { 35450 return this.font_; 35451 } 35452 35453 /** 35454 * Get the maximum angle between adjacent characters. 35455 * @return {number} Angle in radians. 35456 * @api 35457 */ 35458 getMaxAngle() { 35459 return this.maxAngle_; 35460 } 35461 35462 /** 35463 * Get the label placement. 35464 * @return {TextPlacement} Text placement. 35465 * @api 35466 */ 35467 getPlacement() { 35468 return this.placement_; 35469 } 35470 35471 /** 35472 * Get the x-offset for the text. 35473 * @return {number} Horizontal text offset. 35474 * @api 35475 */ 35476 getOffsetX() { 35477 return this.offsetX_; 35478 } 35479 35480 /** 35481 * Get the y-offset for the text. 35482 * @return {number} Vertical text offset. 35483 * @api 35484 */ 35485 getOffsetY() { 35486 return this.offsetY_; 35487 } 35488 35489 /** 35490 * Get the fill style for the text. 35491 * @return {import("./Fill.js").default} Fill style. 35492 * @api 35493 */ 35494 getFill() { 35495 return this.fill_; 35496 } 35497 35498 /** 35499 * Determine whether the text rotates with the map. 35500 * @return {boolean|undefined} Rotate with map. 35501 * @api 35502 */ 35503 getRotateWithView() { 35504 return this.rotateWithView_; 35505 } 35506 35507 /** 35508 * Get the text rotation. 35509 * @return {number|undefined} Rotation. 35510 * @api 35511 */ 35512 getRotation() { 35513 return this.rotation_; 35514 } 35515 35516 /** 35517 * Get the text scale. 35518 * @return {number|import("../size.js").Size|undefined} Scale. 35519 * @api 35520 */ 35521 getScale() { 35522 return this.scale_; 35523 } 35524 35525 /** 35526 * Get the symbolizer scale array. 35527 * @return {import("../size.js").Size} Scale array. 35528 */ 35529 getScaleArray() { 35530 return this.scaleArray_; 35531 } 35532 35533 /** 35534 * Get the stroke style for the text. 35535 * @return {import("./Stroke.js").default} Stroke style. 35536 * @api 35537 */ 35538 getStroke() { 35539 return this.stroke_; 35540 } 35541 35542 /** 35543 * Get the text to be rendered. 35544 * @return {string|Array<string>|undefined} Text. 35545 * @api 35546 */ 35547 getText() { 35548 return this.text_; 35549 } 35550 35551 /** 35552 * Get the text alignment. 35553 * @return {CanvasTextAlign|undefined} Text align. 35554 * @api 35555 */ 35556 getTextAlign() { 35557 return this.textAlign_; 35558 } 35559 35560 /** 35561 * Get the justification. 35562 * @return {TextJustify|undefined} Justification. 35563 * @api 35564 */ 35565 getJustify() { 35566 return this.justify_; 35567 } 35568 35569 /** 35570 * Get the text baseline. 35571 * @return {CanvasTextBaseline|undefined} Text baseline. 35572 * @api 35573 */ 35574 getTextBaseline() { 35575 return this.textBaseline_; 35576 } 35577 35578 /** 35579 * Get the background fill style for the text. 35580 * @return {import("./Fill.js").default} Fill style. 35581 * @api 35582 */ 35583 getBackgroundFill() { 35584 return this.backgroundFill_; 35585 } 35586 35587 /** 35588 * Get the background stroke style for the text. 35589 * @return {import("./Stroke.js").default} Stroke style. 35590 * @api 35591 */ 35592 getBackgroundStroke() { 35593 return this.backgroundStroke_; 35594 } 35595 35596 /** 35597 * Get the padding for the text. 35598 * @return {Array<number>|null} Padding. 35599 * @api 35600 */ 35601 getPadding() { 35602 return this.padding_; 35603 } 35604 35605 /** 35606 * Set the `overflow` property. 35607 * 35608 * @param {boolean} overflow Let text overflow the path that it follows. 35609 * @api 35610 */ 35611 setOverflow(overflow) { 35612 this.overflow_ = overflow; 35613 } 35614 35615 /** 35616 * Set the font. 35617 * 35618 * @param {string|undefined} font Font. 35619 * @api 35620 */ 35621 setFont(font) { 35622 this.font_ = font; 35623 } 35624 35625 /** 35626 * Set the maximum angle between adjacent characters. 35627 * 35628 * @param {number} maxAngle Angle in radians. 35629 * @api 35630 */ 35631 setMaxAngle(maxAngle) { 35632 this.maxAngle_ = maxAngle; 35633 } 35634 35635 /** 35636 * Set the x offset. 35637 * 35638 * @param {number} offsetX Horizontal text offset. 35639 * @api 35640 */ 35641 setOffsetX(offsetX) { 35642 this.offsetX_ = offsetX; 35643 } 35644 35645 /** 35646 * Set the y offset. 35647 * 35648 * @param {number} offsetY Vertical text offset. 35649 * @api 35650 */ 35651 setOffsetY(offsetY) { 35652 this.offsetY_ = offsetY; 35653 } 35654 35655 /** 35656 * Set the text placement. 35657 * 35658 * @param {TextPlacement} placement Placement. 35659 * @api 35660 */ 35661 setPlacement(placement) { 35662 this.placement_ = placement; 35663 } 35664 35665 /** 35666 * Set whether to rotate the text with the view. 35667 * 35668 * @param {boolean} rotateWithView Rotate with map. 35669 * @api 35670 */ 35671 setRotateWithView(rotateWithView) { 35672 this.rotateWithView_ = rotateWithView; 35673 } 35674 35675 /** 35676 * Set the fill. 35677 * 35678 * @param {import("./Fill.js").default} fill Fill style. 35679 * @api 35680 */ 35681 setFill(fill) { 35682 this.fill_ = fill; 35683 } 35684 35685 /** 35686 * Set the rotation. 35687 * 35688 * @param {number|undefined} rotation Rotation. 35689 * @api 35690 */ 35691 setRotation(rotation) { 35692 this.rotation_ = rotation; 35693 } 35694 35695 /** 35696 * Set the scale. 35697 * 35698 * @param {number|import("../size.js").Size|undefined} scale Scale. 35699 * @api 35700 */ 35701 setScale(scale) { 35702 this.scale_ = scale; 35703 this.scaleArray_ = toSize(scale !== undefined ? scale : 1); 35704 } 35705 35706 /** 35707 * Set the stroke. 35708 * 35709 * @param {import("./Stroke.js").default} stroke Stroke style. 35710 * @api 35711 */ 35712 setStroke(stroke) { 35713 this.stroke_ = stroke; 35714 } 35715 35716 /** 35717 * Set the text. 35718 * 35719 * @param {string|Array<string>|undefined} text Text. 35720 * @api 35721 */ 35722 setText(text) { 35723 this.text_ = text; 35724 } 35725 35726 /** 35727 * Set the text alignment. 35728 * 35729 * @param {CanvasTextAlign|undefined} textAlign Text align. 35730 * @api 35731 */ 35732 setTextAlign(textAlign) { 35733 this.textAlign_ = textAlign; 35734 } 35735 35736 /** 35737 * Set the justification. 35738 * 35739 * @param {TextJustify|undefined} justify Justification. 35740 * @api 35741 */ 35742 setJustify(justify) { 35743 this.justify_ = justify; 35744 } 35745 35746 /** 35747 * Set the text baseline. 35748 * 35749 * @param {CanvasTextBaseline|undefined} textBaseline Text baseline. 35750 * @api 35751 */ 35752 setTextBaseline(textBaseline) { 35753 this.textBaseline_ = textBaseline; 35754 } 35755 35756 /** 35757 * Set the background fill. 35758 * 35759 * @param {import("./Fill.js").default} fill Fill style. 35760 * @api 35761 */
35762 setBackgroundFill(fill) { 35763 this.backgroundFill_ = fill; 35764 } 35765 35766 /** 35767 * Set the background stroke. 35768 * 35769 * @param {import("./Stroke.js").default} stroke Stroke style. 35770 * @api 35771 */ 35772 setBackgroundStroke(stroke) { 35773 this.backgroundStroke_ = stroke; 35774 } 35775 35776 /** 35777 * Set the padding (`[top, right, bottom, left]`). 35778 * 35779 * @param {Array<number>|null} padding Padding. 35780 * @api 35781 */ 35782 setPadding(padding) { 35783 this.padding_ = padding; 35784 } 35785} 35786 35787/* harmony default export */ const style_Text = (Text); 35788 35789;// CONCATENATED MODULE: ./node_modules/ol/style/flat.js 35790/** 35791 * @module ol/style/flat 35792 */ 35793 35794 35795 35796 35797 35798 35799 35800 35801 35802/** 35803 * For static styling, the [layer.setStyle()]{@link module:ol/layer/Vector~VectorLayer#setStyle} method 35804 * can be called with an object literal that has fill, stroke, text, icon, regular shape, and/or circle properties. 35805 * @api 35806 * 35807 * @typedef {FlatFill & FlatStroke & FlatText & FlatIcon & FlatShape & FlatCircle} FlatStyle 35808 */ 35809 35810/** 35811 * A flat style literal or an array of the same. 35812 * 35813 * @typedef {FlatStyle|Array<FlatStyle>} FlatStyleLike 35814 */ 35815 35816/** 35817 * Fill style properties applied to polygon features. 35818 * 35819 * @typedef {Object} FlatFill 35820 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [fill-color] The fill color. 35821 */ 35822 35823/** 35824 * Stroke style properties applied to line strings and polygon boundaries. To apply a stroke, at least one of 35825 * `stroke-color` or `stroke-width` must be provided. 35826 * 35827 * @typedef {Object} FlatStroke 35828 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [stroke-color] The stroke color. 35829 * @property {number} [stroke-width] Stroke pixel width. 35830 * @property {CanvasLineCap} [stroke-line-cap='round'] Line cap style: `butt`, `round`, or `square`. 35831 * @property {CanvasLineJoin} [stroke-line-join='round'] Line join style: `bevel`, `round`, or `miter`. 35832 * @property {Array<number>} [stroke-line-dash] Line dash pattern. 35833 * @property {number} [stroke-line-dash-offset=0] Line dash offset. 35834 * @property {number} [stroke-miter-limit=10] Miter limit. 35835 */ 35836 35837/** 35838 * Label style properties applied to all features. At a minimum, a `text-value` must be provided. 35839 * 35840 * @typedef {Object} FlatText 35841 * @property {string|Array<string>} [text-value] Text content or rich text content. For plain text provide a string, which can 35842 * contain line breaks (`\n`). For rich text provide an array of text/font tuples. A tuple consists of the text to 35843 * render and the font to use (or `''` to use the text style's font). A line break has to be a separate tuple (i.e. `'\n', ''`). 35844 * **Example:** `['foo', 'bold 10px sans-serif', ' bar', 'italic 10px sans-serif', ' baz', '']` will yield "**foo** *bar* baz". 35845 * **Note:** Rich text is not supported for the immediate rendering API. 35846 * @property {string} [text-font] Font style as CSS `font` value, see: 35847 * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font. Default is `'10px sans-serif'` 35848 * @property {number} [text-max-angle=Math.PI/4] When `text-placement` is set to `'line'`, allow a maximum angle between adjacent characters. 35849 * The expected value is in radians, and the default is 45° (`Math.PI / 4`). 35850 * @property {number} [text-offset-x=0] Horizontal text offset in pixels. A positive will shift the text right. 35851 * @property {number} [text-offset-y=0] Vertical text offset in pixels. A positive will shift the text down. 35852 * @property {boolean} [text-overflow=false] For polygon labels or when `placement` is set to `'line'`, allow text to exceed 35853 * the width of the polygon at the label position or the length of the path that it follows. 35854 * @property {import("./Text.js").TextPlacement} [text-placement='point'] Text placement. 35855 * @property {number|import("../size.js").Size} [text-scale] Scale. 35856 * @property {boolean} [text-rotate-with-view=false] Whether to rotate the text with the view. 35857 * @property {number} [text-rotation=0] Rotation in radians (positive rotation clockwise). 35858 * @property {CanvasTextAlign} [text-align] Text alignment. Possible values: `'left'`, `'right'`, `'center'`, `'end'` or `'start'`. 35859 * Default is `'center'` for `text-placement: 'point'`. For `text-placement: 'line'`, the default is to let the renderer choose a 35860 * placement where `text-max-angle` is not exceeded. 35861 * @property {import('./Text.js').TextJustify} [text-justify] Text justification within the text box. 35862 * If not set, text is justified towards the `textAlign` anchor. 35863 * Otherwise, use options `'left'`, `'center'`, or `'right'` to justify the text within the text box.
35864 * **Note:** `text-justify` is ignored for immediate rendering and also for `text-placement: 'line'`. 35865 * @property {CanvasTextBaseline} [text-baseline='middle'] Text base line. Possible values: `'bottom'`, `'top'`, `'middle'`, `'alphabetic'`, 35866 * `'hanging'`, `'ideographic'`. 35867 * @property {Array<number>} [text-padding=[0, 0, 0, 0]] Padding in pixels around the text for decluttering and background. The order of 35868 * values in the array is `[top, right, bottom, left]`. 35869 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [text-fill-color] The fill color. 35870 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [text-background-fill-color] The fill color. 35871 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [text-stroke-color] The stroke color. 35872 * @property {CanvasLineCap} [text-stroke-line-cap='round'] Line cap style: `butt`, `round`, or `square`. 35873 * @property {CanvasLineJoin} [text-stroke-line-join='round'] Line join style: `bevel`, `round`, or `miter`. 35874 * @property {Array<number>} [text-stroke-line-dash] Line dash pattern. 35875 * @property {number} [text-stroke-line-dash-offset=0] Line dash offset. 35876 * @property {number} [text-stroke-miter-limit=10] Miter limit. 35877 * @property {number} [text-stroke-width] Stroke pixel width. 35878 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [text-background-stroke-color] The stroke color. 35879 * @property {CanvasLineCap} [text-background-stroke-line-cap='round'] Line cap style: `butt`, `round`, or `square`. 35880 * @property {CanvasLineJoin} [text-background-stroke-line-join='round'] Line join style: `bevel`, `round`, or `miter`. 35881 * @property {Array<number>} [text-background-stroke-line-dash] Line dash pattern. 35882 * @property {number} [text-background-stroke-line-dash-offset=0] Line dash offset. 35883 * @property {number} [text-background-stroke-miter-limit=10] Miter limit. 35884 * @property {number} [text-background-stroke-width] Stroke pixel width. 35885 */ 35886 35887/** 35888 * Icon style properties applied to point features. One of `icon-src` or `icon-img` must be provided to render 35889 * points with an icon. 35890 * 35891 * @typedef {Object} FlatIcon 35892 * @property {string} [icon-src] Image source URI. 35893 * @property {HTMLImageElement|HTMLCanvasElement} [icon-img] Image object for the icon. If the `icon-src` option is not provided then the 35894 * provided image must already be loaded. And in that case, it is required 35895 * to provide the size of the image, with the `icon-img-size` option. 35896 * @property {import("../size.js").Size} [icon-img-size] Image size in pixels. Only required if `icon-img` is set and `icon-src` is not. 35897 * The provided size needs to match the actual size of the image. 35898 * @property {Array<number>} [icon-anchor=[0.5, 0.5]] Anchor. Default value is the icon center. 35899 * @property {import("./Icon.js").IconOrigin} [icon-anchor-origin='top-left'] Origin of the anchor: `bottom-left`, `bottom-right`, 35900 * `top-left` or `top-right`. 35901 * @property {import("./Icon.js").IconAnchorUnits} [icon-anchor-x-units='fraction'] Units in which the anchor x value is 35902 * specified. A value of `'fraction'` indicates the x value is a fraction of the icon. A value of `'pixels'` indicates 35903 * the x value in pixels. 35904 * @property {import("./Icon.js").IconAnchorUnits} [icon-anchor-y-units='fraction'] Units in which the anchor y value is 35905 * specified. A value of `'fraction'` indicates the y value is a fraction of the icon. A value of `'pixels'` indicates 35906 * the y value in pixels. 35907 * @property {import("../color.js").Color|string} [icon-color] Color to tint the icon. If not specified, 35908 * the icon will be left as is. 35909 * @property {null|string} [icon-cross-origin] The `crossOrigin` attribute for loaded images. Note that you must provide a 35910 * `icon-cross-origin` value if you want to access pixel data with the Canvas renderer. 35911 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail. 35912 * @property {Array<number>} [icon-offset=[0, 0]] Offset, which, together with the size and the offset origin, define the 35913 * sub-rectangle to use from the original icon image. 35914 * @property {Array<number>} [icon-displacement=[0,0]] Displacement of the icon. 35915 * @property {import("./Icon.js").IconOrigin}
35915 [icon-offset-origin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`, 35916 * `top-left` or `top-right`. 35917 * @property {number} [icon-opacity=1] Opacity of the icon. 35918 * @property {number|import("../size.js").Size} [icon-scale=1] Scale. 35919 * @property {number} [icon-rotation=0] Rotation in radians (positive rotation clockwise). 35920 * @property {boolean} [icon-rotate-with-view=false] Whether to rotate the icon with the view. 35921 * @property {import("../size.js").Size} [icon-size] Icon size in pixel. Can be used together with `icon-offset` to define the 35922 * sub-rectangle to use from the origin (sprite) icon image. 35923 * @property {"declutter"|"obstacle"|"none"|undefined} [icon-declutter-mode] Declutter mode 35924 */ 35925 35926/** 35927 * Regular shape style properties for rendering point features. At least `shape-points` must be provided. 35928 * 35929 * @typedef {Object} FlatShape 35930 * @property {number} [shape-points] Number of points for stars and regular polygons. In case of a polygon, the number of points 35931 * is the number of sides. 35932 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [shape-fill-color] The fill color. 35933 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [shape-stroke-color] The stroke color. 35934 * @property {number} [shape-stroke-width] Stroke pixel width. 35935 * @property {CanvasLineCap} [shape-stroke-line-cap='round'] Line cap style: `butt`, `round`, or `square`. 35936 * @property {CanvasLineJoin} [shape-stroke-line-join='round'] Line join style: `bevel`, `round`, or `miter`. 35937 * @property {Array<number>} [shape-stroke-line-dash] Line dash pattern. 35938 * @property {number} [shape-stroke-line-dash-offset=0] Line dash offset. 35939 * @property {number} [shape-stroke-miter-limit=10] Miter limit. 35940 * @property {number} [shape-radius] Radius of a regular polygon. 35941 * @property {number} [shape-radius1] First radius of a star. Ignored if radius is set. 35942 * @property {number} [shape-radius2] Second radius of a star. 35943 * @property {number} [shape-angle=0] Shape's angle in radians. A value of 0 will have one of the shape's point facing up. 35944 * @property {Array<number>} [shape-displacement=[0,0]] Displacement of the shape 35945 * @property {number} [shape-rotation=0] Rotation in radians (positive rotation clockwise). 35946 * @property {boolean} [shape-rotate-with-view=false] Whether to rotate the shape with the view. 35947 * @property {number|import("../size.js").Size} [shape-scale=1] Scale. Unless two dimensional scaling is required a better 35948 * result may be obtained with appropriate settings for `shape-radius`, `shape-radius1` and `shape-radius2`. 35949 * @property {"declutter"|"obstacle"|"none"|undefined} [shape-declutter-mode] Declutter mode. 35950 */ 35951 35952/** 35953 * Circle style properties for rendering point features. At least `circle-radius` must be provided. 35954 * 35955 * @typedef {Object} FlatCircle 35956 * @property {number} [circle-radius] Circle radius. 35957 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [circle-fill-color] The fill color. 35958 * @property {import("../color.js").Color|import("../colorlike.js").ColorLike} [circle-stroke-color] The stroke color. 35959 * @property {number} [circle-stroke-width] Stroke pixel width. 35960 * @property {CanvasLineCap} [circle-stroke-line-cap='round'] Line cap style: `butt`, `round`, or `square`. 35961 * @property {CanvasLineJoin} [circle-stroke-line-join='round'] Line join style: `bevel`, `round`, or `miter`. 35962 * @property {Array<number>} [circle-stroke-line-dash] Line dash pattern. 35963 * @property {number} [circle-stroke-line-dash-offset=0] Line dash offset. 35964 * @property {number} [circle-stroke-miter-limit=10] Miter limit. 35965 * @property {Array<number>} [circle-displacement=[0,0]] displacement 35966 * @property {number|import("../size.js").Size} [circle-scale=1] Scale. A two dimensional scale will produce an ellipse. 35967 * Unless two dimensional scaling is required a better result may be obtained with an appropriate setting for `circle-radius`. 35968 * @property {number} [circle-rotation=0] Rotation in radians 35969 * (positive rotation clockwise, meaningful only when used in conjunction with a two dimensional scale). 35970 * @property {boolean} [circle-rotate-with-view=false] Whether to rotate the shape with the view 35971 * (meaningful only when used in conjunction with a two dimensional scale). 35972 * @property {"declutter"|"obstacle"|"none"|undefined} [circle-declutter-mode] Declutter mode 35973 */ 35974 35975/** 35976 * @param {FlatStyle} flatStyle A flat style literal. 35977 * @return {import("./Style.js").default} A style instance. 35978 */ 35979function toStyle(flatStyle) { 35980 const style = new style_Style({
35981 fill: getFill(flatStyle, ''), 35982 stroke: getStroke(flatStyle, ''), 35983 text: getText(flatStyle), 35984 image: getImage(flatStyle), 35985 }); 35986 35987 return style; 35988} 35989 35990/** 35991 * @param {FlatStyle} flatStyle The flat style. 35992 * @param {string} prefix The property prefix. 35993 * @return {Fill|undefined} The fill (if any). 35994 */ 35995function getFill(flatStyle, prefix) { 35996 const color = flatStyle[prefix + 'fill-color']; 35997 if (!color) { 35998 return; 35999 } 36000 36001 return new style_Fill({color: color}); 36002} 36003 36004/** 36005 * @param {FlatStyle} flatStyle The flat style. 36006 * @param {string} prefix The property prefix. 36007 * @return {Stroke|undefined} The stroke (if any). 36008 */ 36009function getStroke(flatStyle, prefix) { 36010 const width = flatStyle[prefix + 'stroke-width']; 36011 const color = flatStyle[prefix + 'stroke-color']; 36012 if (!width && !color) { 36013 return; 36014 } 36015 36016 return new style_Stroke({ 36017 width: width, 36018 color: color, 36019 lineCap: flatStyle[prefix + 'stroke-line-cap'], 36020 lineJoin: flatStyle[prefix + 'stroke-line-join'], 36021 lineDash: flatStyle[prefix + 'stroke-line-dash'], 36022 lineDashOffset: flatStyle[prefix + 'stroke-line-dash-offset'], 36023 miterLimit: flatStyle[prefix + 'stroke-miter-limit'], 36024 }); 36025} 36026 36027/** 36028 * @param {FlatStyle} flatStyle The flat style. 36029 * @return {Text|undefined} The text (if any). 36030 */ 36031function getText(flatStyle) { 36032 const value = flatStyle['text-value']; 36033 if (!value) { 36034 return; 36035 } 36036 36037 const text = new style_Text({ 36038 text: value, 36039 font: flatStyle['text-font'], 36040 maxAngle: flatStyle['text-max-angle'], 36041 offsetX: flatStyle['text-offset-x'], 36042 offsetY: flatStyle['text-offset-y'], 36043 overflow: flatStyle['text-overflow'], 36044 placement: flatStyle['text-placement'], 36045 scale: flatStyle['text-scale'], 36046 rotateWithView: flatStyle['text-rotate-with-view'], 36047 rotation: flatStyle['text-rotation'], 36048 textAlign: flatStyle['text-align'], 36049 justify: flatStyle['text-justify'], 36050 textBaseline: flatStyle['text-baseline'], 36051 padding: flatStyle['text-padding'], 36052 fill: getFill(flatStyle, 'text-'), 36053 backgroundFill: getFill(flatStyle, 'text-background-'), 36054 stroke: getStroke(flatStyle, 'text-'), 36055 backgroundStroke: getStroke(flatStyle, 'text-background-'), 36056 }); 36057 36058 return text; 36059} 36060 36061/** 36062 * @param {FlatStyle} flatStyle The flat style. 36063 * @return {import("./Image.js").default|undefined} The image (if any). 36064 */ 36065function getImage(flatStyle) { 36066 const iconSrc = flatStyle['icon-src']; 36067 const iconImg = flatStyle['icon-img']; 36068 if (iconSrc || iconImg) { 36069 const icon = new style_Icon({ 36070 src: iconSrc, 36071 img: iconImg, 36072 imgSize: flatStyle['icon-img-size'], 36073 anchor: flatStyle['icon-anchor'], 36074 anchorOrigin: flatStyle['icon-anchor-origin'], 36075 anchorXUnits: flatStyle['icon-anchor-x-units'], 36076 anchorYUnits: flatStyle['icon-anchor-y-units'], 36077 color: flatStyle['icon-color'], 36078 crossOrigin: flatStyle['icon-cross-origin'], 36079 offset: flatStyle['icon-offset'], 36080 displacement: flatStyle['icon-displacement'], 36081 opacity: flatStyle['icon-opacity'], 36082 scale: flatStyle['icon-scale'], 36083 rotation: flatStyle['icon-rotation'], 36084 rotateWithView: flatStyle['icon-rotate-with-view'], 36085 size: flatStyle['icon-size'], 36086 declutterMode: flatStyle['icon-declutter-mode'], 36087 }); 36088 return icon; 36089 } 36090 36091 const shapePoints = flatStyle['shape-points']; 36092 if (shapePoints) { 36093 const prefix = 'shape-'; 36094 const shape = new style_RegularShape({ 36095 points: shapePoints, 36096 fill: getFill(flatStyle, prefix), 36097 stroke: getStroke(flatStyle, prefix), 36098 radius: flatStyle['shape-radius'], 36099 radius1: flatStyle['shape-radius1'], 36100 radius2: flatStyle['shape-radius2'], 36101 angle: flatStyle['shape-angle'], 36102 displacement: flatStyle['shape-displacement'], 36103 rotation: flatStyle['shape-rotation'], 36104 rotateWithView: flatStyle['shape-rotate-with-view'], 36105 scale: flatStyle['shape-scale'], 36106 declutterMode: flatStyle['shape-declutter-mode'], 36107 }); 36108 36109 return shape; 36110 } 36111 36112 const circleRadius = flatStyle['circle-radius']; 36113 if (circleRadius) { 36114 const prefix = 'circle-'; 36115 const circle = new Circle({ 36116 radius: circleRadius,
36117 fill: getFill(flatStyle, prefix), 36118 stroke: getStroke(flatStyle, prefix), 36119 displacement: flatStyle['circle-displacement'], 36120 scale: flatStyle['circle-scale'], 36121 rotation: flatStyle['circle-rotation'], 36122 rotateWithView: flatStyle['circle-rotate-with-view'], 36123 declutterMode: flatStyle['circle-declutter-mode'], 36124 }); 36125 36126 return circle; 36127 } 36128 36129 return; 36130} 36131 36132;// CONCATENATED MODULE: ./node_modules/ol/layer/BaseVector.js 36133/** 36134 * @module ol/layer/BaseVector 36135 */ 36136 36137 36138 36139 36140 36141/** 36142 * @template {import("../source/Vector.js").default|import("../source/VectorTile.js").default} VectorSourceType 36143 * @typedef {Object} Options 36144 * @property {string} [className='ol-layer'] A CSS class name to set to the layer element. 36145 * @property {number} [opacity=1] Opacity (0, 1). 36146 * @property {boolean} [visible=true] Visibility. 36147 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be 36148 * rendered outside of this extent. 36149 * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers 36150 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed 36151 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()` 36152 * method was used. 36153 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be 36154 * visible. 36155 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will 36156 * be visible. 36157 * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be 36158 * visible. 36159 * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will 36160 * be visible. 36161 * @property {import("../render.js").OrderFunction} [renderOrder] Render order. Function to be used when sorting 36162 * features before rendering. By default features are drawn in the order that they are created. Use 36163 * `null` to avoid the sort, but get an undefined draw order. 36164 * @property {number} [renderBuffer=100] The buffer in pixels around the viewport extent used by the 36165 * renderer when getting features from the vector source for the rendering or hit-detection. 36166 * Recommended value: the size of the largest symbol, line width or label. 36167 * @property {VectorSourceType} [source] Source. 36168 * @property {import("../Map.js").default} [map] Sets the layer as overlay on a map. The map will not manage 36169 * this layer in its layers collection, and the layer will be rendered on top. This is useful for 36170 * temporary layers. The standard way to add a layer to a map and have it managed by the map is to 36171 * use [map.addLayer()]{@link import("../Map.js").default#addLayer}. 36172 * @property {boolean} [declutter=false] Declutter images and text. Decluttering is applied to all 36173 * image and text styles of all Vector and VectorTile layers that have set this to `true`. The priority 36174 * is defined by the z-index of the layer, the `zIndex` of the style and the render order of features. 36175 * Higher z-index means higher priority. Within the same z-index, a feature rendered before another has 36176 * higher priority. 36177 * 36178 * As an optimization decluttered features from layers with the same `className` are rendered above 36179 * the fill and stroke styles of all of those layers regardless of z-index. To opt out of this 36180 * behavior and place declutterd features with their own layer configure the layer with a `className` 36181 * other than `ol-layer`. 36182 * @property {import("../style/Style.js").StyleLike|import("../style/flat.js").FlatStyleLike|null} [style] Layer style. When set to `null`, only 36183 * features that have their own style will be rendered. See {@link module:ol/style/Style~Style} for the default style 36184 * which will be used if this is not set. 36185 * @property {import("./Base.js").BackgroundColor} [background] Background color for the layer. If not specified, no background 36186 * will be rendered. 36187 * @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will 36188 * be recreated during animations. This means that no vectors will be shown clipped, but the 36189 * setting will have a performance impact for large amounts of vector data. When set to `false`, 36190 * batches will be recreated when no animation is active. 36191 * @property {boolean} [updateWhileInteracting=false] When set to `true`, feature batches will 36192 * be recreated during interactions. See also `updateWhileAnimating`. 36193 * @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`. 36194 */ 36195 36196/** 36197 * @enum {string} 36198 * @private 36199 */ 36200const BaseVector_Property = { 36201 RENDER_ORDER: 'renderOrder', 36202}; 36203 36204/** 36205 * @classdesc 36206 * Vector data that is rendered client-side. 36207 * Note that any property set in the options is set as a {@link module:ol/Object~BaseObject} 36208 * property on the layer object; for example, setting `title: 'My Title'` in the 36209 * options means that `title` is observable, and has get/set accessors. 36210 * 36211 * @template {import("../source/Vector.js").default|import("../source/VectorTile.js").default} VectorSourceType 36212 * @template {import("../renderer/canvas/VectorLayer.js").default|import("../renderer/canvas/VectorTileLayer.js").default|import("../renderer/canvas/VectorImageLayer.js").default|import("../renderer/webgl/PointsLayer.js").default}
36212 RendererType 36213 * @extends {Layer<VectorSourceType, RendererType>} 36214 * @api 36215 */ 36216class BaseVectorLayer extends layer_Layer { 36217 /** 36218 * @param {Options<VectorSourceType>} [options] Options. 36219 */ 36220 constructor(options) { 36221 options = options ? options : {}; 36222 36223 const baseOptions = Object.assign({}, options); 36224 36225 delete baseOptions.style; 36226 delete baseOptions.renderBuffer; 36227 delete baseOptions.updateWhileAnimating; 36228 delete baseOptions.updateWhileInteracting; 36229 super(baseOptions); 36230 36231 /** 36232 * @private 36233 * @type {boolean} 36234 */ 36235 this.declutter_ = 36236 options.declutter !== undefined ? options.declutter : false; 36237 36238 /** 36239 * @type {number} 36240 * @private 36241 */ 36242 this.renderBuffer_ = 36243 options.renderBuffer !== undefined ? options.renderBuffer : 100; 36244 36245 /** 36246 * User provided style. 36247 * @type {import("../style/Style.js").StyleLike} 36248 * @private 36249 */ 36250 this.style_ = null; 36251 36252 /** 36253 * Style function for use within the library. 36254 * @type {import("../style/Style.js").StyleFunction|undefined} 36255 * @private 36256 */ 36257 this.styleFunction_ = undefined; 36258 36259 this.setStyle(options.style); 36260 36261 /** 36262 * @type {boolean} 36263 * @private 36264 */ 36265 this.updateWhileAnimating_ = 36266 options.updateWhileAnimating !== undefined 36267 ? options.updateWhileAnimating 36268 : false; 36269 36270 /** 36271 * @type {boolean} 36272 * @private 36273 */ 36274 this.updateWhileInteracting_ = 36275 options.updateWhileInteracting !== undefined 36276 ? options.updateWhileInteracting 36277 : false; 36278 } 36279 36280 /** 36281 * @return {boolean} Declutter. 36282 */ 36283 getDeclutter() { 36284 return this.declutter_; 36285 } 36286 36287 /** 36288 * Get the topmost feature that intersects the given pixel on the viewport. Returns a promise 36289 * that resolves with an array of features. The array will either contain the topmost feature 36290 * when a hit was detected, or it will be empty. 36291 * 36292 * The hit detection algorithm used for this method is optimized for performance, but is less 36293 * accurate than the one used in [map.getFeaturesAtPixel()]{@link import("../Map.js").default#getFeaturesAtPixel}. 36294 * Text is not considered, and icons are only represented by their bounding box instead of the exact 36295 * image. 36296 * 36297 * @param {import("../pixel.js").Pixel} pixel Pixel. 36298 * @return {Promise<Array<import("../Feature").default>>} Promise that resolves with an array of features. 36299 * @api 36300 */ 36301 getFeatures(pixel) { 36302 return super.getFeatures(pixel); 36303 } 36304 36305 /** 36306 * @return {number|undefined} Render buffer. 36307 */ 36308 getRenderBuffer() { 36309 return this.renderBuffer_; 36310 } 36311 36312 /** 36313 * @return {function(import("../Feature.js").default, import("../Feature.js").default): number|null|undefined} Render 36314 * order. 36315 */ 36316 getRenderOrder() { 36317 return /** @type {import("../render.js").OrderFunction|null|undefined} */ ( 36318 this.get(BaseVector_Property.RENDER_ORDER) 36319 ); 36320 } 36321 36322 /** 36323 * Get the style for features. This returns whatever was passed to the `style` 36324 * option at construction or to the `setStyle` method. 36325 * @return {import("../style/Style.js").StyleLike|null|undefined} Layer style. 36326 * @api 36327 */ 36328 getStyle() { 36329 return this.style_; 36330 } 36331 36332 /** 36333 * Get the style function. 36334 * @return {import("../style/Style.js").StyleFunction|undefined} Layer style function. 36335 * @api 36336 */ 36337 getStyleFunction() { 36338 return this.styleFunction_; 36339 } 36340 36341 /** 36342 * @return {boolean} Whether the rendered layer should be updated while 36343 * animating. 36344 */ 36345 getUpdateWhileAnimating() { 36346 return this.updateWhileAnimating_; 36347 } 36348 36349 /** 36350 * @return {boolean} Whether the rendered layer should be updated while 36351 * interacting. 36352 */ 36353 getUpdateWhileInteracting() { 36354 return this.updateWhileInteracting_; 36355 } 36356 36357 /** 36358 * Render declutter items for this layer 36359 * @param {import("../Map.js").FrameState} frameState Frame state. 36360 */ 36361 renderDeclutter(frameState) { 36362 if (!frameState.declutterTree) { 36363 frameState.declutterTree = new rbush_min(9); 36364 } 36365 /** @type {*} */ (this.getRenderer()).renderDeclutter(frameState); 36366 } 36367 36368 /** 36369 * @param {import("../render.js").OrderFunction|null|undefined} renderOrder 36370 * Render order. 36371 */ 36372 setRenderOrder(renderOrder) { 36373 this.set(BaseVector_Property.RENDER_ORDER, renderOrder); 36374 } 36375 36376 /** 36377 * Set the style for features. This can be a single style object, an array 36378 * of styles, or a function that takes a feature and resolution and returns 36379 * an array of styles. If set to `null`, the layer has no style (a `null` style), 36380 * so only features that have their own styles will be rendered in the layer. C
36380all 36381 * `setStyle()` without arguments to reset to the default style. See 36382 * [the ol/style/Style module]{@link module:ol/style/Style~Style} for information on the default style. 36383 * 36384 * If your layer has a static style, you can use "flat" style object literals instead of 36385 * using the `Style` and symbolizer constructors (`Fill`, `Stroke`, etc.). See the documentation 36386 * for the [flat style types]{@link module:ol/style/flat~FlatStyle} to see what properties are supported. 36387 * 36388 * @param {import("../style/Style.js").StyleLike|import("../style/flat.js").FlatStyleLike|null} [style] Layer style. 36389 * @api 36390 */ 36391 setStyle(style) { 36392 /** 36393 * @type {import("../style/Style.js").StyleLike|null} 36394 */ 36395 let styleLike; 36396 36397 if (style === undefined) { 36398 styleLike = createDefaultStyle; 36399 } else if (style === null) { 36400 styleLike = null; 36401 } else if (typeof style === 'function') { 36402 styleLike = style; 36403 } else if (style instanceof style_Style) { 36404 styleLike = style; 36405 } else if (Array.isArray(style)) { 36406 const len = style.length; 36407 36408 /** 36409 * @type {Array<Style>} 36410 */ 36411 const styles = new Array(len); 36412 36413 for (let i = 0; i < len; ++i) { 36414 const s = style[i]; 36415 if (s instanceof style_Style) { 36416 styles[i] = s; 36417 } else { 36418 styles[i] = toStyle(s); 36419 } 36420 } 36421 styleLike = styles; 36422 } else { 36423 styleLike = toStyle(style); 36424 } 36425 36426 this.style_ = styleLike; 36427 this.styleFunction_ = 36428 style === null ? undefined : toFunction(this.style_); 36429 this.changed(); 36430 } 36431} 36432 36433/* harmony default export */ const BaseVector = (BaseVectorLayer); 36434 36435;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/Instruction.js 36436/** 36437 * @module ol/render/canvas/Instruction 36438 */ 36439 36440/** 36441 * @enum {number} 36442 */ 36443const Instruction = { 36444 BEGIN_GEOMETRY: 0, 36445 BEGIN_PATH: 1, 36446 CIRCLE: 2, 36447 CLOSE_PATH: 3, 36448 CUSTOM: 4, 36449 DRAW_CHARS: 5, 36450 DRAW_IMAGE: 6, 36451 END_GEOMETRY: 7, 36452 FILL: 8, 36453 MOVE_TO_LINE_TO: 9, 36454 SET_FILL_STYLE: 10, 36455 SET_STROKE_STYLE: 11, 36456 STROKE: 12, 36457}; 36458 36459/** 36460 * @type {Array<Instruction>} 36461 */ 36462const fillInstruction = [Instruction.FILL]; 36463 36464/** 36465 * @type {Array<Instruction>} 36466 */ 36467const strokeInstruction = [Instruction.STROKE]; 36468 36469/** 36470 * @type {Array<Instruction>} 36471 */ 36472const beginPathInstruction = [Instruction.BEGIN_PATH]; 36473 36474/** 36475 * @type {Array<Instruction>} 36476 */ 36477const closePathInstruction = [Instruction.CLOSE_PATH]; 36478 36479/* harmony default export */ const canvas_Instruction = (Instruction); 36480 36481;// CONCATENATED MODULE: ./node_modules/ol/render/VectorContext.js 36482/** 36483 * @module ol/render/VectorContext 36484 */ 36485 36486/** 36487 * @classdesc 36488 * Context for drawing geometries. A vector context is available on render 36489 * events and does not need to be constructed directly. 36490 * @api 36491 */ 36492class VectorContext { 36493 /** 36494 * Render a geometry with a custom renderer. 36495 * 36496 * @param {import("../geom/SimpleGeometry.js").default} geometry Geometry. 36497 * @param {import("../Feature.js").FeatureLike} feature Feature. 36498 * @param {Function} renderer Renderer. 36499 * @param {Function} hitDetectionRenderer Renderer. 36500 */ 36501 drawCustom(geometry, feature, renderer, hitDetectionRenderer) {} 36502 36503 /** 36504 * Render a geometry. 36505 * 36506 * @param {import("../geom/Geometry.js").default} geometry The geometry to render. 36507 */ 36508 drawGeometry(geometry) {} 36509 36510 /** 36511 * Set the rendering style. 36512 * 36513 * @param {import("../style/Style.js").default} style The rendering style. 36514 */ 36515 setStyle(style) {} 36516 36517 /** 36518 * @param {import("../geom/Circle.js").default} circleGeometry Circle geometry. 36519 * @param {import("../Feature.js").default} feature Feature. 36520 */ 36521 drawCircle(circleGeometry, feature) {} 36522 36523 /** 36524 * @param {import("../Feature.js").default} feature Feature. 36525 * @param {import("../style/Style.js").default} style Style. 36526 */ 36527 drawFeature(feature, style) {} 36528 36529 /** 36530 * @param {import("../geom/GeometryCollection.js").default} geometryCollectionGeometry Geometry collection. 36531 * @param {import("../Feature.js").default} feature Feature. 36532 */ 36533 drawGeometryCollection(geometryCollectionGeometry, feature) {} 36534 36535 /** 36536 * @param {import("../geom/LineString.js").default|import("./Feature.js").default} lineStringGeometry Line string geometry. 36537 * @param {import("../Feature.js").FeatureLike} feature Feature. 36538 */ 36539 drawLineString(lineStringGeometry, feature) {} 36540 36541 /** 36542 * @param {import("../geom/MultiLineString.js").default|import("./Feature.js").default} multiLineStringGeometry MultiLineString geometry. 36543 * @param {import("../Feature.js").FeatureLike} feature Feature. 36544 */ 36545 drawMultiLineString(multiLineStringGeometry, feature) {} 36546 36547 /** 36548 * @param {import("../geom/MultiPoint.js").default|import("./Feature.js").default} multiPointGeometry MultiPoint geometry. 36549 * @param {import("../Feature.js").FeatureLike} feature Feature. 36550 */ 36551 drawMultiPoint(multiPointGeometry, feature) {} 36552 36553 /** 36554 * @param {import("../geom/MultiPolygon.js").default} multiPolygonGeometry MultiPolygon geometry. 36555 * @param {import("../Feature.js").FeatureLike} feature Feature. 36556 */ 36557 drawMultiPolygon(multiPolygonGeometry, feature) {} 36558 36559 /** 36560 * @param {import("../geom/Point.js").default|import("./Feature.js").default} pointGeometry Point geometry. 36561 * @param {import("../Feature.js").FeatureLike} feature Feature. 36562 */ 36563 drawPoint(pointGeometry, feature) {} 36564 36565 /** 36566 * @param {import("../geom/Polygon.js").default|import("./Feature.js").default} polygonGeometry Polygon geometry. 36567 * @param {import("../Feature.js").FeatureLike} feature Feature. 36568 */ 36569 drawPolygon(polygonGeometry, feature) {} 36570 36571 /** 36572 * @param {import("../geom/SimpleGeometry.js").default|import("./Feature.js").default} geometry Geometry. 36573 * @param {import("../Feature.js").FeatureLike} feature Feature. 36574 */ 36575 drawText(geometry, feature) {} 36576 36577 /** 36578 * @param {import("../style/Fill.js").default} fillStyle Fill style. 36579 * @param {import("../style/Stroke.js").default} strokeStyle Stroke style. 36580 */ 36581 setFillStrokeStyle(fillStyle, strokeStyle) {} 36582 36583 /** 36584 * @param {import("../style/Image.js").default} imageStyle Image style. 36585 * @param {import("../render/canvas.js").DeclutterImageWithText} [declutterImageWithText] Shared data for combined decluttering with a text style. 36586 */ 36587 setImageStyle(imageStyle, declutterImageWithText) {} 36588 36589 /** 36590 * @param {import("../style/Text.js").default} textStyle Text style. 36591 * @param {import("../render/canvas.js").DeclutterImageWithText} [declutterImageWithText] Shared data for combined decluttering with an image style. 36592 */ 36593 setTextStyle(textStyle, declutterImageWithText) {} 36594} 36595 36596/* harmony default export */ const render_VectorContext = (VectorContext); 36597 36598;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/Builder.js 36599/** 36600 * @module ol/render/canvas/Builder 36601 */ 36602 36603 36604 36605 36606 36607 36608 36609 36610 36611class CanvasBuilder extends render_VectorContext { 36612 /** 36613 * @param {number} tolerance Tolerance. 36614 * @param {import("../../extent.js").Extent} maxExtent Maximum extent. 36615 * @param {number} resolution Resolution. 36616 * @param {number} pixelRatio Pixel ratio. 36617 */ 36618 constructor(tolerance, maxExtent, resolution, pixelRatio) { 36619 super(); 36620 36621 /** 36622 * @protected 36623 * @type {number} 36624 */ 36625 this.tolerance = tolerance; 36626 36627 /** 36628 * @protected 36629 * @const 36630 * @type {import("../../extent.js").Extent} 36631 */ 36632 this.maxExtent = maxExtent; 36633 36634 /** 36635 * @protected 36636 * @type {number} 36637 */ 36638 this.pixelRatio = pixelRatio; 36639 36640 /** 36641 * @protected 36642 * @type {number} 36643 */ 36644 this.maxLineWidth = 0; 36645 36646 /** 36647 * @protected 36648 * @const 36649 * @type {number} 36650 */ 36651 this.resolution = resolution; 36652 36653 /** 36654 * @private 36655 * @type {Array<*>} 36656 */ 36657 this.beginGeometryInstruction1_ = null; 36658 36659 /** 36660 * @private 36661 * @type {Array<*>} 36662 */ 36663 this.beginGeometryInstruction2_ = null; 36664 36665 /** 36666 * @private 36667 * @type {import("../../extent.js").Extent} 36668 */ 36669 this.bufferedMaxExtent_ = null; 36670 36671 /** 36672 * @protected 36673 * @type {Array<*>} 36674 */ 36675 this.instructions = []; 36676 36677 /** 36678 * @protected 36679 * @type {Array<number>} 36680 */ 36681 this.coordinates = []; 36682 36683 /** 36684 * @private 36685 * @type {import("../../coordinate.js").Coordinate} 36686 */ 36687 this.tmpCoordinate_ = []; 36688 36689 /** 36690 * @protected 36691 * @type {Array<*>} 36692 */ 36693 this.hitDetectionInstructions = []; 36694 36695 /** 36696 * @protected 36697 * @type {import("../canvas.js").FillStrokeState} 36698 */ 36699 this.state = /** @type {import("../canvas.js").FillStrokeState} */ ({}); 36700 } 36701 36702 /** 36703 * @protected 36704 * @param {Array<number>} dashArray Dash array. 36705 * @return {Array<number>} Dash array with pixel ratio applied 36706 */ 36707 applyPixelRatio(dashArray) { 36708 const pixelRatio = this.pixelRatio; 36709 return pixelRatio == 1 36710 ? dashArray 36711 : dashArray.map(function (dash) { 36712 return dash * pixelRatio; 36713 }); 36714 } 36715 36716 /** 36717 * @param {Array<number>} flatCoordinates Flat coordinates. 36718 * @param {number} stride Stride. 36719 * @protected 36720 * @return {number} My end 36721 */ 36722 appendFlatPointCoordinates(flatCoordinates, stride) { 36723 const extent = this.getBufferedMaxExtent(); 36724 const tmpCoord = this.tmpCoordinate_; 36725 const coordinates = this.coordinates;
36726 let myEnd = coordinates.length; 36727 for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) { 36728 tmpCoord[0] = flatCoordinates[i]; 36729 tmpCoord[1] = flatCoordinates[i + 1]; 36730 if (containsCoordinate(extent, tmpCoord)) { 36731 coordinates[myEnd++] = tmpCoord[0]; 36732 coordinates[myEnd++] = tmpCoord[1]; 36733 } 36734 } 36735 return myEnd; 36736 } 36737 36738 /** 36739 * @param {Array<number>} flatCoordinates Flat coordinates. 36740 * @param {number} offset Offset. 36741 * @param {number} end End. 36742 * @param {number} stride Stride. 36743 * @param {boolean} closed Last input coordinate equals first. 36744 * @param {boolean} skipFirst Skip first coordinate. 36745 * @protected 36746 * @return {number} My end. 36747 */ 36748 appendFlatLineCoordinates( 36749 flatCoordinates, 36750 offset, 36751 end, 36752 stride, 36753 closed, 36754 skipFirst 36755 ) { 36756 const coordinates = this.coordinates; 36757 let myEnd = coordinates.length; 36758 const extent = this.getBufferedMaxExtent(); 36759 if (skipFirst) { 36760 offset += stride; 36761 } 36762 let lastXCoord = flatCoordinates[offset]; 36763 let lastYCoord = flatCoordinates[offset + 1]; 36764 const nextCoord = this.tmpCoordinate_; 36765 let skipped = true; 36766 36767 let i, lastRel, nextRel; 36768 for (i = offset + stride; i < end; i += stride) { 36769 nextCoord[0] = flatCoordinates[i]; 36770 nextCoord[1] = flatCoordinates[i + 1]; 36771 nextRel = coordinateRelationship(extent, nextCoord); 36772 if (nextRel !== lastRel) { 36773 if (skipped) { 36774 coordinates[myEnd++] = lastXCoord; 36775 coordinates[myEnd++] = lastYCoord; 36776 skipped = false; 36777 } 36778 coordinates[myEnd++] = nextCoord[0]; 36779 coordinates[myEnd++] = nextCoord[1]; 36780 } else if (nextRel === Relationship.INTERSECTING) { 36781 coordinates[myEnd++] = nextCoord[0]; 36782 coordinates[myEnd++] = nextCoord[1]; 36783 skipped = false; 36784 } else { 36785 skipped = true; 36786 } 36787 lastXCoord = nextCoord[0]; 36788 lastYCoord = nextCoord[1]; 36789 lastRel = nextRel; 36790 } 36791 36792 // Last coordinate equals first or only one point to append: 36793 if ((closed && skipped) || i === offset + stride) { 36794 coordinates[myEnd++] = lastXCoord; 36795 coordinates[myEnd++] = lastYCoord; 36796 } 36797 return myEnd; 36798 } 36799 36800 /** 36801 * @param {Array<number>} flatCoordinates Flat coordinates. 36802 * @param {number} offset Offset. 36803 * @param {Array<number>} ends Ends. 36804 * @param {number} stride Stride. 36805 * @param {Array<number>} builderEnds Builder ends. 36806 * @return {number} Offset. 36807 */ 36808 drawCustomCoordinates_(flatCoordinates, offset, ends, stride, builderEnds) { 36809 for (let i = 0, ii = ends.length; i < ii; ++i) { 36810 const end = ends[i]; 36811 const builderEnd = this.appendFlatLineCoordinates( 36812 flatCoordinates, 36813 offset, 36814 end, 36815 stride, 36816 false, 36817 false 36818 ); 36819 builderEnds.push(builderEnd); 36820 offset = end; 36821 } 36822 return offset; 36823 } 36824 36825 /** 36826 * @param {import("../../geom/SimpleGeometry.js").default} geometry Geometry. 36827 * @param {import("../../Feature.js").FeatureLike} feature Feature. 36828 * @param {Function} renderer Renderer. 36829 * @param {Function} hitDetectionRenderer Renderer. 36830 */ 36831 drawCustom(geometry, feature, renderer, hitDetectionRenderer) { 36832 this.beginGeometry(geometry, feature); 36833 36834 const type = geometry.getType(); 36835 const stride = geometry.getStride(); 36836 const builderBegin = this.coordinates.length; 36837 36838 let flatCoordinates, builderEnd, builderEnds, builderEndss; 36839 let offset; 36840 36841 switch (type) { 36842 case 'MultiPolygon': 36843 flatCoordinates = 36844 /** @type {import("../../geom/MultiPolygon.js").default} */ ( 36845 geometry 36846 ).getOrientedFlatCoordinates(); 36847 builderEndss = []; 36848 const endss = 36849 /** @type {import("../../geom/MultiPolygon.js").default} */ ( 36850 geometry 36851 ).getEndss(); 36852 offset = 0; 36853 for (let i = 0, ii = endss.length; i < ii; ++i) { 36854 const myEnds = []; 36855 offset = this.drawCustomCoordinates_( 36856 flatCoordinates, 36857 offset, 36858 endss[i], 36859 stride, 36860 myEnds 36861 ); 36862 builderEndss.push(myEnds); 36863 } 36864 this.instructions.push([
36865 canvas_Instruction.CUSTOM, 36866 builderBegin, 36867 builderEndss, 36868 geometry, 36869 renderer, 36870 inflateMultiCoordinatesArray, 36871 ]); 36872 this.hitDetectionInstructions.push([ 36873 canvas_Instruction.CUSTOM, 36874 builderBegin, 36875 builderEndss, 36876 geometry, 36877 hitDetectionRenderer || renderer, 36878 inflateMultiCoordinatesArray, 36879 ]); 36880 break; 36881 case 'Polygon': 36882 case 'MultiLineString': 36883 builderEnds = []; 36884 flatCoordinates = 36885 type == 'Polygon' 36886 ? /** @type {import("../../geom/Polygon.js").default} */ ( 36887 geometry 36888 ).getOrientedFlatCoordinates() 36889 : geometry.getFlatCoordinates(); 36890 offset = this.drawCustomCoordinates_( 36891 flatCoordinates, 36892 0, 36893 /** @type {import("../../geom/Polygon.js").default|import("../../geom/MultiLineString.js").default} */ ( 36894 geometry 36895 ).getEnds(), 36896 stride, 36897 builderEnds 36898 ); 36899 this.instructions.push([ 36900 canvas_Instruction.CUSTOM, 36901 builderBegin, 36902 builderEnds, 36903 geometry, 36904 renderer, 36905 inflateCoordinatesArray, 36906 ]); 36907 this.hitDetectionInstructions.push([ 36908 canvas_Instruction.CUSTOM, 36909 builderBegin, 36910 builderEnds, 36911 geometry, 36912 hitDetectionRenderer || renderer, 36913 inflateCoordinatesArray, 36914 ]); 36915 break; 36916 case 'LineString': 36917 case 'Circle': 36918 flatCoordinates = geometry.getFlatCoordinates(); 36919 builderEnd = this.appendFlatLineCoordinates( 36920 flatCoordinates, 36921 0, 36922 flatCoordinates.length, 36923 stride, 36924 false, 36925 false 36926 ); 36927 this.instructions.push([ 36928 canvas_Instruction.CUSTOM, 36929 builderBegin, 36930 builderEnd, 36931 geometry, 36932 renderer, 36933 inflateCoordinates, 36934 ]); 36935 this.hitDetectionInstructions.push([ 36936 canvas_Instruction.CUSTOM, 36937 builderBegin, 36938 builderEnd, 36939 geometry, 36940 hitDetectionRenderer || renderer, 36941 inflateCoordinates, 36942 ]); 36943 break; 36944 case 'MultiPoint': 36945 flatCoordinates = geometry.getFlatCoordinates(); 36946 builderEnd = this.appendFlatPointCoordinates(flatCoordinates, stride); 36947 36948 if (builderEnd > builderBegin) { 36949 this.instructions.push([ 36950 canvas_Instruction.CUSTOM, 36951 builderBegin, 36952 builderEnd, 36953 geometry, 36954 renderer, 36955 inflateCoordinates, 36956 ]); 36957 this.hitDetectionInstructions.push([ 36958 canvas_Instruction.CUSTOM, 36959 builderBegin, 36960 builderEnd, 36961 geometry, 36962 hitDetectionRenderer || renderer, 36963 inflateCoordinates, 36964 ]); 36965 } 36966 break; 36967 case 'Point': 36968 flatCoordinates = geometry.getFlatCoordinates(); 36969 this.coordinates.push(flatCoordinates[0], flatCoordinates[1]); 36970 builderEnd = this.coordinates.length; 36971 36972 this.instructions.push([ 36973 canvas_Instruction.CUSTOM, 36974 builderBegin, 36975 builderEnd, 36976 geometry, 36977 renderer, 36978 ]); 36979 this.hitDetectionInstructions.push([ 36980 canvas_Instruction.CUSTOM, 36981 builderBegin, 36982 builderEnd, 36983 geometry, 36984 hitDetectionRenderer || renderer, 36985 ]); 36986 break; 36987 default: 36988 } 36989 this.endGeometry(feature); 36990 } 36991 36992 /** 36993 * @protected 36994 * @param {import("../../geom/Geometry").default|import("../Feature.js").default} geometry The geometry. 36995 * @param {import("../../Feature.js").FeatureLike} feature Feature. 36996 */ 36997 beginGeometry(geometry, feature) { 36998 this.beginGeometryInstruction1_ = [ 36999 canvas_Instruction.BEGIN_GEOMETRY, 37000 feature, 37001 0, 37002 geometry, 37003 ]; 37004 this.instructions.push(this.beginGeometryInstruction1_); 37005 this.beginGeometryInstruction2_ = [ 37006 canvas_Instruction.BEGIN_GEOMETRY, 37007 feature, 37008 0, 37009 geometry, 37010 ]; 37011 this.hitDetectionInstructions.push(this.beginGeometryInstruction2_); 37012 } 37013 37014 /** 37015 * @return {import("../canvas.js").SerializableInstructions} the serializable instructions. 37016 */ 37017 finish() { 37018 return { 37019 instructions: this.instructions, 37020 hitDetectionInstructions: this.hitDetectionInstructions, 37021 coordinates: this.coordinates, 37022 }; 37023 } 37024 37025 /** 37026 * Reverse the hit detection instructions. 37027 */ 37028 reverseHitDetectionInstructions() { 37029 const hitDetectionInstructions = this.hitDetectionInstructions; 37030 // step 1 - reverse array 37031 hitDetectionInstructions.reverse(); 37032 // step 2 - reverse instructions within geometry blocks 37033 let i; 37034 const n = hitDetectionInstructions.length; 37035 let instruction; 37036 let type; 37037 let begin = -1; 37038 for (i = 0; i < n; ++i) { 37039 instruction = hitDetectionInstructions[i]; 37040 type = /** @type {import("./Instruction.js").default} */ (instruction[0]);
37041 if (type == canvas_Instruction.END_GEOMETRY) { 37042 begin = i; 37043 } else if (type == canvas_Instruction.BEGIN_GEOMETRY) { 37044 instruction[2] = i; 37045 reverseSubArray(this.hitDetectionInstructions, begin, i); 37046 begin = -1; 37047 } 37048 } 37049 } 37050 37051 /** 37052 * @param {import("../../style/Fill.js").default} fillStyle Fill style. 37053 * @param {import("../../style/Stroke.js").default} strokeStyle Stroke style. 37054 */ 37055 setFillStrokeStyle(fillStyle, strokeStyle) { 37056 const state = this.state; 37057 if (fillStyle) { 37058 const fillStyleColor = fillStyle.getColor(); 37059 state.fillStyle = asColorLike( 37060 fillStyleColor ? fillStyleColor : defaultFillStyle 37061 ); 37062 } else { 37063 state.fillStyle = undefined; 37064 } 37065 if (strokeStyle) { 37066 const strokeStyleColor = strokeStyle.getColor(); 37067 state.strokeStyle = asColorLike( 37068 strokeStyleColor ? strokeStyleColor : defaultStrokeStyle 37069 ); 37070 const strokeStyleLineCap = strokeStyle.getLineCap(); 37071 state.lineCap = 37072 strokeStyleLineCap !== undefined ? strokeStyleLineCap : defaultLineCap; 37073 const strokeStyleLineDash = strokeStyle.getLineDash(); 37074 state.lineDash = strokeStyleLineDash 37075 ? strokeStyleLineDash.slice() 37076 : defaultLineDash; 37077 const strokeStyleLineDashOffset = strokeStyle.getLineDashOffset(); 37078 state.lineDashOffset = strokeStyleLineDashOffset 37079 ? strokeStyleLineDashOffset 37080 : defaultLineDashOffset; 37081 const strokeStyleLineJoin = strokeStyle.getLineJoin(); 37082 state.lineJoin = 37083 strokeStyleLineJoin !== undefined 37084 ? strokeStyleLineJoin 37085 : defaultLineJoin; 37086 const strokeStyleWidth = strokeStyle.getWidth(); 37087 state.lineWidth = 37088 strokeStyleWidth !== undefined ? strokeStyleWidth : defaultLineWidth; 37089 const strokeStyleMiterLimit = strokeStyle.getMiterLimit(); 37090 state.miterLimit = 37091 strokeStyleMiterLimit !== undefined 37092 ? strokeStyleMiterLimit 37093 : defaultMiterLimit; 37094 37095 if (state.lineWidth > this.maxLineWidth) { 37096 this.maxLineWidth = state.lineWidth; 37097 // invalidate the buffered max extent cache 37098 this.bufferedMaxExtent_ = null; 37099 } 37100 } else { 37101 state.strokeStyle = undefined; 37102 state.lineCap = undefined; 37103 state.lineDash = null; 37104 state.lineDashOffset = undefined; 37105 state.lineJoin = undefined; 37106 state.lineWidth = undefined; 37107 state.miterLimit = undefined; 37108 } 37109 } 37110 37111 /** 37112 * @param {import("../canvas.js").FillStrokeState} state State. 37113 * @return {Array<*>} Fill instruction. 37114 */ 37115 createFill(state) { 37116 const fillStyle = state.fillStyle; 37117 /** @type {Array<*>} */ 37118 const fillInstruction = [canvas_Instruction.SET_FILL_STYLE, fillStyle]; 37119 if (typeof fillStyle !== 'string') { 37120 // Fill is a pattern or gradient - align it! 37121 fillInstruction.push(true); 37122 } 37123 return fillInstruction; 37124 } 37125 37126 /** 37127 * @param {import("../canvas.js").FillStrokeState} state State. 37128 */ 37129 applyStroke(state) { 37130 this.instructions.push(this.createStroke(state)); 37131 } 37132 37133 /** 37134 * @param {import("../canvas.js").FillStrokeState} state State. 37135 * @return {Array<*>} Stroke instruction. 37136 */ 37137 createStroke(state) { 37138 return [ 37139 canvas_Instruction.SET_STROKE_STYLE, 37140 state.strokeStyle, 37141 state.lineWidth * this.pixelRatio, 37142 state.lineCap, 37143 state.lineJoin, 37144 state.miterLimit, 37145 this.applyPixelRatio(state.lineDash), 37146 state.lineDashOffset * this.pixelRatio, 37147 ]; 37148 } 37149 37150 /** 37151 * @param {import("../canvas.js").FillStrokeState} state State. 37152 * @param {function(this:CanvasBuilder, import("../canvas.js").FillStrokeState):Array<*>} createFill Create fill. 37153 */ 37154 updateFillStyle(state, createFill) { 37155 const fillStyle = state.fillStyle; 37156 if (typeof fillStyle !== 'string' || state.currentFillStyle != fillStyle) { 37157 if (fillStyle !== undefined) { 37158 this.instructions.push(createFill.call(this, state)); 37159 } 37160 state.currentFillStyle = fillStyle; 37161 } 37162 } 37163 37164 /** 37165 * @param {import("../canvas.js").FillStrokeState} state State. 37166 * @param {function(this:CanvasBuilder, import("../canvas.js").FillStrokeState): void} applyStroke Apply stroke. 37167 */ 37168 updateStrokeStyle(state, applyStroke) { 37169 const strokeStyle = state.strokeStyle; 37170 const lineCap = state.lineCap; 37171 const lineDash = state.lineDash; 37172 const lineDashOffset = state.lineDashOffset; 37173 const lineJoin = state.lineJoin; 37174 const lineWidth = state.lineWidth; 37175 const miterLimit = state.miterLimit; 37176 if ( 37177 state.currentStrokeStyle != strokeStyle || 37178 state.currentLineCap != lineCap || 37179 (lineDash != state.currentLineDash && 37180 !equals(state.currentLineDash, lineDash)) || 37181 state.currentLineDashOffset != lineDashOffset || 37182 state.currentLineJoin != lineJoin || 37183 state.currentLineWidth != lineWidth || 37184 state.currentMiterLimit != miterLimit 37185 ) { 37186 if (strokeStyle !== undefined) { 37187 applyStroke.call(this, state); 37188 } 37189 state.currentStrokeStyle = strokeStyle; 37190 state.currentLineCap = lineCap; 37191 state.currentLineDash = lineDash; 37192 state.currentLineDashOffset = lineDashOffset; 37193 state.currentLineJoin = lineJoin; 37194 state.currentLineWidth = lineWidth;
37195 state.currentMiterLimit = miterLimit; 37196 } 37197 } 37198 37199 /** 37200 * @param {import("../../Feature.js").FeatureLike} feature Feature. 37201 */ 37202 endGeometry(feature) { 37203 this.beginGeometryInstruction1_[2] = this.instructions.length; 37204 this.beginGeometryInstruction1_ = null; 37205 this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length; 37206 this.beginGeometryInstruction2_ = null; 37207 const endGeometryInstruction = [canvas_Instruction.END_GEOMETRY, feature]; 37208 this.instructions.push(endGeometryInstruction); 37209 this.hitDetectionInstructions.push(endGeometryInstruction); 37210 } 37211 37212 /** 37213 * Get the buffered rendering extent. Rendering will be clipped to the extent 37214 * provided to the constructor. To account for symbolizers that may intersect 37215 * this extent, we calculate a buffered extent (e.g. based on stroke width). 37216 * @return {import("../../extent.js").Extent} The buffered rendering extent. 37217 * @protected 37218 */ 37219 getBufferedMaxExtent() { 37220 if (!this.bufferedMaxExtent_) { 37221 this.bufferedMaxExtent_ = clone(this.maxExtent); 37222 if (this.maxLineWidth > 0) { 37223 const width = (this.resolution * (this.maxLineWidth + 1)) / 2; 37224 buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_); 37225 } 37226 } 37227 return this.bufferedMaxExtent_; 37228 } 37229} 37230 37231/* harmony default export */ const Builder = (CanvasBuilder); 37232 37233;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/ImageBuilder.js 37234/** 37235 * @module ol/render/canvas/ImageBuilder 37236 */ 37237 37238 37239 37240class CanvasImageBuilder extends Builder { 37241 /** 37242 * @param {number} tolerance Tolerance. 37243 * @param {import("../../extent.js").Extent} maxExtent Maximum extent. 37244 * @param {number} resolution Resolution. 37245 * @param {number} pixelRatio Pixel ratio. 37246 */ 37247 constructor(tolerance, maxExtent, resolution, pixelRatio) { 37248 super(tolerance, maxExtent, resolution, pixelRatio); 37249 37250 /** 37251 * @private 37252 * @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} 37253 */ 37254 this.hitDetectionImage_ = null; 37255 37256 /** 37257 * @private 37258 * @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} 37259 */ 37260 this.image_ = null; 37261 37262 /** 37263 * @private 37264 * @type {number|undefined} 37265 */ 37266 this.imagePixelRatio_ = undefined; 37267 37268 /** 37269 * @private 37270 * @type {number|undefined} 37271 */ 37272 this.anchorX_ = undefined; 37273 37274 /** 37275 * @private 37276 * @type {number|undefined} 37277 */ 37278 this.anchorY_ = undefined; 37279 37280 /** 37281 * @private 37282 * @type {number|undefined} 37283 */ 37284 this.height_ = undefined; 37285 37286 /** 37287 * @private 37288 * @type {number|undefined} 37289 */ 37290 this.opacity_ = undefined; 37291 37292 /** 37293 * @private 37294 * @type {number|undefined} 37295 */ 37296 this.originX_ = undefined; 37297 37298 /** 37299 * @private 37300 * @type {number|undefined} 37301 */ 37302 this.originY_ = undefined; 37303 37304 /** 37305 * @private 37306 * @type {boolean|undefined} 37307 */ 37308 this.rotateWithView_ = undefined; 37309 37310 /** 37311 * @private 37312 * @type {number|undefined} 37313 */ 37314 this.rotation_ = undefined; 37315 37316 /** 37317 * @private 37318 * @type {import("../../size.js").Size|undefined} 37319 */ 37320 this.scale_ = undefined; 37321 37322 /** 37323 * @private 37324 * @type {number|undefined} 37325 */ 37326 this.width_ = undefined; 37327 37328 /** 37329 * @private 37330 * @type {"declutter"|"obstacle"|"none"|undefined} 37331 */ 37332 this.declutterMode_ = undefined; 37333 37334 /** 37335 * Data shared with a text builder for combined decluttering. 37336 * @private 37337 * @type {import("../canvas.js").DeclutterImageWithText} 37338 */ 37339 this.declutterImageWithText_ = undefined; 37340 } 37341 37342 /** 37343 * @param {import("../../geom/Point.js").default|import("../Feature.js").default} pointGeometry Point geometry. 37344 * @param {import("../../Feature.js").FeatureLike} feature Feature. 37345 */ 37346 drawPoint(pointGeometry, feature) { 37347 if (!this.image_) { 37348 return; 37349 } 37350 this.beginGeometry(pointGeometry, feature); 37351 const flatCoordinates = pointGeometry.getFlatCoordinates(); 37352 const stride = pointGeometry.getStride(); 37353 const myBegin = this.coordinates.length; 37354 const myEnd = this.appendFlatPointCoordinates(flatCoordinates, stride); 37355 this.instructions.push([
37356 canvas_Instruction.DRAW_IMAGE, 37357 myBegin, 37358 myEnd, 37359 this.image_, 37360 // Remaining arguments to DRAW_IMAGE are in alphabetical order 37361 this.anchorX_ * this.imagePixelRatio_, 37362 this.anchorY_ * this.imagePixelRatio_, 37363 Math.ceil(this.height_ * this.imagePixelRatio_), 37364 this.opacity_, 37365 this.originX_ * this.imagePixelRatio_, 37366 this.originY_ * this.imagePixelRatio_, 37367 this.rotateWithView_, 37368 this.rotation_, 37369 [ 37370 (this.scale_[0] * this.pixelRatio) / this.imagePixelRatio_, 37371 (this.scale_[1] * this.pixelRatio) / this.imagePixelRatio_, 37372 ], 37373 Math.ceil(this.width_ * this.imagePixelRatio_), 37374 this.declutterMode_, 37375 this.declutterImageWithText_, 37376 ]); 37377 this.hitDetectionInstructions.push([ 37378 canvas_Instruction.DRAW_IMAGE, 37379 myBegin, 37380 myEnd, 37381 this.hitDetectionImage_, 37382 // Remaining arguments to DRAW_IMAGE are in alphabetical order 37383 this.anchorX_, 37384 this.anchorY_, 37385 this.height_, 37386 this.opacity_, 37387 this.originX_, 37388 this.originY_, 37389 this.rotateWithView_, 37390 this.rotation_, 37391 this.scale_, 37392 this.width_, 37393 this.declutterMode_, 37394 this.declutterImageWithText_, 37395 ]); 37396 this.endGeometry(feature); 37397 } 37398 37399 /** 37400 * @param {import("../../geom/MultiPoint.js").default|import("../Feature.js").default} multiPointGeometry MultiPoint geometry. 37401 * @param {import("../../Feature.js").FeatureLike} feature Feature. 37402 */ 37403 drawMultiPoint(multiPointGeometry, feature) { 37404 if (!this.image_) { 37405 return; 37406 } 37407 this.beginGeometry(multiPointGeometry, feature); 37408 const flatCoordinates = multiPointGeometry.getFlatCoordinates(); 37409 const stride = multiPointGeometry.getStride(); 37410 const myBegin = this.coordinates.length; 37411 const myEnd = this.appendFlatPointCoordinates(flatCoordinates, stride); 37412 this.instructions.push([ 37413 canvas_Instruction.DRAW_IMAGE, 37414 myBegin, 37415 myEnd, 37416 this.image_, 37417 // Remaining arguments to DRAW_IMAGE are in alphabetical order 37418 this.anchorX_ * this.imagePixelRatio_, 37419 this.anchorY_ * this.imagePixelRatio_, 37420 Math.ceil(this.height_ * this.imagePixelRatio_), 37421 this.opacity_, 37422 this.originX_ * this.imagePixelRatio_, 37423 this.originY_ * this.imagePixelRatio_, 37424 this.rotateWithView_, 37425 this.rotation_, 37426 [ 37427 (this.scale_[0] * this.pixelRatio) / this.imagePixelRatio_, 37428 (this.scale_[1] * this.pixelRatio) / this.imagePixelRatio_, 37429 ], 37430 Math.ceil(this.width_ * this.imagePixelRatio_), 37431 this.declutterMode_, 37432 this.declutterImageWithText_, 37433 ]); 37434 this.hitDetectionInstructions.push([ 37435 canvas_Instruction.DRAW_IMAGE, 37436 myBegin, 37437 myEnd, 37438 this.hitDetectionImage_, 37439 // Remaining arguments to DRAW_IMAGE are in alphabetical order 37440 this.anchorX_, 37441 this.anchorY_, 37442 this.height_, 37443 this.opacity_, 37444 this.originX_, 37445 this.originY_, 37446 this.rotateWithView_, 37447 this.rotation_, 37448 this.scale_, 37449 this.width_, 37450 this.declutterMode_, 37451 this.declutterImageWithText_, 37452 ]); 37453 this.endGeometry(feature); 37454 } 37455 37456 /** 37457 * @return {import("../canvas.js").SerializableInstructions} the serializable instructions. 37458 */ 37459 finish() { 37460 this.reverseHitDetectionInstructions(); 37461 // FIXME this doesn't really protect us against further calls to draw*Geometry 37462 this.anchorX_ = undefined; 37463 this.anchorY_ = undefined; 37464 this.hitDetectionImage_ = null; 37465 this.image_ = null; 37466 this.imagePixelRatio_ = undefined; 37467 this.height_ = undefined; 37468 this.scale_ = undefined; 37469 this.opacity_ = undefined; 37470 this.originX_ = undefined; 37471 this.originY_ = undefined; 37472 this.rotateWithView_ = undefined; 37473 this.rotation_ = undefined; 37474 this.width_ = undefined; 37475 return super.finish(); 37476 } 37477 37478 /** 37479 * @param {import("../../style/Image.js").default} imageStyle Image style. 37480 * @param {Object} [sharedData] Shared data. 37481 */ 37482 setImageStyle(imageStyle, sharedData) { 37483 const anchor = imageStyle.getAnchor(); 37484 const size = imageStyle.getSize(); 37485 const origin = imageStyle.getOrigin(); 37486 this.imagePixelRatio_ = imageStyle.getPixelRatio(this.pixelRatio); 37487 this.anchorX_ = anchor[0]; 37488 this.anchorY_ = anchor[1]; 37489 this.hitDetectionImage_ = imageStyle.getHitDetectionImage(); 37490 this.image_ = imageStyle.getImage(this.pixelRatio); 37491 this.height_ = size[1]; 37492 this.opacity_ = imageStyle.getOpacity(); 37493 this.originX_ = origin[0]; 37494 this.originY_ = origin[1]; 37495 this.rotateWithView_ = imageStyle.getRotateWithView(); 37496 this.rotation_ = imageStyle.getRotation(); 37497 this.scale_ = imageStyle.getScaleArray(); 37498 this.width_ = size[0]; 37499 this.declutterMode_ = imageStyle.getDeclutterMode(); 37500 this.declutterImageWithText_ = sharedData; 37501 } 37502} 37503 37504/* harmony default export */ const ImageBuilder = (CanvasImageBuilder); 37505 37506;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/LineStringBuilder.js 37507/** 37508 * @module ol/render/canvas/LineStringBuilder 37509 */ 37510 37511 37512 37513 37514class CanvasLineStringBuilder extends Builder { 37515 /** 37516 * @param {number} tolerance Tolerance. 37517 * @param {import("../../extent.js").Extent} maxExtent Maximum extent. 37518 * @param {number} resolution Resolution. 37519 * @param {number} pixelRatio Pixel ratio. 37520 */ 37521 constructor(tolerance, maxExtent, resolution, pixelRatio) { 37522 super(tolerance, maxExtent, resolution, pixelRatio); 37523 } 37524 37525 /** 37526 * @param {Array<number>} flatCoordinates Flat coordinates. 37527 * @param {number} offset Offset. 37528 * @param {number} end End. 37529 * @param {number} stride Stride. 37530 * @private 37531 * @return {number} end. 37532 */ 37533 drawFlatCoordinates_(flatCoordinates, offset, end, stride) { 37534 const myBegin = this.coordinates.length; 37535 const myEnd = this.appendFlatLineCoordinates( 37536 flatCoordinates, 37537 offset, 37538 end,
37539 stride, 37540 false, 37541 false 37542 ); 37543 const moveToLineToInstruction = [ 37544 canvas_Instruction.MOVE_TO_LINE_TO, 37545 myBegin, 37546 myEnd, 37547 ]; 37548 this.instructions.push(moveToLineToInstruction); 37549 this.hitDetectionInstructions.push(moveToLineToInstruction); 37550 return end; 37551 } 37552 37553 /** 37554 * @param {import("../../geom/LineString.js").default|import("../Feature.js").default} lineStringGeometry Line string geometry. 37555 * @param {import("../../Feature.js").FeatureLike} feature Feature. 37556 */ 37557 drawLineString(lineStringGeometry, feature) { 37558 const state = this.state; 37559 const strokeStyle = state.strokeStyle; 37560 const lineWidth = state.lineWidth; 37561 if (strokeStyle === undefined || lineWidth === undefined) { 37562 return; 37563 } 37564 this.updateStrokeStyle(state, this.applyStroke); 37565 this.beginGeometry(lineStringGeometry, feature); 37566 this.hitDetectionInstructions.push( 37567 [ 37568 canvas_Instruction.SET_STROKE_STYLE, 37569 state.strokeStyle, 37570 state.lineWidth, 37571 state.lineCap, 37572 state.lineJoin, 37573 state.miterLimit, 37574 defaultLineDash, 37575 defaultLineDashOffset, 37576 ], 37577 beginPathInstruction 37578 ); 37579 const flatCoordinates = lineStringGeometry.getFlatCoordinates(); 37580 const stride = lineStringGeometry.getStride(); 37581 this.drawFlatCoordinates_( 37582 flatCoordinates, 37583 0, 37584 flatCoordinates.length, 37585 stride 37586 ); 37587 this.hitDetectionInstructions.push(strokeInstruction); 37588 this.endGeometry(feature); 37589 } 37590 37591 /** 37592 * @param {import("../../geom/MultiLineString.js").default|import("../Feature.js").default} multiLineStringGeometry MultiLineString geometry. 37593 * @param {import("../../Feature.js").FeatureLike} feature Feature. 37594 */ 37595 drawMultiLineString(multiLineStringGeometry, feature) { 37596 const state = this.state; 37597 const strokeStyle = state.strokeStyle; 37598 const lineWidth = state.lineWidth; 37599 if (strokeStyle === undefined || lineWidth === undefined) { 37600 return; 37601 } 37602 this.updateStrokeStyle(state, this.applyStroke); 37603 this.beginGeometry(multiLineStringGeometry, feature); 37604 this.hitDetectionInstructions.push( 37605 [ 37606 canvas_Instruction.SET_STROKE_STYLE, 37607 state.strokeStyle, 37608 state.lineWidth, 37609 state.lineCap, 37610 state.lineJoin, 37611 state.miterLimit, 37612 state.lineDash, 37613 state.lineDashOffset, 37614 ], 37615 beginPathInstruction 37616 ); 37617 const ends = multiLineStringGeometry.getEnds(); 37618 const flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); 37619 const stride = multiLineStringGeometry.getStride(); 37620 let offset = 0; 37621 for (let i = 0, ii = ends.length; i < ii; ++i) { 37622 offset = this.drawFlatCoordinates_( 37623 flatCoordinates, 37624 offset, 37625 /** @type {number} */ (ends[i]), 37626 stride 37627 ); 37628 } 37629 this.hitDetectionInstructions.push(strokeInstruction); 37630 this.endGeometry(feature); 37631 } 37632 37633 /** 37634 * @return {import("../canvas.js").SerializableInstructions} the serializable instructions. 37635 */ 37636 finish() { 37637 const state = this.state; 37638 if ( 37639 state.lastStroke != undefined && 37640 state.lastStroke != this.coordinates.length 37641 ) { 37642 this.instructions.push(strokeInstruction); 37643 } 37644 this.reverseHitDetectionInstructions(); 37645 this.state = null; 37646 return super.finish(); 37647 } 37648 37649 /** 37650 * @param {import("../canvas.js").FillStrokeState} state State. 37651 */ 37652 applyStroke(state) { 37653 if ( 37654 state.lastStroke != undefined && 37655 state.lastStroke != this.coordinates.length 37656 ) { 37657 this.instructions.push(strokeInstruction); 37658 state.lastStroke = this.coordinates.length; 37659 } 37660 state.lastStroke = 0; 37661 super.applyStroke(state); 37662 this.instructions.push(beginPathInstruction); 37663 } 37664} 37665 37666/* harmony default export */ const LineStringBuilder = (CanvasLineStringBuilder); 37667 37668;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/PolygonBuilder.js 37669/** 37670 * @module ol/render/canvas/PolygonBuilder 37671 */ 37672 37673 37674 37675 37676 37677class CanvasPolygonBuilder extends Builder { 37678 /** 37679 * @param {number} tolerance Tolerance. 37680 * @param {import("../../extent.js").Extent} maxExtent Maximum extent. 37681 * @param {number} resolution Resolution. 37682 * @param {number} pixelRatio Pixel ratio. 37683 */ 37684 constructor(tolerance, maxExtent, resolution, pixelRatio) { 37685 super(tolerance, maxExtent, resolution, pixelRatio); 37686 } 37687 37688 /** 37689 * @param {Array<number>} flatCoordinates Flat coordinates. 37690 * @param {number} offset Offset. 37691 * @param {Array<number>} ends Ends. 37692 * @param {number} stride Stride. 37693 * @private 37694 * @return {number} End. 37695 */ 37696 drawFlatCoordinatess_(flatCoordinates, offset, ends, stride) { 37697 const state = this.state; 37698 const fill = state.fillStyle !== undefined; 37699 const stroke = state.strokeStyle !== undefined; 37700 const numEnds = ends.length; 37701 this.instructions.push(beginPathInstruction); 37702 this.hitDetectionInstructions.push(beginPathInstruction); 37703 for (let i = 0; i < numEnds; ++i) { 37704 const end = ends[i]; 37705 const myBegin = this.coordinates.length; 37706 const myEnd = this.appendFlatLineCoordinates( 37707 flatCoordinates, 37708 offset, 37709 end,
37710 stride, 37711 true, 37712 !stroke 37713 ); 37714 const moveToLineToInstruction = [ 37715 canvas_Instruction.MOVE_TO_LINE_TO, 37716 myBegin, 37717 myEnd, 37718 ]; 37719 this.instructions.push(moveToLineToInstruction); 37720 this.hitDetectionInstructions.push(moveToLineToInstruction); 37721 if (stroke) { 37722 // Performance optimization: only call closePath() when we have a stroke. 37723 // Otherwise the ring is closed already (see appendFlatLineCoordinates above). 37724 this.instructions.push(closePathInstruction); 37725 this.hitDetectionInstructions.push(closePathInstruction); 37726 } 37727 offset = end; 37728 } 37729 if (fill) { 37730 this.instructions.push(fillInstruction); 37731 this.hitDetectionInstructions.push(fillInstruction); 37732 } 37733 if (stroke) { 37734 this.instructions.push(strokeInstruction); 37735 this.hitDetectionInstructions.push(strokeInstruction); 37736 } 37737 return offset; 37738 } 37739 37740 /** 37741 * @param {import("../../geom/Circle.js").default} circleGeometry Circle geometry. 37742 * @param {import("../../Feature.js").default} feature Feature. 37743 */ 37744 drawCircle(circleGeometry, feature) { 37745 const state = this.state; 37746 const fillStyle = state.fillStyle; 37747 const strokeStyle = state.strokeStyle; 37748 if (fillStyle === undefined && strokeStyle === undefined) { 37749 return; 37750 } 37751 this.setFillStrokeStyles_(); 37752 this.beginGeometry(circleGeometry, feature); 37753 if (state.fillStyle !== undefined) { 37754 this.hitDetectionInstructions.push([ 37755 canvas_Instruction.SET_FILL_STYLE, 37756 defaultFillStyle, 37757 ]); 37758 } 37759 if (state.strokeStyle !== undefined) { 37760 this.hitDetectionInstructions.push([ 37761 canvas_Instruction.SET_STROKE_STYLE, 37762 state.strokeStyle, 37763 state.lineWidth, 37764 state.lineCap, 37765 state.lineJoin, 37766 state.miterLimit, 37767 state.lineDash, 37768 state.lineDashOffset, 37769 ]); 37770 } 37771 const flatCoordinates = circleGeometry.getFlatCoordinates(); 37772 const stride = circleGeometry.getStride(); 37773 const myBegin = this.coordinates.length; 37774 this.appendFlatLineCoordinates( 37775 flatCoordinates, 37776 0, 37777 flatCoordinates.length, 37778 stride, 37779 false, 37780 false 37781 ); 37782 const circleInstruction = [canvas_Instruction.CIRCLE, myBegin]; 37783 this.instructions.push(beginPathInstruction, circleInstruction); 37784 this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction); 37785 if (state.fillStyle !== undefined) { 37786 this.instructions.push(fillInstruction); 37787 this.hitDetectionInstructions.push(fillInstruction); 37788 } 37789 if (state.strokeStyle !== undefined) { 37790 this.instructions.push(strokeInstruction); 37791 this.hitDetectionInstructions.push(strokeInstruction); 37792 } 37793 this.endGeometry(feature); 37794 } 37795 37796 /** 37797 * @param {import("../../geom/Polygon.js").default|import("../Feature.js").default} polygonGeometry Polygon geometry. 37798 * @param {import("../../Feature.js").FeatureLike} feature Feature. 37799 */ 37800 drawPolygon(polygonGeometry, feature) { 37801 const state = this.state; 37802 const fillStyle = state.fillStyle; 37803 const strokeStyle = state.strokeStyle; 37804 if (fillStyle === undefined && strokeStyle === undefined) { 37805 return; 37806 } 37807 this.setFillStrokeStyles_(); 37808 this.beginGeometry(polygonGeometry, feature); 37809 if (state.fillStyle !== undefined) { 37810 this.hitDetectionInstructions.push([ 37811 canvas_Instruction.SET_FILL_STYLE, 37812 defaultFillStyle, 37813 ]); 37814 } 37815 if (state.strokeStyle !== undefined) { 37816 this.hitDetectionInstructions.push([ 37817 canvas_Instruction.SET_STROKE_STYLE, 37818 state.strokeStyle, 37819 state.lineWidth, 37820 state.lineCap, 37821 state.lineJoin, 37822 state.miterLimit, 37823 state.lineDash, 37824 state.lineDashOffset, 37825 ]); 37826 } 37827 const ends = polygonGeometry.getEnds(); 37828 const flatCoordinates = polygonGeometry.getOrientedFlatCoordinates(); 37829 const stride = polygonGeometry.getStride(); 37830 this.drawFlatCoordinatess_( 37831 flatCoordinates, 37832 0, 37833 /** @type {Array<number>} */ (ends), 37834 stride 37835 ); 37836 this.endGeometry(feature); 37837 } 37838 37839 /** 37840 * @param {import("../../geom/MultiPolygon.js").default} multiPolygonGeometry MultiPolygon geometry. 37841 * @param {import("../../Feature.js").FeatureLike} feature Feature. 37842 */ 37843 drawMultiPolygon(multiPolygonGeometry, feature) { 37844 const state = this.state; 37845 const fillStyle = state.fillStyle; 37846 const strokeStyle = state.strokeStyle; 37847 if (fillStyle === undefined && strokeStyle === undefined) { 37848 return; 37849 } 37850 this.setFillStrokeStyles_(); 37851 this.beginGeometry(multiPolygonGeometry, feature); 37852 if (state.fillStyle !== undefined) { 37853 this.hitDetectionInstructions.push([
37854 canvas_Instruction.SET_FILL_STYLE, 37855 defaultFillStyle, 37856 ]); 37857 } 37858 if (state.strokeStyle !== undefined) { 37859 this.hitDetectionInstructions.push([ 37860 canvas_Instruction.SET_STROKE_STYLE, 37861 state.strokeStyle, 37862 state.lineWidth, 37863 state.lineCap, 37864 state.lineJoin, 37865 state.miterLimit, 37866 state.lineDash, 37867 state.lineDashOffset, 37868 ]); 37869 } 37870 const endss = multiPolygonGeometry.getEndss(); 37871 const flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates(); 37872 const stride = multiPolygonGeometry.getStride(); 37873 let offset = 0; 37874 for (let i = 0, ii = endss.length; i < ii; ++i) { 37875 offset = this.drawFlatCoordinatess_( 37876 flatCoordinates, 37877 offset, 37878 endss[i], 37879 stride 37880 ); 37881 } 37882 this.endGeometry(feature); 37883 } 37884 37885 /** 37886 * @return {import("../canvas.js").SerializableInstructions} the serializable instructions. 37887 */ 37888 finish() { 37889 this.reverseHitDetectionInstructions(); 37890 this.state = null; 37891 // We want to preserve topology when drawing polygons. Polygons are 37892 // simplified using quantization and point elimination. However, we might 37893 // have received a mix of quantized and non-quantized geometries, so ensure 37894 // that all are quantized by quantizing all coordinates in the batch. 37895 const tolerance = this.tolerance; 37896 if (tolerance !== 0) { 37897 const coordinates = this.coordinates; 37898 for (let i = 0, ii = coordinates.length; i < ii; ++i) { 37899 coordinates[i] = snap(coordinates[i], tolerance); 37900 } 37901 } 37902 return super.finish(); 37903 } 37904 37905 /** 37906 * @private 37907 */ 37908 setFillStrokeStyles_() { 37909 const state = this.state; 37910 const fillStyle = state.fillStyle; 37911 if (fillStyle !== undefined) { 37912 this.updateFillStyle(state, this.createFill); 37913 } 37914 if (state.strokeStyle !== undefined) { 37915 this.updateStrokeStyle(state, this.applyStroke); 37916 } 37917 } 37918} 37919 37920/* harmony default export */ const PolygonBuilder = (CanvasPolygonBuilder); 37921 37922;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/straightchunk.js 37923/** 37924 * @module ol/geom/flat/straightchunk 37925 */ 37926 37927/** 37928 * @param {number} maxAngle Maximum acceptable angle delta between segments. 37929 * @param {Array<number>} flatCoordinates Flat coordinates. 37930 * @param {number} offset Offset. 37931 * @param {number} end End. 37932 * @param {number} stride Stride. 37933 * @return {Array<number>} Start and end of the first suitable chunk of the 37934 * given `flatCoordinates`. 37935 */ 37936function matchingChunk(maxAngle, flatCoordinates, offset, end, stride) { 37937 let chunkStart = offset; 37938 let chunkEnd = offset; 37939 let chunkM = 0; 37940 let m = 0; 37941 let start = offset; 37942 let acos, i, m12, m23, x1, y1, x12, y12, x23, y23; 37943 for (i = offset; i < end; i += stride) { 37944 const x2 = flatCoordinates[i]; 37945 const y2 = flatCoordinates[i + 1]; 37946 if (x1 !== undefined) { 37947 x23 = x2 - x1; 37948 y23 = y2 - y1; 37949 m23 = Math.sqrt(x23 * x23 + y23 * y23); 37950 if (x12 !== undefined) { 37951 m += m12; 37952 acos = Math.acos((x12 * x23 + y12 * y23) / (m12 * m23)); 37953 if (acos > maxAngle) { 37954 if (m > chunkM) { 37955 chunkM = m; 37956 chunkStart = start; 37957 chunkEnd = i; 37958 } 37959 m = 0; 37960 start = i - stride; 37961 } 37962 } 37963 m12 = m23; 37964 x12 = x23; 37965 y12 = y23; 37966 } 37967 x1 = x2; 37968 y1 = y2; 37969 } 37970 m += m23; 37971 return m > chunkM ? [start, i] : [chunkStart, chunkEnd]; 37972} 37973 37974;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/TextBuilder.js 37975/** 37976 * @module ol/render/canvas/TextBuilder 37977 */ 37978 37979 37980 37981 37982 37983 37984 37985/** 37986 * @const 37987 * @enum {number} 37988 */ 37989const TEXT_ALIGN = { 37990 'left': 0, 37991 'end': 0, 37992 'center': 0.5, 37993 'right': 1, 37994 'start': 1, 37995 'top': 0, 37996 'middle': 0.5, 37997 'hanging': 0.2, 37998 'alphabetic': 0.8, 37999 'ideographic': 0.8, 38000 'bottom': 1, 38001}; 38002 38003class CanvasTextBuilder extends Builder { 38004 /** 38005 * @param {number} tolerance Tolerance. 38006 * @param {import("../../extent.js").Extent} maxExtent Maximum extent. 38007 * @param {number} resolution Resolution. 38008 * @param {number} pixelRatio Pixel ratio. 38009 */ 38010 constructor(tolerance, maxExtent, resolution, pixelRatio) { 38011 super(tolerance, maxExtent, resolution, pixelRatio); 38012 38013 /** 38014 * @private 38015 * @type {Array<HTMLCanvasElement>} 38016 */ 38017 this.labels_ = null; 38018 38019 /** 38020 * @private 38021 * @type {string|Array<string>} 38022 */ 38023 this.text_ = ''; 38024 38025 /** 38026 * @private 38027 * @type {number} 38028 */ 38029 this.textOffsetX_ = 0; 38030 38031 /** 38032 * @private 38033 * @type {number} 38034 */ 38035 this.textOffsetY_ = 0; 38036 38037 /** 38038 * @private 38039 * @type {boolean|undefined} 38040 */ 38041 this.textRotateWithView_ = undefined; 38042 38043 /** 38044 * @private 38045 * @type {number} 38046 */ 38047 this.textRotation_ = 0; 38048 38049 /** 38050 * @private 38051 * @type {?import("../canvas.js").FillState} 38052 */ 38053 this.textFillState_ = null; 38054 38055 /**
38056 * @type {!Object<string, import("../canvas.js").FillState>} 38057 */ 38058 this.fillStates = {}; 38059 38060 /** 38061 * @private 38062 * @type {?import("../canvas.js").StrokeState} 38063 */ 38064 this.textStrokeState_ = null; 38065 38066 /** 38067 * @type {!Object<string, import("../canvas.js").StrokeState>} 38068 */ 38069 this.strokeStates = {}; 38070 38071 /** 38072 * @private 38073 * @type {import("../canvas.js").TextState} 38074 */ 38075 this.textState_ = /** @type {import("../canvas.js").TextState} */ ({}); 38076 38077 /** 38078 * @type {!Object<string, import("../canvas.js").TextState>} 38079 */ 38080 this.textStates = {}; 38081 38082 /** 38083 * @private 38084 * @type {string} 38085 */ 38086 this.textKey_ = ''; 38087 38088 /** 38089 * @private 38090 * @type {string} 38091 */ 38092 this.fillKey_ = ''; 38093 38094 /** 38095 * @private 38096 * @type {string} 38097 */ 38098 this.strokeKey_ = ''; 38099 38100 /** 38101 * Data shared with an image builder for combined decluttering. 38102 * @private 38103 * @type {import("../canvas.js").DeclutterImageWithText} 38104 */ 38105 this.declutterImageWithText_ = undefined; 38106 } 38107 38108 /** 38109 * @return {import("../canvas.js").SerializableInstructions} the serializable instructions. 38110 */ 38111 finish() { 38112 const instructions = super.finish(); 38113 instructions.textStates = this.textStates; 38114 instructions.fillStates = this.fillStates; 38115 instructions.strokeStates = this.strokeStates; 38116 return instructions; 38117 } 38118 38119 /** 38120 * @param {import("../../geom/SimpleGeometry.js").default|import("../Feature.js").default} geometry Geometry. 38121 * @param {import("../../Feature.js").FeatureLike} feature Feature. 38122 */ 38123 drawText(geometry, feature) { 38124 const fillState = this.textFillState_; 38125 const strokeState = this.textStrokeState_; 38126 const textState = this.textState_; 38127 if (this.text_ === '' || !textState || (!fillState && !strokeState)) { 38128 return; 38129 } 38130 38131 const coordinates = this.coordinates; 38132 let begin = coordinates.length; 38133 38134 const geometryType = geometry.getType(); 38135 let flatCoordinates = null; 38136 let stride = geometry.getStride(); 38137 38138 if ( 38139 textState.placement === 'line' && 38140 (geometryType == 'LineString' || 38141 geometryType == 'MultiLineString' || 38142 geometryType == 'Polygon' || 38143 geometryType == 'MultiPolygon') 38144 ) { 38145 if (!intersects(this.getBufferedMaxExtent(), geometry.getExtent())) { 38146 return; 38147 } 38148 let ends; 38149 flatCoordinates = geometry.getFlatCoordinates(); 38150 if (geometryType == 'LineString') { 38151 ends = [flatCoordinates.length]; 38152 } else if (geometryType == 'MultiLineString') { 38153 ends = /** @type {import("../../geom/MultiLineString.js").default} */ ( 38154 geometry 38155 ).getEnds(); 38156 } else if (geometryType == 'Polygon') { 38157 ends = /** @type {import("../../geom/Polygon.js").default} */ (geometry) 38158 .getEnds() 38159 .slice(0, 1); 38160 } else if (geometryType == 'MultiPolygon') { 38161 const endss = 38162 /** @type {import("../../geom/MultiPolygon.js").default} */ ( 38163 geometry 38164 ).getEndss(); 38165 ends = []; 38166 for (let i = 0, ii = endss.length; i < ii; ++i) { 38167 ends.push(endss[i][0]); 38168 } 38169 } 38170 this.beginGeometry(geometry, feature); 38171 const textAlign = textState.textAlign; 38172 // No `justify` support for line placement. 38173 let flatOffset = 0; 38174 let flatEnd; 38175 for (let o = 0, oo = ends.length; o < oo; ++o) { 38176 if (textAlign == undefined) { 38177 const range = matchingChunk( 38178 textState.maxAngle, 38179 flatCoordinates, 38180 flatOffset, 38181 ends[o], 38182 stride 38183 ); 38184 flatOffset = range[0]; 38185 flatEnd = range[1]; 38186 } else { 38187 flatEnd = ends[o]; 38188 } 38189 for (let i = flatOffset; i < flatEnd; i += stride) { 38190 coordinates.push(flatCoordinates[i], flatCoordinates[i + 1]); 38191 } 38192 const end = coordinates.length; 38193 flatOffset = ends[o]; 38194 this.drawChars_(begin, end); 38195 begin = end; 38196 } 38197 this.endGeometry(feature); 38198 } else { 38199 let geometryWidths = textState.overflow ? null : []; 38200 switch (geometryType) { 38201 case 'Point': 38202 case 'MultiPoint': 38203 flatCoordinates = 38204 /** @type {import("../../geom/MultiPoint.js").default} */ ( 38205 geometry 38206 ).getFlatCoordinates(); 38207 break; 38208 case 'LineString': 38209 flatCoordinates = 38210 /** @type {import("../../geom/LineString.js").default} */ ( 38211 geometry 38212 ).getFlatMidpoint(); 38213 break; 38214 case 'Circle': 38215 flatCoordinates = 38216 /** @type {import("../../geom/Circle.js").default} */ ( 38217 geometry 38218 ).getCenter(); 38219 break; 38220 case 'MultiLineString': 38221 flatCoordinates = 38222 /** @type {import("../../geom/MultiLineString.js").default} */ ( 38223 geometry 38224 ).getFlatMidpoints();
38225 stride = 2; 38226 break; 38227 case 'Polygon': 38228 flatCoordinates = 38229 /** @type {import("../../geom/Polygon.js").default} */ ( 38230 geometry 38231 ).getFlatInteriorPoint(); 38232 if (!textState.overflow) { 38233 geometryWidths.push(flatCoordinates[2] / this.resolution); 38234 } 38235 stride = 3; 38236 break; 38237 case 'MultiPolygon': 38238 const interiorPoints = 38239 /** @type {import("../../geom/MultiPolygon.js").default} */ ( 38240 geometry 38241 ).getFlatInteriorPoints(); 38242 flatCoordinates = []; 38243 for (let i = 0, ii = interiorPoints.length; i < ii; i += 3) { 38244 if (!textState.overflow) { 38245 geometryWidths.push(interiorPoints[i + 2] / this.resolution); 38246 } 38247 flatCoordinates.push(interiorPoints[i], interiorPoints[i + 1]); 38248 } 38249 if (flatCoordinates.length === 0) { 38250 return; 38251 } 38252 stride = 2; 38253 break; 38254 default: 38255 } 38256 const end = this.appendFlatPointCoordinates(flatCoordinates, stride); 38257 if (end === begin) { 38258 return; 38259 } 38260 if ( 38261 geometryWidths && 38262 (end - begin) / 2 !== flatCoordinates.length / stride 38263 ) { 38264 let beg = begin / 2; 38265 geometryWidths = geometryWidths.filter((w, i) => { 38266 const keep = 38267 coordinates[(beg + i) * 2] === flatCoordinates[i * stride] && 38268 coordinates[(beg + i) * 2 + 1] === flatCoordinates[i * stride + 1]; 38269 if (!keep) { 38270 --beg; 38271 } 38272 return keep; 38273 }); 38274 } 38275 38276 this.saveTextStates_(); 38277 38278 if (textState.backgroundFill || textState.backgroundStroke) { 38279 this.setFillStrokeStyle( 38280 textState.backgroundFill, 38281 textState.backgroundStroke 38282 ); 38283 if (textState.backgroundFill) { 38284 this.updateFillStyle(this.state, this.createFill); 38285 this.hitDetectionInstructions.push(this.createFill(this.state)); 38286 } 38287 if (textState.backgroundStroke) { 38288 this.updateStrokeStyle(this.state, this.applyStroke); 38289 this.hitDetectionInstructions.push(this.createStroke(this.state)); 38290 } 38291 } 38292 38293 this.beginGeometry(geometry, feature); 38294 38295 // adjust padding for negative scale 38296 let padding = textState.padding; 38297 if ( 38298 padding != defaultPadding && 38299 (textState.scale[0] < 0 || textState.scale[1] < 0) 38300 ) { 38301 let p0 = textState.padding[0]; 38302 let p1 = textState.padding[1]; 38303 let p2 = textState.padding[2]; 38304 let p3 = textState.padding[3]; 38305 if (textState.scale[0] < 0) { 38306 p1 = -p1; 38307 p3 = -p3; 38308 } 38309 if (textState.scale[1] < 0) { 38310 p0 = -p0; 38311 p2 = -p2; 38312 } 38313 padding = [p0, p1, p2, p3]; 38314 } 38315 38316 // The image is unknown at this stage so we pass null; it will be computed at render time. 38317 // For clarity, we pass NaN for offsetX, offsetY, width and height, which will be computed at 38318 // render time. 38319 const pixelRatio = this.pixelRatio; 38320 this.instructions.push([ 38321 canvas_Instruction.DRAW_IMAGE, 38322 begin, 38323 end, 38324 null, 38325 NaN, 38326 NaN, 38327 NaN, 38328 1, 38329 0, 38330 0, 38331 this.textRotateWithView_, 38332 this.textRotation_, 38333 [1, 1], 38334 NaN, 38335 undefined, 38336 this.declutterImageWithText_, 38337 padding == defaultPadding 38338 ? defaultPadding 38339 : padding.map(function (p) { 38340 return p * pixelRatio; 38341 }), 38342 !!textState.backgroundFill, 38343 !!textState.backgroundStroke, 38344 this.text_, 38345 this.textKey_, 38346 this.strokeKey_, 38347 this.fillKey_, 38348 this.textOffsetX_, 38349 this.textOffsetY_, 38350 geometryWidths, 38351 ]); 38352 const scale = 1 / pixelRatio; 38353 this.hitDetectionInstructions.push([ 38354 canvas_Instruction.DRAW_IMAGE, 38355 begin, 38356 end, 38357 null, 38358 NaN, 38359 NaN, 38360 NaN, 38361 1, 38362 0, 38363 0, 38364 this.textRotateWithView_, 38365 this.textRotation_, 38366 [scale, scale], 38367 NaN, 38368 undefined, 38369 this.declutterImageWithText_, 38370 padding, 38371 !!textState.backgroundFill, 38372 !!textState.backgroundStroke, 38373 this.text_, 38374 this.textKey_, 38375 this.strokeKey_, 38376 this.fillKey_, 38377 this.textOffsetX_, 38378 this.textOffsetY_, 38379 geometryWidths, 38380 ]); 38381 38382 this.endGeometry(feature); 38383 } 38384 } 38385 38386 /** 38387 * @private 38388 */ 38389 saveTextStates_() { 38390 const strokeState = this.textStrokeState_; 38391 const textState = this.textState_; 38392 const fillState = this.textFillState_; 38393 38394 const strokeKey = this.strokeKey_; 38395 if (strokeState) { 38396 if (!(strokeKey in this.strokeStates)) { 38397 this.strokeStates[strokeKey] = { 38398 strokeStyle: strokeState.strokeStyle, 38399 lineCap: strokeState.lineCap, 38400 lineDashOffset: strokeState.lineDashOffset, 38401 lineWidth: strokeState.lineWidth, 38402 lineJoin: strokeState.lineJoin, 38403 miterLimit: strokeState.miterLimit, 38404 lineDash: strokeState.lineDash, 38405 }; 38406 } 38407 } 38408 const textKey = this.textKey_;
38409 if (!(textKey in this.textStates)) { 38410 this.textStates[textKey] = { 38411 font: textState.font, 38412 textAlign: textState.textAlign || defaultTextAlign, 38413 justify: textState.justify, 38414 textBaseline: textState.textBaseline || defaultTextBaseline, 38415 scale: textState.scale, 38416 }; 38417 } 38418 const fillKey = this.fillKey_; 38419 if (fillState) { 38420 if (!(fillKey in this.fillStates)) { 38421 this.fillStates[fillKey] = { 38422 fillStyle: fillState.fillStyle, 38423 }; 38424 } 38425 } 38426 } 38427 38428 /** 38429 * @private 38430 * @param {number} begin Begin. 38431 * @param {number} end End. 38432 */ 38433 drawChars_(begin, end) { 38434 const strokeState = this.textStrokeState_; 38435 const textState = this.textState_; 38436 38437 const strokeKey = this.strokeKey_; 38438 const textKey = this.textKey_; 38439 const fillKey = this.fillKey_; 38440 this.saveTextStates_(); 38441 38442 const pixelRatio = this.pixelRatio; 38443 const baseline = TEXT_ALIGN[textState.textBaseline]; 38444 38445 const offsetY = this.textOffsetY_ * pixelRatio; 38446 const text = this.text_; 38447 const strokeWidth = strokeState 38448 ? (strokeState.lineWidth * Math.abs(textState.scale[0])) / 2 38449 : 0; 38450 38451 this.instructions.push([ 38452 canvas_Instruction.DRAW_CHARS, 38453 begin, 38454 end, 38455 baseline, 38456 textState.overflow, 38457 fillKey, 38458 textState.maxAngle, 38459 pixelRatio, 38460 offsetY, 38461 strokeKey, 38462 strokeWidth * pixelRatio, 38463 text, 38464 textKey, 38465 1, 38466 ]); 38467 this.hitDetectionInstructions.push([ 38468 canvas_Instruction.DRAW_CHARS, 38469 begin, 38470 end, 38471 baseline, 38472 textState.overflow, 38473 fillKey, 38474 textState.maxAngle, 38475 1, 38476 offsetY, 38477 strokeKey, 38478 strokeWidth, 38479 text, 38480 textKey, 38481 1 / pixelRatio, 38482 ]); 38483 } 38484 38485 /** 38486 * @param {import("../../style/Text.js").default} textStyle Text style. 38487 * @param {Object} [sharedData] Shared data. 38488 */ 38489 setTextStyle(textStyle, sharedData) { 38490 let textState, fillState, strokeState; 38491 if (!textStyle) { 38492 this.text_ = ''; 38493 } else { 38494 const textFillStyle = textStyle.getFill(); 38495 if (!textFillStyle) { 38496 fillState = null; 38497 this.textFillState_ = fillState; 38498 } else { 38499 fillState = this.textFillState_; 38500 if (!fillState) { 38501 fillState = /** @type {import("../canvas.js").FillState} */ ({}); 38502 this.textFillState_ = fillState; 38503 } 38504 fillState.fillStyle = asColorLike( 38505 textFillStyle.getColor() || defaultFillStyle 38506 ); 38507 } 38508 38509 const textStrokeStyle = textStyle.getStroke(); 38510 if (!textStrokeStyle) { 38511 strokeState = null; 38512 this.textStrokeState_ = strokeState; 38513 } else { 38514 strokeState = this.textStrokeState_; 38515 if (!strokeState) { 38516 strokeState = /** @type {import("../canvas.js").StrokeState} */ ({}); 38517 this.textStrokeState_ = strokeState; 38518 } 38519 const lineDash = textStrokeStyle.getLineDash(); 38520 const lineDashOffset = textStrokeStyle.getLineDashOffset(); 38521 const lineWidth = textStrokeStyle.getWidth(); 38522 const miterLimit = textStrokeStyle.getMiterLimit(); 38523 strokeState.lineCap = textStrokeStyle.getLineCap() || defaultLineCap; 38524 strokeState.lineDash = lineDash ? lineDash.slice() : defaultLineDash; 38525 strokeState.lineDashOffset = 38526 lineDashOffset === undefined ? defaultLineDashOffset : lineDashOffset; 38527 strokeState.lineJoin = textStrokeStyle.getLineJoin() || defaultLineJoin; 38528 strokeState.lineWidth = 38529 lineWidth === undefined ? defaultLineWidth : lineWidth; 38530 strokeState.miterLimit = 38531 miterLimit === undefined ? defaultMiterLimit : miterLimit; 38532 strokeState.strokeStyle = asColorLike( 38533 textStrokeStyle.getColor() || defaultStrokeStyle 38534 ); 38535 } 38536 38537 textState = this.textState_; 38538 const font = textStyle.getFont() || defaultFont; 38539 registerFont(font); 38540 const textScale = textStyle.getScaleArray(); 38541 textState.overflow = textStyle.getOverflow(); 38542 textState.font = font; 38543 textState.maxAngle = textStyle.getMaxAngle(); 38544 textState.placement = textStyle.getPlacement(); 38545 textState.textAlign = textStyle.getTextAlign(); 38546 textState.justify = textStyle.getJustify(); 38547 textState.textBaseline = 38548 textStyle.getTextBaseline() || defaultTextBaseline;
38549 textState.backgroundFill = textStyle.getBackgroundFill(); 38550 textState.backgroundStroke = textStyle.getBackgroundStroke(); 38551 textState.padding = textStyle.getPadding() || defaultPadding; 38552 textState.scale = textScale === undefined ? [1, 1] : textScale; 38553 38554 const textOffsetX = textStyle.getOffsetX(); 38555 const textOffsetY = textStyle.getOffsetY(); 38556 const textRotateWithView = textStyle.getRotateWithView(); 38557 const textRotation = textStyle.getRotation(); 38558 this.text_ = textStyle.getText() || ''; 38559 this.textOffsetX_ = textOffsetX === undefined ? 0 : textOffsetX; 38560 this.textOffsetY_ = textOffsetY === undefined ? 0 : textOffsetY; 38561 this.textRotateWithView_ = 38562 textRotateWithView === undefined ? false : textRotateWithView; 38563 this.textRotation_ = textRotation === undefined ? 0 : textRotation; 38564 38565 this.strokeKey_ = strokeState 38566 ? (typeof strokeState.strokeStyle == 'string' 38567 ? strokeState.strokeStyle 38568 : getUid(strokeState.strokeStyle)) + 38569 strokeState.lineCap + 38570 strokeState.lineDashOffset + 38571 '|' + 38572 strokeState.lineWidth + 38573 strokeState.lineJoin + 38574 strokeState.miterLimit + 38575 '[' + 38576 strokeState.lineDash.join() + 38577 ']' 38578 : ''; 38579 this.textKey_ = 38580 textState.font + 38581 textState.scale + 38582 (textState.textAlign || '?') + 38583 (textState.justify || '?') + 38584 (textState.textBaseline || '?'); 38585 this.fillKey_ = fillState 38586 ? typeof fillState.fillStyle == 'string' 38587 ? fillState.fillStyle 38588 : '|' + getUid(fillState.fillStyle) 38589 : ''; 38590 } 38591 this.declutterImageWithText_ = sharedData; 38592 } 38593} 38594 38595/* harmony default export */ const TextBuilder = (CanvasTextBuilder); 38596 38597;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/BuilderGroup.js 38598/** 38599 * @module ol/render/canvas/BuilderGroup 38600 */ 38601 38602 38603 38604 38605 38606 38607 38608/** 38609 * @type {Object<import("../canvas.js").BuilderType, typeof Builder>} 38610 */ 38611const BATCH_CONSTRUCTORS = { 38612 'Circle': PolygonBuilder, 38613 'Default': Builder, 38614 'Image': ImageBuilder, 38615 'LineString': LineStringBuilder, 38616 'Polygon': PolygonBuilder, 38617 'Text': TextBuilder, 38618}; 38619 38620class BuilderGroup { 38621 /** 38622 * @param {number} tolerance Tolerance. 38623 * @param {import("../../extent.js").Extent} maxExtent Max extent. 38624 * @param {number} resolution Resolution. 38625 * @param {number} pixelRatio Pixel ratio. 38626 */ 38627 constructor(tolerance, maxExtent, resolution, pixelRatio) { 38628 /** 38629 * @private 38630 * @type {number} 38631 */ 38632 this.tolerance_ = tolerance; 38633 38634 /** 38635 * @private 38636 * @type {import("../../extent.js").Extent} 38637 */ 38638 this.maxExtent_ = maxExtent; 38639 38640 /** 38641 * @private 38642 * @type {number} 38643 */ 38644 this.pixelRatio_ = pixelRatio; 38645 38646 /** 38647 * @private 38648 * @type {number} 38649 */ 38650 this.resolution_ = resolution; 38651 38652 /** 38653 * @private 38654 * @type {!Object<string, !Object<import("../canvas.js").BuilderType, Builder>>} 38655 */ 38656 this.buildersByZIndex_ = {}; 38657 } 38658 38659 /** 38660 * @return {!Object<string, !Object<import("../canvas.js").BuilderType, import("./Builder.js").SerializableInstructions>>} The serializable instructions 38661 */ 38662 finish() { 38663 const builderInstructions = {}; 38664 for (const zKey in this.buildersByZIndex_) { 38665 builderInstructions[zKey] = builderInstructions[zKey] || {}; 38666 const builders = this.buildersByZIndex_[zKey]; 38667 for (const builderKey in builders) { 38668 const builderInstruction = builders[builderKey].finish(); 38669 builderInstructions[zKey][builderKey] = builderInstruction; 38670 } 38671 } 38672 return builderInstructions; 38673 } 38674 38675 /** 38676 * @param {number|undefined} zIndex Z index. 38677 * @param {import("../canvas.js").BuilderType} builderType Replay type. 38678 * @return {import("../VectorContext.js").default} Replay. 38679 */ 38680 getBuilder(zIndex, builderType) { 38681 const zIndexKey = zIndex !== undefined ? zIndex.toString() : '0'; 38682 let replays = this.buildersByZIndex_[zIndexKey]; 38683 if (replays === undefined) { 38684 replays = {}; 38685 this.buildersByZIndex_[zIndexKey] = replays; 38686 } 38687 let replay = replays[builderType]; 38688 if (replay === undefined) { 38689 const Constructor = BATCH_CONSTRUCTORS[builderType]; 38690 replay = new Constructor( 38691 this.tolerance_, 38692 this.maxExtent_, 38693 this.resolution_, 38694 this.pixelRatio_ 38695 ); 38696 replays[builderType] = replay; 38697 } 38698 return replay; 38699 } 38700} 38701 38702/* harmony default export */ const canvas_BuilderGroup = (BuilderGroup); 38703 38704;// CONCATENATED MODULE: ./node_modules/ol/renderer/Layer.js 38705/** 38706 * @module ol/renderer/Layer 38707 */ 38708 38709 38710 38711 38712 38713/** 38714 * @template {import("../layer/Layer.js").default} LayerType 38715 */ 38716class LayerRenderer extends ol_Observable { 38717 /** 38718 * @param {LayerType} layer Layer. 38719 */ 38720 constructor(layer) { 38721 super(); 38722 38723 /** 38724 * The renderer is initialized and ready to render. 38725 * @type {boolean} 38726 */ 38727 this.ready = true; 38728 38729 /** @private */ 38730 this.boundHandleImageChange_ = this.handleImageChange_.bind(this); 38731 38732 /** 38733 * @protected 38734 * @type {LayerType} 38735 */ 38736 this.layer_ = layer; 38737 38738 /** 38739 * @type {import("../render/canvas/ExecutorGroup").default} 38740 */ 38741 this.declutterExecutorGroup = null; 38742 } 38743 38744 /** 38745 * Asynchronous layer level hit detection. 38746 * @param {import("../pixel.js").Pixel} pixel Pixel. 38747 * @return {Promise<Array<import("../Feature").default>>} Promise that resolves with 38748 * an array of features. 38749 */ 38750 getFeatures(pixel) { 38751 return util_abstract(); 38752 } 38753 38754 /** 38755 * @param {import("../pixel.js").Pixel} pixel Pixel. 38756 * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data. 38757 */ 38758 getData(pixel) { 38759 return null; 38760 } 38761 38762 /** 38763 * Determine whether render should be called. 38764 * @abstract 38765 * @param {import("../Map.js").FrameState} frameState Frame state. 38766 * @return {boolean} Layer is ready to be rendered. 38767 */ 38768 prepareFrame(frameState) { 38769 return util_abstract(); 38770 } 38771 38772 /** 38773 * Render the layer. 38774 * @abstract 38775 * @param {import("../Map.js").FrameState} frameState Frame state. 38776 * @param {HTMLElement} target Target that may be used to render content to. 38777 * @return {HTMLElement} The rendered element. 38778 */ 38779 renderFrame(frameState, target) { 38780 return util_abstract(); 38781 } 38782 38783 /** 38784 * @param {Object<number, Object<string, import("../Tile.js").default>>} tiles Lookup of loaded tiles by zoom level. 38785 * @param {number} zoom Zoom level. 38786 * @param {import("../Tile.js").default} tile Tile. 38787 * @return {boolean|void} If `false`, the tile will not be considered loaded. 38788 */
38789 loadedTileCallback(tiles, zoom, tile) { 38790 if (!tiles[zoom]) { 38791 tiles[zoom] = {}; 38792 } 38793 tiles[zoom][tile.tileCoord.toString()] = tile; 38794 return undefined; 38795 } 38796 38797 /** 38798 * Create a function that adds loaded tiles to the tile lookup. 38799 * @param {import("../source/Tile.js").default} source Tile source. 38800 * @param {import("../proj/Projection.js").default} projection Projection of the tiles. 38801 * @param {Object<number, Object<string, import("../Tile.js").default>>} tiles Lookup of loaded tiles by zoom level. 38802 * @return {function(number, import("../TileRange.js").default):boolean} A function that can be 38803 * called with a zoom level and a tile range to add loaded tiles to the lookup. 38804 * @protected 38805 */ 38806 createLoadedTileFinder(source, projection, tiles) { 38807 return ( 38808 /** 38809 * @param {number} zoom Zoom level. 38810 * @param {import("../TileRange.js").default} tileRange Tile range. 38811 * @return {boolean} The tile range is fully loaded. 38812 * @this {LayerRenderer} 38813 */ 38814 function (zoom, tileRange) { 38815 const callback = this.loadedTileCallback.bind(this, tiles, zoom); 38816 return source.forEachLoadedTile(projection, zoom, tileRange, callback); 38817 }.bind(this) 38818 ); 38819 } 38820 /** 38821 * @abstract 38822 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 38823 * @param {import("../Map.js").FrameState} frameState Frame state. 38824 * @param {number} hitTolerance Hit tolerance in pixels. 38825 * @param {import("./vector.js").FeatureCallback<T>} callback Feature callback. 38826 * @param {Array<import("./Map.js").HitMatch<T>>} matches The hit detected matches with tolerance. 38827 * @return {T|undefined} Callback result. 38828 * @template T 38829 */ 38830 forEachFeatureAtCoordinate( 38831 coordinate, 38832 frameState, 38833 hitTolerance, 38834 callback, 38835 matches 38836 ) { 38837 return undefined; 38838 } 38839 38840 /** 38841 * @return {LayerType} Layer. 38842 */ 38843 getLayer() { 38844 return this.layer_; 38845 } 38846 38847 /** 38848 * Perform action necessary to get the layer rendered after new fonts have loaded 38849 * @abstract 38850 */ 38851 handleFontsChanged() {} 38852 38853 /** 38854 * Handle changes in image state. 38855 * @param {import("../events/Event.js").default} event Image change event. 38856 * @private 38857 */ 38858 handleImageChange_(event) { 38859 const image = /** @type {import("../Image.js").default} */ (event.target); 38860 if (image.getState() === ol_ImageState.LOADED) { 38861 this.renderIfReadyAndVisible(); 38862 } 38863 } 38864 38865 /** 38866 * Load the image if not already loaded, and register the image change 38867 * listener if needed. 38868 * @param {import("../ImageBase.js").default} image Image. 38869 * @return {boolean} `true` if the image is already loaded, `false` otherwise. 38870 * @protected 38871 */ 38872 loadImage(image) { 38873 let imageState = image.getState(); 38874 if (imageState != ol_ImageState.LOADED && imageState != ol_ImageState.ERROR) { 38875 image.addEventListener(EventType.CHANGE, this.boundHandleImageChange_); 38876 } 38877 if (imageState == ol_ImageState.IDLE) { 38878 image.load(); 38879 imageState = image.getState(); 38880 } 38881 return imageState == ol_ImageState.LOADED; 38882 } 38883 38884 /** 38885 * @protected 38886 */ 38887 renderIfReadyAndVisible() { 38888 const layer = this.getLayer(); 38889 if (layer && layer.getVisible() && layer.getSourceState() === 'ready') { 38890 layer.changed(); 38891 } 38892 } 38893 38894 /** 38895 * Clean up. 38896 */ 38897 disposeInternal() { 38898 delete this.layer_; 38899 super.disposeInternal(); 38900 } 38901} 38902 38903/* harmony default export */ const renderer_Layer = (LayerRenderer); 38904 38905;// CONCATENATED MODULE: ./node_modules/ol/renderer/canvas/Layer.js 38906/** 38907 * @module ol/renderer/canvas/Layer 38908 */ 38909 38910 38911 38912 38913 38914 38915 38916 38917 38918/** 38919 * @type {Array<HTMLCanvasElement>} 38920 */ 38921const canvasPool = []; 38922 38923/** 38924 * @type {CanvasRenderingContext2D} 38925 */ 38926let pixelContext = null; 38927 38928function createPixelContext() { 38929 const canvas = document.createElement('canvas'); 38930 canvas.width = 1; 38931 canvas.height = 1; 38932 pixelContext = canvas.getContext('2d'); 38933} 38934 38935/** 38936 * @abstract 38937 * @template {import("../../layer/Layer.js").default} LayerType 38938 * @extends {LayerRenderer<LayerType>} 38939 */ 38940class CanvasLayerRenderer extends renderer_Layer { 38941 /** 38942 * @param {LayerType} layer Layer. 38943 */ 38944 constructor(layer) { 38945 super(layer); 38946 38947 /** 38948 * @protected 38949 * @type {HTMLElement} 38950 */ 38951 this.container = null; 38952 38953 /** 38954 * @protected 38955 * @type {number} 38956 */ 38957 this.renderedResolution; 38958 38959 /** 38960 * A temporary transform. The values in this transform should only be used in a 38961 * function that sets the values. 38962 * @protected 38963 * @type {import("../../transform.js").Transform} 38964 */ 38965 this.tempTransform = create(); 38966 38967 /** 38968 * The transform for rendered pixels to viewport CSS pixels. This transform must 38969 * be set when rendering a frame and may be used by other functions after rendering. 38970 * @protected 38971 * @type {import("../../transform.js").Transform} 38972 */ 38973 this.pixelTransform = create(); 38974 38975 /** 38976 * The transform for viewport CSS pixels to rendered pixels. This transform must 38977 * be set when rendering a frame and may be used by other functions after rendering. 38978 * @protected 38979 * @type {import("../../transform.js").Transform} 38980 */ 38981 this.inversePixelTransform = create(); 38982 38983 /** 38984 * @type {CanvasRenderingContext2D} 38985 */ 38986 this.context = null; 38987 38988 /** 38989 * @type {boolean} 38990 */ 38991 this.containerReused = false;
38992 38993 /** 38994 * @private 38995 * @type {CanvasRenderingContext2D} 38996 */ 38997 this.pixelContext_ = null; 38998 38999 /** 39000 * @protected 39001 * @type {import("../../Map.js").FrameState|null} 39002 */ 39003 this.frameState = null; 39004 } 39005 39006 /** 39007 * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image. 39008 * @param {number} col The column index. 39009 * @param {number} row The row index. 39010 * @return {Uint8ClampedArray|null} The image data. 39011 */ 39012 getImageData(image, col, row) { 39013 if (!pixelContext) { 39014 createPixelContext(); 39015 } 39016 pixelContext.clearRect(0, 0, 1, 1); 39017 39018 let data; 39019 try { 39020 pixelContext.drawImage(image, col, row, 1, 1, 0, 0, 1, 1); 39021 data = pixelContext.getImageData(0, 0, 1, 1).data; 39022 } catch (err) { 39023 pixelContext = null; 39024 return null; 39025 } 39026 return data; 39027 } 39028 39029 /** 39030 * @param {import('../../Map.js').FrameState} frameState Frame state. 39031 * @return {string} Background color. 39032 */ 39033 getBackground(frameState) { 39034 const layer = this.getLayer(); 39035 let background = layer.getBackground(); 39036 if (typeof background === 'function') { 39037 background = background(frameState.viewState.resolution); 39038 } 39039 return background || undefined; 39040 } 39041 39042 /** 39043 * Get a rendering container from an existing target, if compatible. 39044 * @param {HTMLElement} target Potential render target. 39045 * @param {string} transform CSS Transform. 39046 * @param {string} [backgroundColor] Background color. 39047 */ 39048 useContainer(target, transform, backgroundColor) { 39049 const layerClassName = this.getLayer().getClassName(); 39050 let container, context; 39051 if ( 39052 target && 39053 target.className === layerClassName && 39054 (!backgroundColor || 39055 (target && 39056 target.style.backgroundColor && 39057 equals( 39058 asArray(target.style.backgroundColor), 39059 asArray(backgroundColor) 39060 ))) 39061 ) { 39062 const canvas = target.firstElementChild; 39063 if (canvas instanceof HTMLCanvasElement) { 39064 context = canvas.getContext('2d'); 39065 } 39066 } 39067 if (context && context.canvas.style.transform === transform) { 39068 // Container of the previous layer renderer can be used. 39069 this.container = target; 39070 this.context = context; 39071 this.containerReused = true; 39072 } else if (this.containerReused) { 39073 // Previously reused container cannot be used any more. 39074 this.container = null; 39075 this.context = null; 39076 this.containerReused = false; 39077 } 39078 if (!this.container) { 39079 container = document.createElement('div'); 39080 container.className = layerClassName; 39081 let style = container.style; 39082 style.position = 'absolute'; 39083 style.width = '100%'; 39084 style.height = '100%'; 39085 context = createCanvasContext2D(); 39086 const canvas = context.canvas; 39087 container.appendChild(canvas); 39088 style = canvas.style; 39089 style.position = 'absolute'; 39090 style.left = '0'; 39091 style.transformOrigin = 'top left'; 39092 this.container = container; 39093 this.context = context; 39094 } 39095 if ( 39096 !this.containerReused && 39097 backgroundColor && 39098 !this.container.style.backgroundColor 39099 ) { 39100 this.container.style.backgroundColor = backgroundColor; 39101 } 39102 } 39103 39104 /** 39105 * @param {CanvasRenderingContext2D} context Context. 39106 * @param {import("../../Map.js").FrameState} frameState Frame state. 39107 * @param {import("../../extent.js").Extent} extent Clip extent. 39108 * @protected 39109 */ 39110 clipUnrotated(context, frameState, extent) { 39111 const topLeft = getTopLeft(extent); 39112 const topRight = getTopRight(extent); 39113 const bottomRight = getBottomRight(extent); 39114 const bottomLeft = getBottomLeft(extent); 39115 39116 apply(frameState.coordinateToPixelTransform, topLeft); 39117 apply(frameState.coordinateToPixelTransform, topRight); 39118 apply(frameState.coordinateToPixelTransform, bottomRight); 39119 apply(frameState.coordinateToPixelTransform, bottomLeft); 39120 39121 const inverted = this.inversePixelTransform; 39122 apply(inverted, topLeft); 39123 apply(inverted, topRight); 39124 apply(inverted, bottomRight); 39125 apply(inverted, bottomLeft); 39126 39127 context.save(); 39128 context.beginPath(); 39129 context.moveTo(Math.round(topLeft[0]), Math.round(topLeft[1])); 39130 context.lineTo(Math.round(topRight[0]), Math.round(topRight[1])); 39131 context.lineTo(Math.round(bottomRight[0]), Math.round(bottomRight[1])); 39132 context.lineTo(Math.round(bottomLeft[0]), Math.round(bottomLeft[1])); 39133 context.clip(); 39134 } 39135 39136 /** 39137 * @param {import("../../render/EventType.js").default} type Event type. 39138 * @param {CanvasRenderingContext2D} context Context. 39139 * @param {import("../../Map.js").FrameState} frameState Frame state. 39140 * @private 39141 */ 39142 dispatchRenderEvent_(type, context, frameState) { 39143 const layer = this.getLayer(); 39144 if (layer.hasListener(type)) { 39145 const event = new render_Event( 39146 type, 39147 this.inversePixelTransform, 39148 frameState, 39149 context 39150 );
39151 layer.dispatchEvent(event); 39152 } 39153 } 39154 39155 /** 39156 * @param {CanvasRenderingContext2D} context Context. 39157 * @param {import("../../Map.js").FrameState} frameState Frame state. 39158 * @protected 39159 */ 39160 preRender(context, frameState) { 39161 this.frameState = frameState; 39162 this.dispatchRenderEvent_(render_EventType.PRERENDER, context, frameState); 39163 } 39164 39165 /** 39166 * @param {CanvasRenderingContext2D} context Context. 39167 * @param {import("../../Map.js").FrameState} frameState Frame state. 39168 * @protected 39169 */ 39170 postRender(context, frameState) { 39171 this.dispatchRenderEvent_(render_EventType.POSTRENDER, context, frameState); 39172 } 39173 39174 /** 39175 * Creates a transform for rendering to an element that will be rotated after rendering. 39176 * @param {import("../../coordinate.js").Coordinate} center Center. 39177 * @param {number} resolution Resolution. 39178 * @param {number} rotation Rotation. 39179 * @param {number} pixelRatio Pixel ratio. 39180 * @param {number} width Width of the rendered element (in pixels). 39181 * @param {number} height Height of the rendered element (in pixels). 39182 * @param {number} offsetX Offset on the x-axis in view coordinates. 39183 * @protected 39184 * @return {!import("../../transform.js").Transform} Transform. 39185 */ 39186 getRenderTransform( 39187 center, 39188 resolution, 39189 rotation, 39190 pixelRatio, 39191 width, 39192 height, 39193 offsetX 39194 ) { 39195 const dx1 = width / 2; 39196 const dy1 = height / 2; 39197 const sx = pixelRatio / resolution; 39198 const sy = -sx; 39199 const dx2 = -center[0] + offsetX; 39200 const dy2 = -center[1]; 39201 return compose( 39202 this.tempTransform, 39203 dx1, 39204 dy1, 39205 sx, 39206 sy, 39207 -rotation, 39208 dx2, 39209 dy2 39210 ); 39211 } 39212 39213 /** 39214 * Clean up. 39215 */ 39216 disposeInternal() { 39217 delete this.frameState; 39218 super.disposeInternal(); 39219 } 39220} 39221 39222/* harmony default export */ const canvas_Layer = (CanvasLayerRenderer); 39223 39224;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/textpath.js 39225/** 39226 * @module ol/geom/flat/textpath 39227 */ 39228 39229 39230 39231/** 39232 * @param {Array<number>} flatCoordinates Path to put text on. 39233 * @param {number} offset Start offset of the `flatCoordinates`. 39234 * @param {number} end End offset of the `flatCoordinates`. 39235 * @param {number} stride Stride. 39236 * @param {string} text Text to place on the path. 39237 * @param {number} startM m along the path where the text starts. 39238 * @param {number} maxAngle Max angle between adjacent chars in radians. 39239 * @param {number} scale The product of the text scale and the device pixel ratio. 39240 * @param {function(string, string, Object<string, number>):number} measureAndCacheTextWidth Measure and cache text width. 39241 * @param {string} font The font. 39242 * @param {Object<string, number>} cache A cache of measured widths. 39243 * @param {number} rotation Rotation to apply to the flatCoordinates to determine whether text needs to be reversed. 39244 * @return {Array<Array<*>>|null} The result array (or null if `maxAngle` was 39245 * exceeded). Entries of the array are x, y, anchorX, angle, chunk. 39246 */ 39247function drawTextOnPath( 39248 flatCoordinates, 39249 offset, 39250 end, 39251 stride, 39252 text, 39253 startM, 39254 maxAngle, 39255 scale, 39256 measureAndCacheTextWidth, 39257 font, 39258 cache, 39259 rotation 39260) { 39261 let x2 = flatCoordinates[offset]; 39262 let y2 = flatCoordinates[offset + 1]; 39263 let x1 = 0; 39264 let y1 = 0; 39265 let segmentLength = 0; 39266 let segmentM = 0; 39267 39268 function advance() { 39269 x1 = x2; 39270 y1 = y2; 39271 offset += stride; 39272 x2 = flatCoordinates[offset]; 39273 y2 = flatCoordinates[offset + 1]; 39274 segmentM += segmentLength; 39275 segmentLength = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); 39276 } 39277 do { 39278 advance(); 39279 } while (offset < end - stride && segmentM + segmentLength < startM); 39280 39281 let interpolate = 39282 segmentLength === 0 ? 0 : (startM - segmentM) / segmentLength; 39283 const beginX = lerp(x1, x2, interpolate); 39284 const beginY = lerp(y1, y2, interpolate); 39285 39286 const startOffset = offset - stride; 39287 const startLength = segmentM; 39288 const endM = startM + scale * measureAndCacheTextWidth(font, text, cache); 39289 while (offset < end - stride && segmentM + segmentLength < endM) { 39290 advance(); 39291 } 39292 interpolate = segmentLength === 0 ? 0 : (endM - segmentM) / segmentLength; 39293 const endX = lerp(x1, x2, interpolate); 39294 const endY = lerp(y1, y2, interpolate); 39295 39296 // Keep text upright 39297 let reverse; 39298 if (rotation) { 39299 const flat = [beginX, beginY, endX, endY]; 39300 flat_transform_rotate(flat, 0, 4, 2, rotation, flat, flat); 39301 reverse = flat[0] > flat[2]; 39302 } else { 39303 reverse = beginX > endX; 39304 } 39305 39306 const PI = Math.PI; 39307 const result = []; 39308 const singleSegment = startOffset + stride === offset; 39309 39310 offset = startOffset; 39311 segmentLength = 0; 39312 segmentM = startLength; 39313 x2 = flatCoordinates[offset]; 39314 y2 = flatCoordinates[offset + 1]; 39315 39316 let previousAngle; 39317 // All on the same segment 39318 if (singleSegment) { 39319 advance(); 39320 39321 previousAngle = Math.atan2(y2 - y1, x2 - x1); 39322 if (reverse) { 39323 previousAngle += previousAngle > 0 ? -PI : PI; 39324 } 39325 const x = (endX + beginX) / 2; 39326 const y = (endY + beginY) / 2; 39327 result[0] = [x, y, (endM - startM) / 2, previousAngle, text]; 39328 return result; 39329 } 39330 39331 // rendering across line segments 39332 text = text.replace(/\n/g, ' '); // ensure rendering in single-line as all calculations below don't handle multi-lines 39333 39334 for (let i = 0, ii = text.length; i < ii; ) { 39335 advance(); 39336 let angle = Math.atan2(y2 - y1, x2 - x1); 39337 if (reverse) { 39338 angle += angle > 0 ? -PI : PI; 39339 } 39340 if (previousAngle !== undefined) { 39341 let delta = angle - previousAngle; 39342 delta += delta > PI ? -2 * PI : delta < -PI ? 2 * PI : 0; 39343 if (Math.abs(delta) > maxAngle) { 39344 return null; 39345 } 39346 } 39347 previousAngle = angle; 39348 39349 const iStart = i;
39350 let charLength = 0; 39351 for (; i < ii; ++i) { 39352 const index = reverse ? ii - i - 1 : i; 39353 const len = scale * measureAndCacheTextWidth(font, text[index], cache); 39354 if ( 39355 offset + stride < end && 39356 segmentM + segmentLength < startM + charLength + len / 2 39357 ) { 39358 break; 39359 } 39360 charLength += len; 39361 } 39362 if (i === iStart) { 39363 continue; 39364 } 39365 const chars = reverse 39366 ? text.substring(ii - iStart, ii - i) 39367 : text.substring(iStart, i); 39368 interpolate = 39369 segmentLength === 0 39370 ? 0 39371 : (startM + charLength / 2 - segmentM) / segmentLength; 39372 const x = lerp(x1, x2, interpolate); 39373 const y = lerp(y1, y2, interpolate); 39374 result.push([x, y, charLength / 2, angle, chars]); 39375 startM += charLength; 39376 } 39377 return result; 39378} 39379 39380;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/length.js 39381/** 39382 * @module ol/geom/flat/length 39383 */ 39384 39385/** 39386 * @param {Array<number>} flatCoordinates Flat coordinates. 39387 * @param {number} offset Offset. 39388 * @param {number} end End. 39389 * @param {number} stride Stride. 39390 * @return {number} Length. 39391 */ 39392function lineStringLength(flatCoordinates, offset, end, stride) { 39393 let x1 = flatCoordinates[offset]; 39394 let y1 = flatCoordinates[offset + 1]; 39395 let length = 0; 39396 for (let i = offset + stride; i < end; i += stride) { 39397 const x2 = flatCoordinates[i]; 39398 const y2 = flatCoordinates[i + 1]; 39399 length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); 39400 x1 = x2; 39401 y1 = y2; 39402 } 39403 return length; 39404} 39405 39406/** 39407 * @param {Array<number>} flatCoordinates Flat coordinates. 39408 * @param {number} offset Offset. 39409 * @param {number} end End. 39410 * @param {number} stride Stride. 39411 * @return {number} Perimeter. 39412 */ 39413function linearRingLength(flatCoordinates, offset, end, stride) { 39414 let perimeter = lineStringLength(flatCoordinates, offset, end, stride); 39415 const dx = flatCoordinates[end - stride] - flatCoordinates[offset]; 39416 const dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1]; 39417 perimeter += Math.sqrt(dx * dx + dy * dy); 39418 return perimeter; 39419} 39420 39421;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/Executor.js 39422/** 39423 * @module ol/render/canvas/Executor 39424 */ 39425 39426 39427 39428 39429 39430 39431 39432 39433 39434 39435/** 39436 * @typedef {Object} BBox 39437 * @property {number} minX Minimal x. 39438 * @property {number} minY Minimal y. 39439 * @property {number} maxX Maximal x. 39440 * @property {number} maxY Maximal y 39441 * @property {*} value Value. 39442 */ 39443 39444/** 39445 * @typedef {Object} ImageOrLabelDimensions 39446 * @property {number} drawImageX DrawImageX. 39447 * @property {number} drawImageY DrawImageY. 39448 * @property {number} drawImageW DrawImageW. 39449 * @property {number} drawImageH DrawImageH. 39450 * @property {number} originX OriginX. 39451 * @property {number} originY OriginY. 39452 * @property {Array<number>} scale Scale. 39453 * @property {BBox} declutterBox DeclutterBox. 39454 * @property {import("../../transform.js").Transform} canvasTransform CanvasTransform. 39455 */ 39456 39457/** 39458 * @typedef {{0: CanvasRenderingContext2D, 1: number, 2: import("../canvas.js").Label|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement, 3: ImageOrLabelDimensions, 4: number, 5: Array<*>, 6: Array<*>}} ReplayImageOrLabelArgs 39459 */ 39460 39461/** 39462 * @template T 39463 * @typedef {function(import("../../Feature.js").FeatureLike, import("../../geom/SimpleGeometry.js").default): T} FeatureCallback 39464 */ 39465 39466/** 39467 * @type {import("../../extent.js").Extent} 39468 */ 39469const tmpExtent = createEmpty(); 39470 39471/** @type {import("../../coordinate.js").Coordinate} */ 39472const p1 = []; 39473/** @type {import("../../coordinate.js").Coordinate} */ 39474const p2 = []; 39475/** @type {import("../../coordinate.js").Coordinate} */ 39476const p3 = []; 39477/** @type {import("../../coordinate.js").Coordinate} */ 39478const p4 = []; 39479 39480/** 39481 * @param {ReplayImageOrLabelArgs} replayImageOrLabelArgs Arguments to replayImageOrLabel 39482 * @return {BBox} Declutter bbox. 39483 */ 39484function getDeclutterBox(replayImageOrLabelArgs) { 39485 return replayImageOrLabelArgs[3].declutterBox; 39486} 39487 39488const rtlRegEx = new RegExp( 39489 /* eslint-disable prettier/prettier */ 39490 '[' + 39491 String.fromCharCode(0x00591) + '-' + String.fromCharCode(0x008ff) + 39492 String.fromCharCode(0x0fb1d) + '-' + String.fromCharCode(0x0fdff) + 39493 String.fromCharCode(0x0fe70) + '-' + String.fromCharCode(0x0fefc) + 39494 String.fromCharCode(0x10800) + '-' + String.fromCharCode(0x10fff) + 39495 String.fromCharCode(0x1e800) + '-' + String.fromCharCode(0x1efff) + 39496 ']' 39497 /* eslint-enable prettier/prettier */ 39498); 39499 39500/** 39501 * @param {string} text Text. 39502 * @param {CanvasTextAlign} align Alignment. 39503 * @return {number} Text alignment. 39504 */ 39505function horizontalTextAlign(text, align) { 39506 if ((align === 'start' || align === 'end') && !rtlRegEx.test(text)) {
39507 align = align === 'start' ? 'left' : 'right'; 39508 } 39509 return TEXT_ALIGN[align]; 39510} 39511 39512/** 39513 * @param {Array<string>} acc Accumulator. 39514 * @param {string} line Line of text. 39515 * @param {number} i Index 39516 * @return {Array<string>} Accumulator. 39517 */ 39518function createTextChunks(acc, line, i) { 39519 if (i > 0) { 39520 acc.push('\n', ''); 39521 } 39522 acc.push(line, ''); 39523 return acc; 39524} 39525 39526class Executor { 39527 /** 39528 * @param {number} resolution Resolution. 39529 * @param {number} pixelRatio Pixel ratio. 39530 * @param {boolean} overlaps The replay can have overlapping geometries. 39531 * @param {import("../canvas.js").SerializableInstructions} instructions The serializable instructions 39532 */ 39533 constructor(resolution, pixelRatio, overlaps, instructions) { 39534 /** 39535 * @protected 39536 * @type {boolean} 39537 */ 39538 this.overlaps = overlaps; 39539 39540 /** 39541 * @protected 39542 * @type {number} 39543 */ 39544 this.pixelRatio = pixelRatio; 39545 39546 /** 39547 * @protected 39548 * @const 39549 * @type {number} 39550 */ 39551 this.resolution = resolution; 39552 39553 /** 39554 * @private 39555 * @type {boolean} 39556 */ 39557 this.alignFill_; 39558 39559 /** 39560 * @protected 39561 * @type {Array<*>} 39562 */ 39563 this.instructions = instructions.instructions; 39564 39565 /** 39566 * @protected 39567 * @type {Array<number>} 39568 */ 39569 this.coordinates = instructions.coordinates; 39570 39571 /** 39572 * @private 39573 * @type {!Object<number,import("../../coordinate.js").Coordinate|Array<import("../../coordinate.js").Coordinate>|Array<Array<import("../../coordinate.js").Coordinate>>>} 39574 */ 39575 this.coordinateCache_ = {}; 39576 39577 /** 39578 * @private 39579 * @type {!import("../../transform.js").Transform} 39580 */ 39581 this.renderedTransform_ = create(); 39582 39583 /** 39584 * @protected 39585 * @type {Array<*>} 39586 */ 39587 this.hitDetectionInstructions = instructions.hitDetectionInstructions; 39588 39589 /** 39590 * @private 39591 * @type {Array<number>} 39592 */ 39593 this.pixelCoordinates_ = null; 39594 39595 /** 39596 * @private 39597 * @type {number} 39598 */ 39599 this.viewRotation_ = 0; 39600 39601 /** 39602 * @type {!Object<string, import("../canvas.js").FillState>} 39603 */ 39604 this.fillStates = instructions.fillStates || {}; 39605 39606 /** 39607 * @type {!Object<string, import("../canvas.js").StrokeState>} 39608 */ 39609 this.strokeStates = instructions.strokeStates || {}; 39610 39611 /** 39612 * @type {!Object<string, import("../canvas.js").TextState>} 39613 */ 39614 this.textStates = instructions.textStates || {}; 39615 39616 /** 39617 * @private 39618 * @type {Object<string, Object<string, number>>} 39619 */ 39620 this.widths_ = {}; 39621 39622 /** 39623 * @private 39624 * @type {Object<string, import("../canvas.js").Label>} 39625 */ 39626 this.labels_ = {}; 39627 } 39628 39629 /** 39630 * @param {string|Array<string>} text Text. 39631 * @param {string} textKey Text style key. 39632 * @param {string} fillKey Fill style key. 39633 * @param {string} strokeKey Stroke style key. 39634 * @return {import("../canvas.js").Label} Label. 39635 */ 39636 createLabel(text, textKey, fillKey, strokeKey) { 39637 const key = text + textKey + fillKey + strokeKey; 39638 if (this.labels_[key]) { 39639 return this.labels_[key]; 39640 } 39641 const strokeState = strokeKey ? this.strokeStates[strokeKey] : null; 39642 const fillState = fillKey ? this.fillStates[fillKey] : null; 39643 const textState = this.textStates[textKey]; 39644 const pixelRatio = this.pixelRatio; 39645 const scale = [ 39646 textState.scale[0] * pixelRatio, 39647 textState.scale[1] * pixelRatio, 39648 ]; 39649 const textIsArray = Array.isArray(text); 39650 const align = textState.justify 39651 ? TEXT_ALIGN[textState.justify] 39652 : horizontalTextAlign( 39653 Array.isArray(text) ? text[0] : text, 39654 textState.textAlign || defaultTextAlign 39655 ); 39656 const strokeWidth = 39657 strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0; 39658 39659 const chunks = textIsArray 39660 ? text 39661 : text.split('\n').reduce(createTextChunks, []); 39662 39663 const {width, height, widths, heights, lineWidths} = getTextDimensions( 39664 textState, 39665 chunks 39666 ); 39667 const renderWidth = width + strokeWidth; 39668 const contextInstructions = []; 39669 // make canvas 2 pixels wider to account for italic text width measurement errors 39670 const w = (renderWidth + 2) * scale[0]; 39671 const h = (height + strokeWidth) * scale[1]; 39672 /** @type {import("../canvas.js").Label} */ 39673 const label = { 39674 width: w < 0 ? Math.floor(w) : Math.ceil(w), 39675 height: h < 0 ? Math.floor(h) : Math.ceil(h), 39676 contextInstructions: contextInstructions, 39677 }; 39678 if (scale[0] != 1 || scale[1] != 1) { 39679 contextInstructions.push('scale', scale); 39680 } 39681 if (strokeKey) { 39682 contextInstructions.push('strokeStyle', strokeState.strokeStyle); 39683 contextInstructions.push('lineWidth', strokeWidth); 39684 contextInstructions.push('lineCap', strokeState.lineCap); 39685 contextInstructions.push('lineJoin', strokeState.lineJoin); 39686 contextInstructions.push('miterLimit', strokeState.miterLimit); 39687 contextInstructions.push('setLineDash', [strokeState.lineDash]); 39688 contextInstructions.push('lineDashOffset', strokeState.lineDashOffset); 39689 } 39690 if (fillKey) { 39691 contextInstructions.push('fillStyle', fillState.fillStyle); 39692 } 39693 contextInstructions.push('textBaseline', 'middle'); 39694 contextInstructions.push('textAlign', 'center'); 39695 const leftRight = 0.5 - align; 39696 let x = align * renderWidth + leftRight * strokeWidth;
39697 const strokeInstructions = []; 39698 const fillInstructions = []; 39699 let lineHeight = 0; 39700 let lineOffset = 0; 39701 let widthHeightIndex = 0; 39702 let lineWidthIndex = 0; 39703 let previousFont; 39704 for (let i = 0, ii = chunks.length; i < ii; i += 2) { 39705 const text = chunks[i]; 39706 if (text === '\n') { 39707 lineOffset += lineHeight; 39708 lineHeight = 0; 39709 x = align * renderWidth + leftRight * strokeWidth; 39710 ++lineWidthIndex; 39711 continue; 39712 } 39713 const font = chunks[i + 1] || textState.font; 39714 if (font !== previousFont) { 39715 if (strokeKey) { 39716 strokeInstructions.push('font', font); 39717 } 39718 if (fillKey) { 39719 fillInstructions.push('font', font); 39720 } 39721 previousFont = font; 39722 } 39723 lineHeight = Math.max(lineHeight, heights[widthHeightIndex]); 39724 const fillStrokeArgs = [ 39725 text, 39726 x + 39727 leftRight * widths[widthHeightIndex] + 39728 align * (widths[widthHeightIndex] - lineWidths[lineWidthIndex]), 39729 0.5 * (strokeWidth + lineHeight) + lineOffset, 39730 ]; 39731 x += widths[widthHeightIndex]; 39732 if (strokeKey) { 39733 strokeInstructions.push('strokeText', fillStrokeArgs); 39734 } 39735 if (fillKey) { 39736 fillInstructions.push('fillText', fillStrokeArgs); 39737 } 39738 ++widthHeightIndex; 39739 } 39740 Array.prototype.push.apply(contextInstructions, strokeInstructions); 39741 Array.prototype.push.apply(contextInstructions, fillInstructions); 39742 this.labels_[key] = label; 39743 return label; 39744 } 39745 39746 /** 39747 * @param {CanvasRenderingContext2D} context Context. 39748 * @param {import("../../coordinate.js").Coordinate} p1 1st point of the background box. 39749 * @param {import("../../coordinate.js").Coordinate} p2 2nd point of the background box. 39750 * @param {import("../../coordinate.js").Coordinate} p3 3rd point of the background box. 39751 * @param {import("../../coordinate.js").Coordinate} p4 4th point of the background box. 39752 * @param {Array<*>} fillInstruction Fill instruction. 39753 * @param {Array<*>} strokeInstruction Stroke instruction. 39754 */ 39755 replayTextBackground_( 39756 context, 39757 p1, 39758 p2, 39759 p3, 39760 p4, 39761 fillInstruction, 39762 strokeInstruction 39763 ) { 39764 context.beginPath(); 39765 context.moveTo.apply(context, p1); 39766 context.lineTo.apply(context, p2); 39767 context.lineTo.apply(context, p3); 39768 context.lineTo.apply(context, p4); 39769 context.lineTo.apply(context, p1); 39770 if (fillInstruction) { 39771 this.alignFill_ = /** @type {boolean} */ (fillInstruction[2]); 39772 this.fill_(context); 39773 } 39774 if (strokeInstruction) { 39775 this.setStrokeStyle_( 39776 context, 39777 /** @type {Array<*>} */ (strokeInstruction) 39778 ); 39779 context.stroke(); 39780 } 39781 } 39782 39783 /** 39784 * @private 39785 * @param {number} sheetWidth Width of the sprite sheet. 39786 * @param {number} sheetHeight Height of the sprite sheet. 39787 * @param {number} centerX X. 39788 * @param {number} centerY Y. 39789 * @param {number} width Width. 39790 * @param {number} height Height. 39791 * @param {number} anchorX Anchor X. 39792 * @param {number} anchorY Anchor Y. 39793 * @param {number} originX Origin X. 39794 * @param {number} originY Origin Y. 39795 * @param {number} rotation Rotation. 39796 * @param {import("../../size.js").Size} scale Scale. 39797 * @param {boolean} snapToPixel Snap to pixel. 39798 * @param {Array<number>} padding Padding. 39799 * @param {boolean} fillStroke Background fill or stroke. 39800 * @param {import("../../Feature.js").FeatureLike} feature Feature. 39801 * @return {ImageOrLabelDimensions} Dimensions for positioning and decluttering the image or label. 39802 */ 39803 calculateImageOrLabelDimensions_( 39804 sheetWidth, 39805 sheetHeight, 39806 centerX, 39807 centerY, 39808 width, 39809 height, 39810 anchorX, 39811 anchorY, 39812 originX, 39813 originY, 39814 rotation, 39815 scale, 39816 snapToPixel, 39817 padding, 39818 fillStroke, 39819 feature 39820 ) { 39821 anchorX *= scale[0]; 39822 anchorY *= scale[1]; 39823 let x = centerX - anchorX; 39824 let y = centerY - anchorY; 39825 39826 const w = width + originX > sheetWidth ? sheetWidth - originX : width; 39827 const h = height + originY > sheetHeight ? sheetHeight - originY : height; 39828 const boxW = padding[3] + w * scale[0] + padding[1]; 39829 const boxH = padding[0] + h * scale[1] + padding[2]; 39830 const boxX = x - padding[3]; 39831 const boxY = y - padding[0]; 39832 39833 if (fillStroke || rotation !== 0) { 39834 p1[0] = boxX; 39835 p4[0] = boxX; 39836 p1[1] = boxY; 39837 p2[1] = boxY; 39838 p2[0] = boxX + boxW; 39839 p3[0] = p2[0]; 39840 p3[1] = boxY + boxH; 39841 p4[1] = p3[1]; 39842 } 39843 39844 let transform; 39845 if (rotation !== 0) { 39846 transform = compose( 39847 create(), 39848 centerX, 39849 centerY, 39850 1, 39851 1, 39852 rotation, 39853 -centerX, 39854 -centerY 39855 ); 39856 39857 apply(transform, p1); 39858 apply(transform, p2); 39859 apply(transform, p3); 39860 apply(transform, p4); 39861 createOrUpdate( 39862 Math.min(p1[0], p2[0], p3[0], p4[0]), 39863 Math.min(p1[1], p2[1], p3[1], p4[1]), 39864 Math.max(p1[0], p2[0], p3[0], p4[0]), 39865 Math.max(p1[1], p2[1], p3[1], p4[1]), 39866 tmpExtent 39867 ); 39868 } else { 39869 createOrUpdate( 39870 Math.min(boxX, boxX + boxW), 39871 Math.min(boxY, boxY + boxH), 39872 Math.max(boxX, boxX + boxW), 39873 Math.max(boxY, boxY + boxH), 39874 tmpExtent 39875 ); 39876 } 39877 if (snapToPixel) { 39878 x = Math.round(x); 39879 y = Math.round(y); 39880 } 39881 return { 39882 drawImageX: x, 39883 drawImageY: y, 39884 drawImageW: w, 39885 drawImageH: h, 39886 originX: originX, 39887 originY: originY, 39888 declutterBox: { 39889 minX: tmpExtent[0], 39890 minY: tmpExtent[1], 39891 maxX: tmpExtent[2], 39892 maxY: tmpExtent[3], 39893 value: feature, 39894 }, 39895 canvasTransform: transform, 39896 scale: scale, 39897 }; 39898 } 39899 39900 /** 39901 * @private 39902 * @param {CanvasRenderingContext2D} context Context. 39903 * @param {number} contextScale Scale of the context. 39904 * @param {import("../canvas.js").Label|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} imageOrLabel Image. 39905 * @param {ImageOrLabelDimensions} dimensions Dimensions. 39906 * @param {number} opacity Opacity. 39907 * @param {Array<*>} fillInstruction Fill instruction. 39908 * @param {Array<*>}
39908 strokeInstruction Stroke instruction. 39909 * @return {boolean} The image or label was rendered. 39910 */ 39911 replayImageOrLabel_( 39912 context, 39913 contextScale, 39914 imageOrLabel, 39915 dimensions, 39916 opacity, 39917 fillInstruction, 39918 strokeInstruction 39919 ) { 39920 const fillStroke = !!(fillInstruction || strokeInstruction); 39921 39922 const box = dimensions.declutterBox; 39923 const canvas = context.canvas; 39924 const strokePadding = strokeInstruction 39925 ? (strokeInstruction[2] * dimensions.scale[0]) / 2 39926 : 0; 39927 const intersects = 39928 box.minX - strokePadding <= canvas.width / contextScale && 39929 box.maxX + strokePadding >= 0 && 39930 box.minY - strokePadding <= canvas.height / contextScale && 39931 box.maxY + strokePadding >= 0; 39932 39933 if (intersects) { 39934 if (fillStroke) { 39935 this.replayTextBackground_( 39936 context, 39937 p1, 39938 p2, 39939 p3, 39940 p4, 39941 /** @type {Array<*>} */ (fillInstruction), 39942 /** @type {Array<*>} */ (strokeInstruction) 39943 ); 39944 } 39945 drawImageOrLabel( 39946 context, 39947 dimensions.canvasTransform, 39948 opacity, 39949 imageOrLabel, 39950 dimensions.originX, 39951 dimensions.originY, 39952 dimensions.drawImageW, 39953 dimensions.drawImageH, 39954 dimensions.drawImageX, 39955 dimensions.drawImageY, 39956 dimensions.scale 39957 ); 39958 } 39959 return true; 39960 } 39961 39962 /** 39963 * @private 39964 * @param {CanvasRenderingContext2D} context Context. 39965 */ 39966 fill_(context) { 39967 if (this.alignFill_) { 39968 const origin = apply(this.renderedTransform_, [0, 0]); 39969 const repeatSize = 512 * this.pixelRatio; 39970 context.save(); 39971 context.translate(origin[0] % repeatSize, origin[1] % repeatSize); 39972 context.rotate(this.viewRotation_); 39973 } 39974 context.fill(); 39975 if (this.alignFill_) { 39976 context.restore(); 39977 } 39978 } 39979 39980 /** 39981 * @private 39982 * @param {CanvasRenderingContext2D} context Context. 39983 * @param {Array<*>} instruction Instruction. 39984 */ 39985 setStrokeStyle_(context, instruction) { 39986 context['strokeStyle'] = 39987 /** @type {import("../../colorlike.js").ColorLike} */ (instruction[1]); 39988 context.lineWidth = /** @type {number} */ (instruction[2]); 39989 context.lineCap = /** @type {CanvasLineCap} */ (instruction[3]); 39990 context.lineJoin = /** @type {CanvasLineJoin} */ (instruction[4]); 39991 context.miterLimit = /** @type {number} */ (instruction[5]); 39992 context.lineDashOffset = /** @type {number} */ (instruction[7]); 39993 context.setLineDash(/** @type {Array<number>} */ (instruction[6])); 39994 } 39995 39996 /** 39997 * @private 39998 * @param {string|Array<string>} text The text to draw. 39999 * @param {string} textKey The key of the text state. 40000 * @param {string} strokeKey The key for the stroke state. 40001 * @param {string} fillKey The key for the fill state. 40002 * @return {{label: import("../canvas.js").Label, anchorX: number, anchorY: number}} The text image and its anchor. 40003 */ 40004 drawLabelWithPointPlacement_(text, textKey, strokeKey, fillKey) { 40005 const textState = this.textStates[textKey]; 40006 40007 const label = this.createLabel(text, textKey, fillKey, strokeKey); 40008 40009 const strokeState = this.strokeStates[strokeKey]; 40010 const pixelRatio = this.pixelRatio; 40011 const align = horizontalTextAlign( 40012 Array.isArray(text) ? text[0] : text, 40013 textState.textAlign || defaultTextAlign 40014 ); 40015 const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline]; 40016 const strokeWidth = 40017 strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0; 40018 40019 // Remove the 2 pixels we added in createLabel() for the anchor 40020 const width = label.width / pixelRatio - 2 * textState.scale[0]; 40021 const anchorX = align * width + 2 * (0.5 - align) * strokeWidth; 40022 const anchorY = 40023 (baseline * label.height) / pixelRatio + 40024 2 * (0.5 - baseline) * strokeWidth; 40025 40026 return { 40027 label: label, 40028 anchorX: anchorX, 40029 anchorY: anchorY, 40030 }; 40031 } 40032 40033 /** 40034 * @private 40035 * @param {CanvasRenderingContext2D} context Context. 40036 * @param {number} contextScale Scale of the context. 40037 * @param {import("../../transform.js").Transform} transform Transform. 40038 * @param {Array<*>}
40038 instructions Instructions array. 40039 * @param {boolean} snapToPixel Snap point symbols and text to integer pixels. 40040 * @param {FeatureCallback<T>} [featureCallback] Feature callback. 40041 * @param {import("../../extent.js").Extent} [hitExtent] Only check 40042 * features that intersect this extent. 40043 * @param {import("rbush").default} [declutterTree] Declutter tree. 40044 * @return {T|undefined} Callback result. 40045 * @template T 40046 */ 40047 execute_( 40048 context, 40049 contextScale, 40050 transform, 40051 instructions, 40052 snapToPixel, 40053 featureCallback, 40054 hitExtent, 40055 declutterTree 40056 ) { 40057 /** @type {Array<number>} */ 40058 let pixelCoordinates; 40059 if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) { 40060 pixelCoordinates = this.pixelCoordinates_; 40061 } else { 40062 if (!this.pixelCoordinates_) { 40063 this.pixelCoordinates_ = []; 40064 } 40065 pixelCoordinates = transform2D( 40066 this.coordinates, 40067 0, 40068 this.coordinates.length, 40069 2, 40070 transform, 40071 this.pixelCoordinates_ 40072 ); 40073 setFromArray(this.renderedTransform_, transform); 40074 } 40075 let i = 0; // instruction index 40076 const ii = instructions.length; // end of instructions 40077 let d = 0; // data index 40078 let dd; // end of per-instruction data 40079 let anchorX, 40080 anchorY, 40081 prevX, 40082 prevY, 40083 roundX, 40084 roundY, 40085 image, 40086 text, 40087 textKey, 40088 strokeKey, 40089 fillKey; 40090 let pendingFill = 0; 40091 let pendingStroke = 0; 40092 let lastFillInstruction = null; 40093 let lastStrokeInstruction = null; 40094 const coordinateCache = this.coordinateCache_; 40095 const viewRotation = this.viewRotation_; 40096 const viewRotationFromTransform = 40097 Math.round(Math.atan2(-transform[1], transform[0]) * 1e12) / 1e12; 40098 40099 const state = /** @type {import("../../render.js").State} */ ({ 40100 context: context, 40101 pixelRatio: this.pixelRatio, 40102 resolution: this.resolution, 40103 rotation: viewRotation, 40104 }); 40105 40106 // When the batch size gets too big, performance decreases. 200 is a good 40107 // balance between batch size and number of fill/stroke instructions. 40108 const batchSize = 40109 this.instructions != instructions || this.overlaps ? 0 : 200; 40110 let /** @type {import("../../Feature.js").FeatureLike} */ feature; 40111 let x, y, currentGeometry; 40112 while (i < ii) { 40113 const instruction = instructions[i]; 40114 const type = /** @type {import("./Instruction.js").default} */ ( 40115 instruction[0] 40116 ); 40117 switch (type) { 40118 case canvas_Instruction.BEGIN_GEOMETRY: 40119 feature = /** @type {import("../../Feature.js").FeatureLike} */ ( 40120 instruction[1] 40121 ); 40122 currentGeometry = instruction[3]; 40123 if (!feature.getGeometry()) { 40124 i = /** @type {number} */ (instruction[2]); 40125 } else if ( 40126 hitExtent !== undefined && 40127 !intersects(hitExtent, currentGeometry.getExtent()) 40128 ) { 40129 i = /** @type {number} */ (instruction[2]) + 1; 40130 } else { 40131 ++i; 40132 } 40133 break; 40134 case canvas_Instruction.BEGIN_PATH: 40135 if (pendingFill > batchSize) { 40136 this.fill_(context); 40137 pendingFill = 0; 40138 } 40139 if (pendingStroke > batchSize) { 40140 context.stroke(); 40141 pendingStroke = 0; 40142 } 40143 if (!pendingFill && !pendingStroke) { 40144 context.beginPath(); 40145 prevX = NaN; 40146 prevY = NaN; 40147 } 40148 ++i; 40149 break; 40150 case canvas_Instruction.CIRCLE: 40151 d = /** @type {number} */ (instruction[1]); 40152 const x1 = pixelCoordinates[d]; 40153 const y1 = pixelCoordinates[d + 1]; 40154 const x2 = pixelCoordinates[d + 2]; 40155 const y2 = pixelCoordinates[d + 3]; 40156 const dx = x2 - x1; 40157 const dy = y2 - y1; 40158 const r = Math.sqrt(dx * dx + dy * dy); 40159 context.moveTo(x1 + r, y1); 40160 context.arc(x1, y1, r, 0, 2 * Math.PI, true); 40161 ++i; 40162 break; 40163 case canvas_Instruction.CLOSE_PATH: 40164 context.closePath(); 40165 ++i; 40166 break;
40167 case canvas_Instruction.CUSTOM: 40168 d = /** @type {number} */ (instruction[1]); 40169 dd = instruction[2]; 40170 const geometry = 40171 /** @type {import("../../geom/SimpleGeometry.js").default} */ ( 40172 instruction[3] 40173 ); 40174 const renderer = instruction[4]; 40175 const fn = instruction.length == 6 ? instruction[5] : undefined; 40176 state.geometry = geometry; 40177 state.feature = feature; 40178 if (!(i in coordinateCache)) { 40179 coordinateCache[i] = []; 40180 } 40181 const coords = coordinateCache[i]; 40182 if (fn) { 40183 fn(pixelCoordinates, d, dd, 2, coords); 40184 } else { 40185 coords[0] = pixelCoordinates[d]; 40186 coords[1] = pixelCoordinates[d + 1]; 40187 coords.length = 2; 40188 } 40189 renderer(coords, state); 40190 ++i; 40191 break; 40192 case canvas_Instruction.DRAW_IMAGE: 40193 d = /** @type {number} */ (instruction[1]); 40194 dd = /** @type {number} */ (instruction[2]); 40195 image = 40196 /** @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} */ ( 40197 instruction[3] 40198 ); 40199 40200 // Remaining arguments in DRAW_IMAGE are in alphabetical order 40201 anchorX = /** @type {number} */ (instruction[4]); 40202 anchorY = /** @type {number} */ (instruction[5]); 40203 let height = /** @type {number} */ (instruction[6]); 40204 const opacity = /** @type {number} */ (instruction[7]); 40205 const originX = /** @type {number} */ (instruction[8]); 40206 const originY = /** @type {number} */ (instruction[9]); 40207 const rotateWithView = /** @type {boolean} */ (instruction[10]); 40208 let rotation = /** @type {number} */ (instruction[11]); 40209 const scale = /** @type {import("../../size.js").Size} */ ( 40210 instruction[12] 40211 ); 40212 let width = /** @type {number} */ (instruction[13]); 40213 const declutterMode = 40214 /** @type {"declutter"|"obstacle"|"none"|undefined} */ ( 40215 instruction[14] 40216 ); 40217 const declutterImageWithText = 40218 /** @type {import("../canvas.js").DeclutterImageWithText} */ ( 40219 instruction[15] 40220 ); 40221 40222 if (!image && instruction.length >= 20) { 40223 // create label images 40224 text = /** @type {string} */ (instruction[19]); 40225 textKey = /** @type {string} */ (instruction[20]); 40226 strokeKey = /** @type {string} */ (instruction[21]); 40227 fillKey = /** @type {string} */ (instruction[22]); 40228 const labelWithAnchor = this.drawLabelWithPointPlacement_( 40229 text, 40230 textKey, 40231 strokeKey, 40232 fillKey 40233 ); 40234 image = labelWithAnchor.label; 40235 instruction[3] = image; 40236 const textOffsetX = /** @type {number} */ (instruction[23]); 40237 anchorX = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio; 40238 instruction[4] = anchorX; 40239 const textOffsetY = /** @type {number} */ (instruction[24]); 40240 anchorY = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio; 40241 instruction[5] = anchorY; 40242 height = image.height; 40243 instruction[6] = height; 40244 width = image.width; 40245 instruction[13] = width; 40246 } 40247 40248 let geometryWidths; 40249 if (instruction.length > 25) { 40250 geometryWidths = /** @type {number} */ (instruction[25]); 40251 } 40252 40253 let padding, backgroundFill, backgroundStroke; 40254 if (instruction.length > 17) { 40255 padding = /** @type {Array<number>} */ (instruction[16]); 40256 backgroundFill = /** @type {boolean} */ (instruction[17]); 40257 backgroundStroke = /** @type {boolean} */ (instruction[18]); 40258 } else { 40259 padding = defaultPadding; 40260 backgroundFill = false; 40261 backgroundStroke = false; 40262 } 40263 40264 if (rotateWithView && viewRotationFromTransform) { 40265 // Canvas is expected to be rotated to reverse view rotation. 40266 rotation += viewRotation; 40267 } else if (!rotateWithView && !viewRotationFromTransform) { 40268 // Canvas is not rotated, images need to be rotated back to be north-up. 40269 rotation -= viewRotation; 40270 } 40271 let widthIndex = 0; 40272 for (; d < dd; d += 2) { 40273 if ( 40274 geometryWidths && 40275 geometryWidths[widthIndex++] < width / this.pixelRatio 40276 ) { 40277 continue; 40278 } 40279 const dimensions = this.calculateImageOrLabelDimensions_( 40280 image.width, 40281 image.height, 40282 pixelCoordinates[d], 40283 pixelCoordinates[d + 1], 40284 width, 40285 height, 40286 anchorX, 40287 anchorY, 40288 originX, 40289 originY, 40290 rotation, 40291 scale, 40292 snapToPixel, 40293 padding, 40294 backgroundFill || backgroundStroke, 40295 feature 40296 ); 40297 /** @type {ReplayImageOrLabelArgs} */ 40298 const args = [ 40299 context, 40300 contextScale, 40301 image, 40302 dimensions, 40303 opacity, 40304 backgroundFill 40305 ? /** @type {Array<*>} */ (lastFillInstruction) 40306 : null, 40307 backgroundStroke 40308 ? /** @type {Array<*>}
40308 */ (lastStrokeInstruction) 40309 : null, 40310 ]; 40311 if (declutterTree) { 40312 if (declutterMode === 'none') { 40313 // not rendered in declutter group 40314 continue; 40315 } else if (declutterMode === 'obstacle') { 40316 // will always be drawn, thus no collision detection, but insert as obstacle 40317 declutterTree.insert(dimensions.declutterBox); 40318 continue; 40319 } else { 40320 let imageArgs; 40321 let imageDeclutterBox; 40322 if (declutterImageWithText) { 40323 const index = dd - d; 40324 if (!declutterImageWithText[index]) { 40325 // We now have the image for an image+text combination. 40326 declutterImageWithText[index] = args; 40327 // Don't render anything for now, wait for the text. 40328 continue; 40329 } 40330 imageArgs = declutterImageWithText[index]; 40331 delete declutterImageWithText[index]; 40332 imageDeclutterBox = getDeclutterBox(imageArgs); 40333 if (declutterTree.collides(imageDeclutterBox)) { 40334 continue; 40335 } 40336 } 40337 if (declutterTree.collides(dimensions.declutterBox)) { 40338 continue; 40339 } 40340 if (imageArgs) { 40341 // We now have image and text for an image+text combination. 40342 declutterTree.insert(imageDeclutterBox); 40343 // Render the image before we render the text. 40344 this.replayImageOrLabel_.apply(this, imageArgs); 40345 } 40346 declutterTree.insert(dimensions.declutterBox); 40347 } 40348 } 40349 this.replayImageOrLabel_.apply(this, args); 40350 } 40351 ++i; 40352 break; 40353 case canvas_Instruction.DRAW_CHARS: 40354 const begin = /** @type {number} */ (instruction[1]); 40355 const end = /** @type {number} */ (instruction[2]); 40356 const baseline = /** @type {number} */ (instruction[3]); 40357 const overflow = /** @type {number} */ (instruction[4]); 40358 fillKey = /** @type {string} */ (instruction[5]); 40359 const maxAngle = /** @type {number} */ (instruction[6]); 40360 const measurePixelRatio = /** @type {number} */ (instruction[7]); 40361 const offsetY = /** @type {number} */ (instruction[8]); 40362 strokeKey = /** @type {string} */ (instruction[9]); 40363 const strokeWidth = /** @type {number} */ (instruction[10]); 40364 text = /** @type {string} */ (instruction[11]); 40365 textKey = /** @type {string} */ (instruction[12]); 40366 const pixelRatioScale = [ 40367 /** @type {number} */ (instruction[13]), 40368 /** @type {number} */ (instruction[13]), 40369 ]; 40370 40371 const textState = this.textStates[textKey]; 40372 const font = textState.font; 40373 const textScale = [ 40374 textState.scale[0] * measurePixelRatio, 40375 textState.scale[1] * measurePixelRatio, 40376 ]; 40377 40378 let cachedWidths; 40379 if (font in this.widths_) { 40380 cachedWidths = this.widths_[font]; 40381 } else { 40382 cachedWidths = {}; 40383 this.widths_[font] = cachedWidths; 40384 } 40385 40386 const pathLength = lineStringLength(pixelCoordinates, begin, end, 2); 40387 const textLength = 40388 Math.abs(textScale[0]) * 40389 measureAndCacheTextWidth(font, text, cachedWidths); 40390 if (overflow || textLength <= pathLength) { 40391 const textAlign = this.textStates[textKey].textAlign; 40392 const startM = (pathLength - textLength) * TEXT_ALIGN[textAlign]; 40393 const parts = drawTextOnPath( 40394 pixelCoordinates, 40395 begin, 40396 end, 40397 2, 40398 text, 40399 startM, 40400 maxAngle, 40401 Math.abs(textScale[0]), 40402 measureAndCacheTextWidth, 40403 font, 40404 cachedWidths, 40405 viewRotationFromTransform ? 0 : this.viewRotation_ 40406 ); 40407 drawChars: if (parts) { 40408 /** @type {Array<ReplayImageOrLabelArgs>} */ 40409 const replayImageOrLabelArgs = []; 40410 let c, cc, chars, label, part; 40411 if (strokeKey) { 40412 for (c = 0, cc = parts.length; c < cc; ++c) { 40413 part = parts[c]; // x, y, anchorX, rotation, chunk 40414 chars = /** @type {string} */ (part[4]); 40415 label = this.createLabel(chars, textKey, '', strokeKey); 40416 anchorX = 40417 /** @type {number} */ (part[2]) + 40418 (textScale[0] < 0 ? -strokeWidth : strokeWidth); 40419 anchorY = 40420 baseline * label.height + 40421 ((0.5 - baseline) * 2 * strokeWidth * textScale[1]) / 40422 textScale[0] - 40423 offsetY; 40424 const dimensions = this.calculateImageOrLabelDimensions_( 40425 label.width, 40426 label.height, 40427 part[0], 40428 part[1], 40429 label.width, 40430 label.height, 40431 anchorX, 40432 anchorY, 40433 0, 40434 0, 40435 part[3], 40436 pixelRatioScale, 40437 false, 40438 defaultPadding, 40439 false, 40440 feature 40441 ); 40442 if ( 40443 declutterTree && 40444 declutterTree.collides(dimensions.declutterBox) 40445 ) { 40446 break drawChars; 40447 } 40448 replayImageOrLabelArgs.push([ 40449 context, 40450 contextScale, 40451 label, 40452 dimensions, 40453 1, 40454 null, 40455 null, 40456 ]); 40457 } 40458 } 40459 if (fillKey) { 40460 for (c = 0, cc = parts.length; c < cc; ++c) { 40461 part = parts[c]; // x, y, anchorX, rotation, chunk 40462 chars = /** @type {string} */ (part[4]); 40463 label = this.createLabel(chars, textKey, fillKey, ''); 40464 anchorX = /** @type {number} */ (part[2]); 40465 anchorY = baseline * label.height - offsetY; 40466 const dimensions = this.calculateImageOrLabelDimensions_( 40467 label.width, 40468 label.height, 40469 part[0], 40470 part[1], 40471 label.width, 40472 label.height, 40473 anchorX, 40474 anchorY, 40475 0, 40476 0, 40477 part[3], 40478 pixelRatioScale, 40479 false, 40480 defaultPadding, 40481 false, 40482 feature 40483 ); 40484 if ( 40485 declutterTree && 40486 declutterTree.collides(dimensions.declutterBox) 40487 ) { 40488 break drawChars; 40489 } 40490 replayImageOrLabelArgs.push([ 40491 context, 40492 contextScale, 40493 label, 40494 dimensions, 40495 1, 40496 null, 40497 null, 40498 ]); 40499 } 40500 } 40501 if (declutterTree) { 40502 declutterTree.load(replayImageOrLabelArgs.map(getDeclutterBox)); 40503 } 40504 for (let i = 0, ii = replayImageOrLabelArgs.length; i < ii; ++i) { 40505 this.replayImageOrLabel_.apply(this, replayImageOrLabelArgs[i]); 40506 } 40507 } 40508 } 40509 ++i; 40510 break;
40511 case canvas_Instruction.END_GEOMETRY: 40512 if (featureCallback !== undefined) { 40513 feature = /** @type {import("../../Feature.js").FeatureLike} */ ( 40514 instruction[1] 40515 ); 40516 const result = featureCallback(feature, currentGeometry); 40517 if (result) { 40518 return result; 40519 } 40520 } 40521 ++i; 40522 break; 40523 case canvas_Instruction.FILL: 40524 if (batchSize) { 40525 pendingFill++; 40526 } else { 40527 this.fill_(context); 40528 } 40529 ++i; 40530 break; 40531 case canvas_Instruction.MOVE_TO_LINE_TO: 40532 d = /** @type {number} */ (instruction[1]); 40533 dd = /** @type {number} */ (instruction[2]); 40534 x = pixelCoordinates[d]; 40535 y = pixelCoordinates[d + 1]; 40536 roundX = (x + 0.5) | 0; 40537 roundY = (y + 0.5) | 0; 40538 if (roundX !== prevX || roundY !== prevY) { 40539 context.moveTo(x, y); 40540 prevX = roundX; 40541 prevY = roundY; 40542 } 40543 for (d += 2; d < dd; d += 2) { 40544 x = pixelCoordinates[d]; 40545 y = pixelCoordinates[d + 1]; 40546 roundX = (x + 0.5) | 0; 40547 roundY = (y + 0.5) | 0; 40548 if (d == dd - 2 || roundX !== prevX || roundY !== prevY) { 40549 context.lineTo(x, y); 40550 prevX = roundX; 40551 prevY = roundY; 40552 } 40553 } 40554 ++i; 40555 break; 40556 case canvas_Instruction.SET_FILL_STYLE: 40557 lastFillInstruction = instruction; 40558 this.alignFill_ = instruction[2]; 40559 40560 if (pendingFill) { 40561 this.fill_(context); 40562 pendingFill = 0; 40563 if (pendingStroke) { 40564 context.stroke(); 40565 pendingStroke = 0; 40566 } 40567 } 40568 40569 context.fillStyle = 40570 /** @type {import("../../colorlike.js").ColorLike} */ ( 40571 instruction[1] 40572 ); 40573 ++i; 40574 break; 40575 case canvas_Instruction.SET_STROKE_STYLE: 40576 lastStrokeInstruction = instruction; 40577 if (pendingStroke) { 40578 context.stroke(); 40579 pendingStroke = 0; 40580 } 40581 this.setStrokeStyle_(context, /** @type {Array<*>} */ (instruction)); 40582 ++i; 40583 break; 40584 case canvas_Instruction.STROKE: 40585 if (batchSize) { 40586 pendingStroke++; 40587 } else { 40588 context.stroke(); 40589 } 40590 ++i; 40591 break; 40592 default: // consume the instruction anyway, to avoid an infinite loop 40593 ++i; 40594 break; 40595 } 40596 } 40597 if (pendingFill) { 40598 this.fill_(context); 40599 } 40600 if (pendingStroke) { 40601 context.stroke(); 40602 } 40603 return undefined; 40604 } 40605 40606 /** 40607 * @param {CanvasRenderingContext2D} context Context. 40608 * @param {number} contextScale Scale of the context. 40609 * @param {import("../../transform.js").Transform} transform Transform. 40610 * @param {number} viewRotation View rotation. 40611 * @param {boolean} snapToPixel Snap point symbols and text to integer pixels. 40612 * @param {import("rbush").default} [declutterTree] Declutter tree. 40613 */ 40614 execute( 40615 context, 40616 contextScale, 40617 transform, 40618 viewRotation, 40619 snapToPixel, 40620 declutterTree 40621 ) { 40622 this.viewRotation_ = viewRotation; 40623 this.execute_( 40624 context, 40625 contextScale, 40626 transform, 40627 this.instructions, 40628 snapToPixel, 40629 undefined, 40630 undefined, 40631 declutterTree 40632 ); 40633 } 40634 40635 /** 40636 * @param {CanvasRenderingContext2D} context Context. 40637 * @param {import("../../transform.js").Transform} transform Transform. 40638 * @param {number} viewRotation View rotation. 40639 * @param {FeatureCallback<T>} [featureCallback] Feature callback. 40640 * @param {import("../../extent.js").Extent} [hitExtent] Only check 40641 * features that intersect this extent. 40642 * @return {T|undefined} Callback result. 40643 * @template T 40644 */ 40645 executeHitDetection( 40646 context, 40647 transform, 40648 viewRotation, 40649 featureCallback, 40650 hitExtent 40651 ) { 40652 this.viewRotation_ = viewRotation; 40653 return this.execute_( 40654 context, 40655 1, 40656 transform, 40657 this.hitDetectionInstructions, 40658 true, 40659 featureCallback, 40660 hitExtent 40661 ); 40662 } 40663} 40664 40665/* harmony default export */ const canvas_Executor = (Executor); 40666 40667;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/ExecutorGroup.js 40668/** 40669 * @module ol/render/canvas/ExecutorGroup 40670 */ 40671 40672 40673 40674 40675 40676 40677 40678 40679 40680/** 40681 * @const 40682 * @type {Array<import("../canvas.js").BuilderType>} 40683 */ 40684const ORDER = ['Polygon', 'Circle', 'LineString', 'Image', 'Text', 'Default']; 40685 40686class ExecutorGroup { 40687 /** 40688 * @param {import("../../extent.js").Extent} maxExtent Max extent for clipping. When a 40689 * `maxExtent` was set on the Builder for this executor group, the same `maxExtent` 40690 * should be set here, unless the target context does not exceed that extent (which 40691 * can be the case when rendering to tiles). 40692 * @param {number} resolution Resolution. 40693 * @param {number} pixelRatio Pixel ratio. 40694 * @param {boolean} overlaps The executor group can have overlapping geometries. 40695 * @param {!Object<string, !Object<import("../canvas.js").BuilderType, import("../canvas.js").SerializableInstructions>>} allInstructions
40696 * The serializable instructions. 40697 * @param {number} [renderBuffer] Optional rendering buffer. 40698 */ 40699 constructor( 40700 maxExtent, 40701 resolution, 40702 pixelRatio, 40703 overlaps, 40704 allInstructions, 40705 renderBuffer 40706 ) { 40707 /** 40708 * @private 40709 * @type {import("../../extent.js").Extent} 40710 */ 40711 this.maxExtent_ = maxExtent; 40712 40713 /** 40714 * @private 40715 * @type {boolean} 40716 */ 40717 this.overlaps_ = overlaps; 40718 40719 /** 40720 * @private 40721 * @type {number} 40722 */ 40723 this.pixelRatio_ = pixelRatio; 40724 40725 /** 40726 * @private 40727 * @type {number} 40728 */ 40729 this.resolution_ = resolution; 40730 40731 /** 40732 * @private 40733 * @type {number|undefined} 40734 */ 40735 this.renderBuffer_ = renderBuffer; 40736 40737 /** 40738 * @private 40739 * @type {!Object<string, !Object<import("../canvas.js").BuilderType, import("./Executor").default>>} 40740 */ 40741 this.executorsByZIndex_ = {}; 40742 40743 /** 40744 * @private 40745 * @type {CanvasRenderingContext2D} 40746 */ 40747 this.hitDetectionContext_ = null; 40748 40749 /** 40750 * @private 40751 * @type {import("../../transform.js").Transform} 40752 */ 40753 this.hitDetectionTransform_ = create(); 40754 40755 this.createExecutors_(allInstructions); 40756 } 40757 40758 /** 40759 * @param {CanvasRenderingContext2D} context Context. 40760 * @param {import("../../transform.js").Transform} transform Transform. 40761 */ 40762 clip(context, transform) { 40763 const flatClipCoords = this.getClipCoords(transform); 40764 context.beginPath(); 40765 context.moveTo(flatClipCoords[0], flatClipCoords[1]); 40766 context.lineTo(flatClipCoords[2], flatClipCoords[3]); 40767 context.lineTo(flatClipCoords[4], flatClipCoords[5]); 40768 context.lineTo(flatClipCoords[6], flatClipCoords[7]); 40769 context.clip(); 40770 } 40771 40772 /** 40773 * Create executors and populate them using the provided instructions. 40774 * @private 40775 * @param {!Object<string, !Object<import("../canvas.js").BuilderType, import("../canvas.js").SerializableInstructions>>} allInstructions The serializable instructions 40776 */ 40777 createExecutors_(allInstructions) { 40778 for (const zIndex in allInstructions) { 40779 let executors = this.executorsByZIndex_[zIndex]; 40780 if (executors === undefined) { 40781 executors = {}; 40782 this.executorsByZIndex_[zIndex] = executors; 40783 } 40784 const instructionByZindex = allInstructions[zIndex]; 40785 for (const builderType in instructionByZindex) { 40786 const instructions = instructionByZindex[builderType]; 40787 executors[builderType] = new canvas_Executor( 40788 this.resolution_, 40789 this.pixelRatio_, 40790 this.overlaps_, 40791 instructions 40792 ); 40793 } 40794 } 40795 } 40796 40797 /** 40798 * @param {Array<import("../canvas.js").BuilderType>} executors Executors. 40799 * @return {boolean} Has executors of the provided types. 40800 */ 40801 hasExecutors(executors) { 40802 for (const zIndex in this.executorsByZIndex_) { 40803 const candidates = this.executorsByZIndex_[zIndex]; 40804 for (let i = 0, ii = executors.length; i < ii; ++i) { 40805 if (executors[i] in candidates) { 40806 return true; 40807 } 40808 } 40809 } 40810 return false; 40811 } 40812 40813 /** 40814 * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate. 40815 * @param {number} resolution Resolution. 40816 * @param {number} rotation Rotation. 40817 * @param {number} hitTolerance Hit tolerance in pixels. 40818 * @param {function(import("../../Feature.js").FeatureLike, import("../../geom/SimpleGeometry.js").default, number): T} callback Feature callback. 40819 * @param {Array<import("../../Feature.js").FeatureLike>} declutteredFeatures Decluttered features. 40820 * @return {T|undefined} Callback result. 40821 * @template T 40822 */ 40823 forEachFeatureAtCoordinate( 40824 coordinate, 40825 resolution, 40826 rotation, 40827 hitTolerance, 40828 callback, 40829 declutteredFeatures 40830 ) { 40831 hitTolerance = Math.round(hitTolerance); 40832 const contextSize = hitTolerance * 2 + 1; 40833 const transform = compose( 40834 this.hitDetectionTransform_, 40835 hitTolerance + 0.5, 40836 hitTolerance + 0.5, 40837 1 / resolution, 40838 -1 / resolution, 40839 -rotation, 40840 -coordinate[0], 40841 -coordinate[1] 40842 ); 40843 40844 const newContext = !this.hitDetectionContext_; 40845 if (newContext) { 40846 this.hitDetectionContext_ = createCanvasContext2D( 40847 contextSize, 40848 contextSize 40849 ); 40850 } 40851 const context = this.hitDetectionContext_; 40852 40853 if ( 40854 context.canvas.width !== contextSize || 40855 context.canvas.height !== contextSize 40856 ) { 40857 context.canvas.width = contextSize; 40858 context.canvas.height = contextSize; 40859 } else if (!newContext) { 40860 context.clearRect(0, 0, contextSize, contextSize); 40861 } 40862 40863 /** 40864 * @type {import("../../extent.js").Extent} 40865 */ 40866 let hitExtent; 40867 if (this.renderBuffer_ !== undefined) { 40868 hitExtent = createEmpty(); 40869 extendCoordinate(hitExtent, coordinate); 40870 buffer( 40871 hitExtent, 40872 resolution * (this.renderBuffer_ + hitTolerance), 40873 hitExtent 40874 ); 40875 } 40876 40877 const indexes = getPixelIndexArray(hitTolerance); 40878 40879 let builderType; 40880 40881 /** 40882 * @param {import("../../Feature.js").FeatureLike} feature Feature. 40883 * @param {import("../../geom/SimpleGeometry.js").default} geometry Geometry. 40884 * @return {T|undefined} Callback result. 40885 */ 40886 function featureCallback(feature, geometry) { 40887 const imageData = context.getImageData( 40888 0, 40889 0, 40890 contextSize, 40891 contextSize 40892 ).data; 40893 for (let i = 0, ii = indexes.length; i < ii; i++) { 40894 if (imageData[indexes[i]] > 0) { 40895 if ( 40896 !declutteredFeatures || 40897 (builderType !== 'Image' && builderType !== 'Text') || 40898 declutteredFeatures.includes(feature) 40899 ) { 40900 const idx = (indexes[i] - 3) / 4; 40901 const x = hitTolerance - (idx % contextSize); 40902 const y = hitTolerance - ((idx / contextSize) | 0); 40903 const result = callback(feature, geometry, x * x + y * y); 40904 if (result) { 40905 return result; 40906 } 40907 } 40908 context.clearRect(0, 0, contextSize, contextSize); 40909 break; 40910 } 40911 } 40912 return undefined; 40913 } 40914 40915 /** @type {Array<number>} */ 40916 const zs = Object.keys(this.executorsByZIndex_).map(Number); 40917 zs.sort(numberSafeCompareFunction); 40918 40919 let i, j, executors, executor, result; 40920 for (i = zs.length - 1; i >= 0; --i) { 40921 const zIndexKey = zs[i].toString(); 40922 executors = this.executorsByZIndex_[zIndexKey]; 40923 for (j = ORDER.length - 1; j >= 0; --j) { 40924 builderType = ORDER[j]; 40925 executor = executors[builderType]; 40926 if (executor !== undefined) { 40927 result = executor.executeHitDetection( 40928 context, 40929 transform, 40930 rotation, 40931 featureCallback, 40932 hitExtent 40933 ); 40934 if (result) { 40935 return result; 40936 } 40937 } 40938 } 40939 } 40940 return undefined; 40941 } 40942 40943 /** 40944 * @param {import("../../transform.js").Transform} transform Transform. 40945 * @return {Array<number>|null} Clip coordinates. 40946 */ 40947 getClipCoords(transform) { 40948 const maxExtent = this.maxExtent_; 40949 if (!maxExtent) { 40950 return null; 40951 } 40952 const minX = maxExtent[0]; 40953 const minY = maxExtent[1]; 40954 const maxX = maxExtent[2]; 40955 const maxY = maxExtent[3]; 40956 const flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY]; 40957 transform2D(flatClipCoords, 0, 8, 2, transform, flatClipCoords); 40958 return flatClipCoords; 40959 } 40960 40961 /** 40962 * @return {boolean} Is empty. 40963 */ 40964 isEmpty() { 40965 return obj_isEmpty(this.executorsByZIndex_); 40966 } 40967 40968 /** 40969 * @param {CanvasRenderingContext2D} context Context. 40970 * @param {number} contextScale Scale of the context. 40971 * @param {import("../../transform.js").Transform} transform Transform. 40972 * @param {number} viewRotation View rotation. 40973 * @param {boolean} snapToPixel Snap point symbols and test to integer pixel. 40974 * @param {Array<import("../canvas.js").BuilderType>} [builderTypes] Ordered replay types to replay. 40975 * Default is {@link module:ol/render/replay~ORDER} 40976 * @param {import("rbush").default} [declutterTree] Declutter tree. 40977 */ 40978 execute( 40979 context, 40980 contextScale, 40981 transform, 40982 viewRotation, 40983 snapToPixel, 40984 builderTypes, 40985 declutterTree 40986 ) { 40987 /** @type {Array<number>} */ 40988 const zs = Object.keys(this.executorsByZIndex_).map(Number); 40989 zs.sort(numberSafeCompareFunction); 40990 40991 // setup clipping so that the parts of over-simplified geometries are not 40992 // visible outside the current extent when panning 40993 if (this.maxExtent_) { 40994 context.save(); 40995 this.clip(context, transform); 40996 } 40997 40998 builderTypes = builderTypes ? builderTypes : ORDER; 40999 let i, ii, j, jj, replays, replay; 41000 if (declutterTree) { 41001 zs.reverse(); 41002 } 41003 for (i = 0, ii = zs.length; i < ii; ++i) { 41004 const zIndexKey = zs[i].toString(); 41005 replays = this.executorsByZIndex_[zIndexKey]; 41006 for (j = 0, jj = builderTypes.length; j < jj; ++j) { 41007 const builderType = builderTypes[j]; 41008 replay = replays[builderType]; 41009 if (replay !== undefined) { 41010 replay.execute( 41011 context, 41012 contextScale, 41013 transform, 41014 viewRotation, 41015 snapToPixel, 41016 declutterTree 41017 ); 41018 } 41019 } 41020 } 41021 41022 if (this.maxExtent_) {
41023 context.restore(); 41024 } 41025 } 41026} 41027 41028/** 41029 * This cache is used to store arrays of indexes for calculated pixel circles 41030 * to increase performance. 41031 * It is a static property to allow each Replaygroup to access it. 41032 * @type {Object<number, Array<number>>} 41033 */ 41034const circlePixelIndexArrayCache = {}; 41035 41036/** 41037 * This methods creates an array with indexes of all pixels within a circle, 41038 * ordered by how close they are to the center. 41039 * A cache is used to increase performance. 41040 * @param {number} radius Radius. 41041 * @return {Array<number>} An array with indexes within a circle. 41042 */ 41043function getPixelIndexArray(radius) { 41044 if (circlePixelIndexArrayCache[radius] !== undefined) { 41045 return circlePixelIndexArrayCache[radius]; 41046 } 41047 41048 const size = radius * 2 + 1; 41049 const maxDistanceSq = radius * radius; 41050 const distances = new Array(maxDistanceSq + 1); 41051 for (let i = 0; i <= radius; ++i) { 41052 for (let j = 0; j <= radius; ++j) { 41053 const distanceSq = i * i + j * j; 41054 if (distanceSq > maxDistanceSq) { 41055 break; 41056 } 41057 let distance = distances[distanceSq]; 41058 if (!distance) { 41059 distance = []; 41060 distances[distanceSq] = distance; 41061 } 41062 distance.push(((radius + i) * size + (radius + j)) * 4 + 3); 41063 if (i > 0) { 41064 distance.push(((radius - i) * size + (radius + j)) * 4 + 3); 41065 } 41066 if (j > 0) { 41067 distance.push(((radius + i) * size + (radius - j)) * 4 + 3); 41068 if (i > 0) { 41069 distance.push(((radius - i) * size + (radius - j)) * 4 + 3); 41070 } 41071 } 41072 } 41073 } 41074 41075 const pixelIndex = []; 41076 for (let i = 0, ii = distances.length; i < ii; ++i) { 41077 if (distances[i]) { 41078 pixelIndex.push(...distances[i]); 41079 } 41080 } 41081 41082 circlePixelIndexArrayCache[radius] = pixelIndex; 41083 return pixelIndex; 41084} 41085 41086/* harmony default export */ const canvas_ExecutorGroup = (ExecutorGroup); 41087 41088;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/Immediate.js 41089/** 41090 * @module ol/render/canvas/Immediate 41091 */ 41092// FIXME test, especially polygons with holes and multipolygons 41093// FIXME need to handle large thick features (where pixel size matters) 41094// FIXME add offset and end to ol/geom/flat/transform~transform2D? 41095 41096 41097 41098 41099 41100 41101 41102 41103 41104 41105/** 41106 * @classdesc 41107 * A concrete subclass of {@link module:ol/render/VectorContext~VectorContext} that implements 41108 * direct rendering of features and geometries to an HTML5 Canvas context. 41109 * Instances of this class are created internally by the library and 41110 * provided to application code as vectorContext member of the 41111 * {@link module:ol/render/Event~RenderEvent} object associated with postcompose, precompose and 41112 * render events emitted by layers and maps. 41113 */ 41114class CanvasImmediateRenderer extends render_VectorContext { 41115 /** 41116 * @param {CanvasRenderingContext2D} context Context. 41117 * @param {number} pixelRatio Pixel ratio. 41118 * @param {import("../../extent.js").Extent} extent Extent. 41119 * @param {import("../../transform.js").Transform} transform Transform. 41120 * @param {number} viewRotation View rotation. 41121 * @param {number} [squaredTolerance] Optional squared tolerance for simplification. 41122 * @param {import("../../proj.js").TransformFunction} [userTransform] Transform from user to view projection. 41123 */ 41124 constructor( 41125 context, 41126 pixelRatio, 41127 extent, 41128 transform, 41129 viewRotation, 41130 squaredTolerance, 41131 userTransform 41132 ) { 41133 super(); 41134 41135 /** 41136 * @private 41137 * @type {CanvasRenderingContext2D} 41138 */ 41139 this.context_ = context; 41140 41141 /** 41142 * @private 41143 * @type {number} 41144 */ 41145 this.pixelRatio_ = pixelRatio; 41146 41147 /** 41148 * @private 41149 * @type {import("../../extent.js").Extent} 41150 */ 41151 this.extent_ = extent; 41152 41153 /** 41154 * @private 41155 * @type {import("../../transform.js").Transform} 41156 */ 41157 this.transform_ = transform; 41158 41159 /** 41160 * @private 41161 * @type {number} 41162 */ 41163 this.viewRotation_ = viewRotation; 41164 41165 /** 41166 * @private 41167 * @type {number} 41168 */ 41169 this.squaredTolerance_ = squaredTolerance; 41170 41171 /** 41172 * @private 41173 * @type {import("../../proj.js").TransformFunction} 41174 */ 41175 this.userTransform_ = userTransform; 41176 41177 /** 41178 * @private 41179 * @type {?import("../canvas.js").FillState} 41180 */ 41181 this.contextFillState_ = null; 41182 41183 /** 41184 * @private 41185 * @type {?import("../canvas.js").StrokeState} 41186 */ 41187 this.contextStrokeState_ = null; 41188 41189 /** 41190 * @private 41191 * @type {?import("../canvas.js").TextState} 41192 */ 41193 this.contextTextState_ = null; 41194 41195 /** 41196 * @private 41197 * @type {?import("../canvas.js").FillState} 41198 */ 41199 this.fillState_ = null; 41200 41201 /** 41202 * @private 41203 * @type {?import("../canvas.js").StrokeState} 41204 */ 41205 this.strokeState_ = null; 41206 41207 /** 41208 * @private 41209 * @type {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} 41210 */ 41211 this.image_ = null; 41212 41213 /** 41214 * @private 41215 * @type {number} 41216 */ 41217 this.imageAnchorX_ = 0; 41218 41219 /** 41220 * @private 41221 * @type {number} 41222 */ 41223 this.imageAnchorY_ = 0; 41224 41225 /** 41226 * @private 41227 * @type {number} 41228 */ 41229 this.imageHeight_ = 0; 41230 41231 /** 41232 * @private 41233 * @type {number} 41234 */ 41235 this.imageOpacity_ = 0; 41236 41237 /** 41238 * @private 41239 * @type {number} 41240 */ 41241 this.imageOriginX_ = 0; 41242 41243 /** 41244 * @private 41245 * @type {number} 41246 */ 41247 this.imageOriginY_ = 0; 41248 41249 /** 41250 * @private 41251 * @type {boolean} 41252 */ 41253 this.imageRotateWithView_ = false;
41254 41255 /** 41256 * @private 41257 * @type {number} 41258 */ 41259 this.imageRotation_ = 0; 41260 41261 /** 41262 * @private 41263 * @type {import("../../size.js").Size} 41264 */ 41265 this.imageScale_ = [0, 0]; 41266 41267 /** 41268 * @private 41269 * @type {number} 41270 */ 41271 this.imageWidth_ = 0; 41272 41273 /** 41274 * @private 41275 * @type {string} 41276 */ 41277 this.text_ = ''; 41278 41279 /** 41280 * @private 41281 * @type {number} 41282 */ 41283 this.textOffsetX_ = 0; 41284 41285 /** 41286 * @private 41287 * @type {number} 41288 */ 41289 this.textOffsetY_ = 0; 41290 41291 /** 41292 * @private 41293 * @type {boolean} 41294 */ 41295 this.textRotateWithView_ = false; 41296 41297 /** 41298 * @private 41299 * @type {number} 41300 */ 41301 this.textRotation_ = 0; 41302 41303 /** 41304 * @private 41305 * @type {import("../../size.js").Size} 41306 */ 41307 this.textScale_ = [0, 0]; 41308 41309 /** 41310 * @private 41311 * @type {?import("../canvas.js").FillState} 41312 */ 41313 this.textFillState_ = null; 41314 41315 /** 41316 * @private 41317 * @type {?import("../canvas.js").StrokeState} 41318 */ 41319 this.textStrokeState_ = null; 41320 41321 /** 41322 * @private 41323 * @type {?import("../canvas.js").TextState} 41324 */ 41325 this.textState_ = null; 41326 41327 /** 41328 * @private 41329 * @type {Array<number>} 41330 */ 41331 this.pixelCoordinates_ = []; 41332 41333 /** 41334 * @private 41335 * @type {import("../../transform.js").Transform} 41336 */ 41337 this.tmpLocalTransform_ = create(); 41338 } 41339 41340 /** 41341 * @param {Array<number>} flatCoordinates Flat coordinates. 41342 * @param {number} offset Offset. 41343 * @param {number} end End. 41344 * @param {number} stride Stride. 41345 * @private 41346 */ 41347 drawImages_(flatCoordinates, offset, end, stride) { 41348 if (!this.image_) { 41349 return; 41350 } 41351 const pixelCoordinates = transform2D( 41352 flatCoordinates, 41353 offset, 41354 end, 41355 stride, 41356 this.transform_, 41357 this.pixelCoordinates_ 41358 ); 41359 const context = this.context_; 41360 const localTransform = this.tmpLocalTransform_; 41361 const alpha = context.globalAlpha; 41362 if (this.imageOpacity_ != 1) { 41363 context.globalAlpha = alpha * this.imageOpacity_; 41364 } 41365 let rotation = this.imageRotation_; 41366 if (this.imageRotateWithView_) { 41367 rotation += this.viewRotation_; 41368 } 41369 for (let i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { 41370 const x = pixelCoordinates[i] - this.imageAnchorX_; 41371 const y = pixelCoordinates[i + 1] - this.imageAnchorY_; 41372 if ( 41373 rotation !== 0 || 41374 this.imageScale_[0] != 1 || 41375 this.imageScale_[1] != 1 41376 ) { 41377 const centerX = x + this.imageAnchorX_; 41378 const centerY = y + this.imageAnchorY_; 41379 compose( 41380 localTransform, 41381 centerX, 41382 centerY, 41383 1, 41384 1, 41385 rotation, 41386 -centerX, 41387 -centerY 41388 ); 41389 context.setTransform.apply(context, localTransform); 41390 context.translate(centerX, centerY); 41391 context.scale(this.imageScale_[0], this.imageScale_[1]); 41392 context.drawImage( 41393 this.image_, 41394 this.imageOriginX_, 41395 this.imageOriginY_, 41396 this.imageWidth_, 41397 this.imageHeight_, 41398 -this.imageAnchorX_, 41399 -this.imageAnchorY_, 41400 this.imageWidth_, 41401 this.imageHeight_ 41402 ); 41403 context.setTransform(1, 0, 0, 1, 0, 0); 41404 } else { 41405 context.drawImage( 41406 this.image_, 41407 this.imageOriginX_, 41408 this.imageOriginY_, 41409 this.imageWidth_, 41410 this.imageHeight_, 41411 x, 41412 y, 41413 this.imageWidth_, 41414 this.imageHeight_ 41415 ); 41416 } 41417 } 41418 if (this.imageOpacity_ != 1) { 41419 context.globalAlpha = alpha; 41420 } 41421 } 41422 41423 /** 41424 * @param {Array<number>} flatCoordinates Flat coordinates. 41425 * @param {number} offset Offset. 41426 * @param {number} end End. 41427 * @param {number} stride Stride. 41428 * @private 41429 */ 41430 drawText_(flatCoordinates, offset, end, stride) { 41431 if (!this.textState_ || this.text_ === '') { 41432 return; 41433 } 41434 if (this.textFillState_) { 41435 this.setContextFillState_(this.textFillState_); 41436 } 41437 if (this.textStrokeState_) { 41438 this.setContextStrokeState_(this.textStrokeState_); 41439 } 41440 this.setContextTextState_(this.textState_); 41441 const pixelCoordinates = transform2D( 41442 flatCoordinates, 41443 offset, 41444 end,
41445 stride, 41446 this.transform_, 41447 this.pixelCoordinates_ 41448 ); 41449 const context = this.context_; 41450 let rotation = this.textRotation_; 41451 if (this.textRotateWithView_) { 41452 rotation += this.viewRotation_; 41453 } 41454 for (; offset < end; offset += stride) { 41455 const x = pixelCoordinates[offset] + this.textOffsetX_; 41456 const y = pixelCoordinates[offset + 1] + this.textOffsetY_; 41457 if ( 41458 rotation !== 0 || 41459 this.textScale_[0] != 1 || 41460 this.textScale_[1] != 1 41461 ) { 41462 context.translate(x - this.textOffsetX_, y - this.textOffsetY_); 41463 context.rotate(rotation); 41464 context.translate(this.textOffsetX_, this.textOffsetY_); 41465 context.scale(this.textScale_[0], this.textScale_[1]); 41466 if (this.textStrokeState_) { 41467 context.strokeText(this.text_, 0, 0); 41468 } 41469 if (this.textFillState_) { 41470 context.fillText(this.text_, 0, 0); 41471 } 41472 context.setTransform(1, 0, 0, 1, 0, 0); 41473 } else { 41474 if (this.textStrokeState_) { 41475 context.strokeText(this.text_, x, y); 41476 } 41477 if (this.textFillState_) { 41478 context.fillText(this.text_, x, y); 41479 } 41480 } 41481 } 41482 } 41483 41484 /** 41485 * @param {Array<number>} flatCoordinates Flat coordinates. 41486 * @param {number} offset Offset. 41487 * @param {number} end End. 41488 * @param {number} stride Stride. 41489 * @param {boolean} close Close. 41490 * @private 41491 * @return {number} end End. 41492 */ 41493 moveToLineTo_(flatCoordinates, offset, end, stride, close) { 41494 const context = this.context_; 41495 const pixelCoordinates = transform2D( 41496 flatCoordinates, 41497 offset, 41498 end, 41499 stride, 41500 this.transform_, 41501 this.pixelCoordinates_ 41502 ); 41503 context.moveTo(pixelCoordinates[0], pixelCoordinates[1]); 41504 let length = pixelCoordinates.length; 41505 if (close) { 41506 length -= 2; 41507 } 41508 for (let i = 2; i < length; i += 2) { 41509 context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]); 41510 } 41511 if (close) { 41512 context.closePath(); 41513 } 41514 return end; 41515 } 41516 41517 /** 41518 * @param {Array<number>} flatCoordinates Flat coordinates. 41519 * @param {number} offset Offset. 41520 * @param {Array<number>} ends Ends. 41521 * @param {number} stride Stride. 41522 * @private 41523 * @return {number} End. 41524 */ 41525 drawRings_(flatCoordinates, offset, ends, stride) { 41526 for (let i = 0, ii = ends.length; i < ii; ++i) { 41527 offset = this.moveToLineTo_( 41528 flatCoordinates, 41529 offset, 41530 ends[i], 41531 stride, 41532 true 41533 ); 41534 } 41535 return offset; 41536 } 41537 41538 /** 41539 * Render a circle geometry into the canvas. Rendering is immediate and uses 41540 * the current fill and stroke styles. 41541 * 41542 * @param {import("../../geom/Circle.js").default} geometry Circle geometry. 41543 * @api 41544 */ 41545 drawCircle(geometry) { 41546 if (!intersects(this.extent_, geometry.getExtent())) { 41547 return; 41548 } 41549 if (this.fillState_ || this.strokeState_) { 41550 if (this.fillState_) { 41551 this.setContextFillState_(this.fillState_); 41552 } 41553 if (this.strokeState_) { 41554 this.setContextStrokeState_(this.strokeState_); 41555 } 41556 const pixelCoordinates = transformGeom2D( 41557 geometry, 41558 this.transform_, 41559 this.pixelCoordinates_ 41560 ); 41561 const dx = pixelCoordinates[2] - pixelCoordinates[0]; 41562 const dy = pixelCoordinates[3] - pixelCoordinates[1]; 41563 const radius = Math.sqrt(dx * dx + dy * dy); 41564 const context = this.context_; 41565 context.beginPath(); 41566 context.arc( 41567 pixelCoordinates[0], 41568 pixelCoordinates[1], 41569 radius, 41570 0, 41571 2 * Math.PI 41572 ); 41573 if (this.fillState_) { 41574 context.fill(); 41575 } 41576 if (this.strokeState_) { 41577 context.stroke(); 41578 } 41579 } 41580 if (this.text_ !== '') { 41581 this.drawText_(geometry.getCenter(), 0, 2, 2); 41582 } 41583 } 41584 41585 /** 41586 * Set the rendering style. Note that since this is an immediate rendering API, 41587 * any `zIndex` on the provided style will be ignored. 41588 * 41589 * @param {import("../../style/Style.js").default} style The rendering style. 41590 * @api 41591 */ 41592 setStyle(style) {
41593 this.setFillStrokeStyle(style.getFill(), style.getStroke()); 41594 this.setImageStyle(style.getImage()); 41595 this.setTextStyle(style.getText()); 41596 } 41597 41598 /** 41599 * @param {import("../../transform.js").Transform} transform Transform. 41600 */ 41601 setTransform(transform) { 41602 this.transform_ = transform; 41603 } 41604 41605 /** 41606 * Render a geometry into the canvas. Call 41607 * {@link module:ol/render/canvas/Immediate~CanvasImmediateRenderer#setStyle renderer.setStyle()} first to set the rendering style. 41608 * 41609 * @param {import("../../geom/Geometry.js").default|import("../Feature.js").default} geometry The geometry to render. 41610 * @api 41611 */ 41612 drawGeometry(geometry) { 41613 const type = geometry.getType(); 41614 switch (type) { 41615 case 'Point': 41616 this.drawPoint( 41617 /** @type {import("../../geom/Point.js").default} */ (geometry) 41618 ); 41619 break; 41620 case 'LineString': 41621 this.drawLineString( 41622 /** @type {import("../../geom/LineString.js").default} */ (geometry) 41623 ); 41624 break; 41625 case 'Polygon': 41626 this.drawPolygon( 41627 /** @type {import("../../geom/Polygon.js").default} */ (geometry) 41628 ); 41629 break; 41630 case 'MultiPoint': 41631 this.drawMultiPoint( 41632 /** @type {import("../../geom/MultiPoint.js").default} */ (geometry) 41633 ); 41634 break; 41635 case 'MultiLineString': 41636 this.drawMultiLineString( 41637 /** @type {import("../../geom/MultiLineString.js").default} */ ( 41638 geometry 41639 ) 41640 ); 41641 break; 41642 case 'MultiPolygon': 41643 this.drawMultiPolygon( 41644 /** @type {import("../../geom/MultiPolygon.js").default} */ (geometry) 41645 ); 41646 break; 41647 case 'GeometryCollection': 41648 this.drawGeometryCollection( 41649 /** @type {import("../../geom/GeometryCollection.js").default} */ ( 41650 geometry 41651 ) 41652 ); 41653 break; 41654 case 'Circle': 41655 this.drawCircle( 41656 /** @type {import("../../geom/Circle.js").default} */ (geometry) 41657 ); 41658 break; 41659 default: 41660 } 41661 } 41662 41663 /** 41664 * Render a feature into the canvas. Note that any `zIndex` on the provided 41665 * style will be ignored - features are rendered immediately in the order that 41666 * this method is called. If you need `zIndex` support, you should be using an 41667 * {@link module:ol/layer/Vector~VectorLayer} instead. 41668 * 41669 * @param {import("../../Feature.js").default} feature Feature. 41670 * @param {import("../../style/Style.js").default} style Style. 41671 * @api 41672 */ 41673 drawFeature(feature, style) { 41674 const geometry = style.getGeometryFunction()(feature); 41675 if (!geometry || !intersects(this.extent_, geometry.getExtent())) { 41676 return; 41677 } 41678 this.setStyle(style); 41679 this.drawGeometry(geometry); 41680 } 41681 41682 /** 41683 * Render a GeometryCollection to the canvas. Rendering is immediate and 41684 * uses the current styles appropriate for each geometry in the collection. 41685 * 41686 * @param {import("../../geom/GeometryCollection.js").default} geometry Geometry collection. 41687 */ 41688 drawGeometryCollection(geometry) { 41689 const geometries = geometry.getGeometriesArray(); 41690 for (let i = 0, ii = geometries.length; i < ii; ++i) { 41691 this.drawGeometry(geometries[i]); 41692 } 41693 } 41694 41695 /** 41696 * Render a Point geometry into the canvas. Rendering is immediate and uses 41697 * the current style. 41698 * 41699 * @param {import("../../geom/Point.js").default|import("../Feature.js").default} geometry Point geometry. 41700 */ 41701 drawPoint(geometry) { 41702 if (this.squaredTolerance_) { 41703 geometry = /** @type {import("../../geom/Point.js").default} */ ( 41704 geometry.simplifyTransformed( 41705 this.squaredTolerance_, 41706 this.userTransform_ 41707 ) 41708 ); 41709 } 41710 const flatCoordinates = geometry.getFlatCoordinates(); 41711 const stride = geometry.getStride(); 41712 if (this.image_) { 41713 this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); 41714 } 41715 if (this.text_ !== '') { 41716 this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); 41717 } 41718 } 41719 41720 /** 41721 * Render a MultiPoint geometry into the canvas. Rendering is immediate and 41722 * uses the current style. 41723 * 41724 * @param {import("../../geom/MultiPoint.js").default|import("../Feature.js").default} geometry MultiPoint geometry. 41725 */ 41726 drawMultiPoint(geometry) { 41727 if (this.squaredTolerance_) { 41728 geometry = /** @type {import("../../geom/MultiPoint.js").default} */ ( 41729 geometry.simplifyTransformed( 41730 this.squaredTolerance_, 41731 this.userTransform_ 41732 ) 41733 ); 41734 } 41735 const flatCoordinates = geometry.getFlatCoordinates(); 41736 const stride = geometry.getStride(); 41737 if (this.image_) { 41738 this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride); 41739 } 41740 if (this.text_ !== '') { 41741 this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride); 41742 } 41743 } 41744 41745 /** 41746 * Render a LineString into the canvas. Rendering is immediate and uses 41747 * the current style. 41748 * 41749 * @param {import("../../geom/LineString.js").default|import("../Feature.js").default} geometry LineString geometry. 41750 */ 41751 drawLineString(geometry) { 41752 if (this.squaredTolerance_) { 41753 geometry = /** @type {import("../../geom/LineString.js").default} */ ( 41754 geometry.simplifyTransformed( 41755 this.squaredTolerance_, 41756 this.userTransform_ 41757 ) 41758 ); 41759 } 41760 if (!intersects(this.extent_, geometry.getExtent())) { 41761 return; 41762 } 41763 if (this.strokeState_) { 41764 this.setContextStrokeState_(this.strokeState_); 41765 const context = this.context_; 41766 const flatCoordinates = geometry.getFlatCoordinates(); 41767 context.beginPath(); 41768 this.moveToLineTo_( 41769 flatCoordinates, 41770 0, 41771 flatCoordinates.length, 41772 geometry.getStride(), 41773 false 41774 ); 41775 context.stroke(); 41776 } 41777 if (this.text_ !== '') { 41778 const flatMidpoint = geometry.getFlatMidpoint(); 41779 this.drawText_(flatMidpoint, 0, 2, 2); 41780 } 41781 } 41782 41783 /** 41784 * Render a MultiLineString geometry into the canvas. Rendering is immediate 41785 * and uses the current style. 41786 * 41787 * @param {import("../../geom/MultiLineString.js").default|import("../Feature.js").default} geometry MultiLineString geometry. 41788 */ 41789 drawMultiLineString(geometry) { 41790 if (this.squaredTolerance_) { 41791 geometry = 41792 /** @type {import("../../geom/MultiLineString.js").default} */ ( 41793 geometry.simplifyTransformed( 41794 this.squaredTolerance_, 41795 this.userTransform_ 41796 ) 41797 ); 41798 } 41799 const geometryExtent = geometry.getExtent(); 41800 if (!intersects(this.extent_, geometryExtent)) { 41801 return; 41802 } 41803 if (this.strokeState_) { 41804 this.setContextStrokeState_(this.strokeState_); 41805 const context = this.context_; 41806 const flatCoordinates = geometry.getFlatCoordinates(); 41807 let offset = 0; 41808 const ends = /** @type {Array<number>} */ (geometry.getEnds()); 41809 const stride = geometry.getStride(); 41810 context.beginPath(); 41811 for (let i = 0, ii = ends.length; i < ii; ++i) { 41812 offset = this.moveToLineTo_( 41813 flatCoordinates, 41814 offset, 41815 ends[i],
41816 stride, 41817 false 41818 ); 41819 } 41820 context.stroke(); 41821 } 41822 if (this.text_ !== '') { 41823 const flatMidpoints = geometry.getFlatMidpoints(); 41824 this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2); 41825 } 41826 } 41827 41828 /** 41829 * Render a Polygon geometry into the canvas. Rendering is immediate and uses 41830 * the current style. 41831 * 41832 * @param {import("../../geom/Polygon.js").default|import("../Feature.js").default} geometry Polygon geometry. 41833 */ 41834 drawPolygon(geometry) { 41835 if (this.squaredTolerance_) { 41836 geometry = /** @type {import("../../geom/Polygon.js").default} */ ( 41837 geometry.simplifyTransformed( 41838 this.squaredTolerance_, 41839 this.userTransform_ 41840 ) 41841 ); 41842 } 41843 if (!intersects(this.extent_, geometry.getExtent())) { 41844 return; 41845 } 41846 if (this.strokeState_ || this.fillState_) { 41847 if (this.fillState_) { 41848 this.setContextFillState_(this.fillState_); 41849 } 41850 if (this.strokeState_) { 41851 this.setContextStrokeState_(this.strokeState_); 41852 } 41853 const context = this.context_; 41854 context.beginPath(); 41855 this.drawRings_( 41856 geometry.getOrientedFlatCoordinates(), 41857 0, 41858 /** @type {Array<number>} */ (geometry.getEnds()), 41859 geometry.getStride() 41860 ); 41861 if (this.fillState_) { 41862 context.fill(); 41863 } 41864 if (this.strokeState_) { 41865 context.stroke(); 41866 } 41867 } 41868 if (this.text_ !== '') { 41869 const flatInteriorPoint = geometry.getFlatInteriorPoint(); 41870 this.drawText_(flatInteriorPoint, 0, 2, 2); 41871 } 41872 } 41873 41874 /** 41875 * Render MultiPolygon geometry into the canvas. Rendering is immediate and 41876 * uses the current style. 41877 * @param {import("../../geom/MultiPolygon.js").default} geometry MultiPolygon geometry. 41878 */ 41879 drawMultiPolygon(geometry) { 41880 if (this.squaredTolerance_) { 41881 geometry = /** @type {import("../../geom/MultiPolygon.js").default} */ ( 41882 geometry.simplifyTransformed( 41883 this.squaredTolerance_, 41884 this.userTransform_ 41885 ) 41886 ); 41887 } 41888 if (!intersects(this.extent_, geometry.getExtent())) { 41889 return; 41890 } 41891 if (this.strokeState_ || this.fillState_) { 41892 if (this.fillState_) { 41893 this.setContextFillState_(this.fillState_); 41894 } 41895 if (this.strokeState_) { 41896 this.setContextStrokeState_(this.strokeState_); 41897 } 41898 const context = this.context_; 41899 const flatCoordinates = geometry.getOrientedFlatCoordinates(); 41900 let offset = 0; 41901 const endss = geometry.getEndss(); 41902 const stride = geometry.getStride(); 41903 context.beginPath(); 41904 for (let i = 0, ii = endss.length; i < ii; ++i) { 41905 const ends = endss[i]; 41906 offset = this.drawRings_(flatCoordinates, offset, ends, stride); 41907 } 41908 if (this.fillState_) { 41909 context.fill(); 41910 } 41911 if (this.strokeState_) { 41912 context.stroke(); 41913 } 41914 } 41915 if (this.text_ !== '') { 41916 const flatInteriorPoints = geometry.getFlatInteriorPoints(); 41917 this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2); 41918 } 41919 } 41920 41921 /** 41922 * @param {import("../canvas.js").FillState} fillState Fill state. 41923 * @private 41924 */ 41925 setContextFillState_(fillState) { 41926 const context = this.context_; 41927 const contextFillState = this.contextFillState_; 41928 if (!contextFillState) { 41929 context.fillStyle = fillState.fillStyle; 41930 this.contextFillState_ = { 41931 fillStyle: fillState.fillStyle, 41932 }; 41933 } else { 41934 if (contextFillState.fillStyle != fillState.fillStyle) { 41935 contextFillState.fillStyle = fillState.fillStyle; 41936 context.fillStyle = fillState.fillStyle; 41937 } 41938 } 41939 } 41940 41941 /** 41942 * @param {import("../canvas.js").StrokeState} strokeState Stroke state. 41943 * @private 41944 */ 41945 setContextStrokeState_(strokeState) { 41946 const context = this.context_; 41947 const contextStrokeState = this.contextStrokeState_; 41948 if (!contextStrokeState) { 41949 context.lineCap = strokeState.lineCap; 41950 context.setLineDash(strokeState.lineDash); 41951 context.lineDashOffset = strokeState.lineDashOffset; 41952 context.lineJoin = strokeState.lineJoin; 41953 context.lineWidth = strokeState.lineWidth; 41954 context.miterLimit = strokeState.miterLimit; 41955 context.strokeStyle = strokeState.strokeStyle; 41956 this.contextStrokeState_ = { 41957 lineCap: strokeState.lineCap, 41958 lineDash: strokeState.lineDash, 41959 lineDashOffset: strokeState.lineDashOffset, 41960 lineJoin: strokeState.lineJoin, 41961 lineWidth: strokeState.lineWidth, 41962 miterLimit: strokeState.miterLimit, 41963 strokeStyle: strokeState.strokeStyle, 41964 }; 41965 } else { 41966 if (contextStrokeState.lineCap != strokeState.lineCap) { 41967 contextStrokeState.lineCap = strokeState.lineCap; 41968 context.lineCap = strokeState.lineCap; 41969 } 41970 if (!equals(contextStrokeState.lineDash, strokeState.lineDash)) { 41971 context.setLineDash( 41972 (contextStrokeState.lineDash = strokeState.lineDash) 41973 ); 41974 } 41975 if (contextStrokeState.lineDashOffset != strokeState.lineDashOffset) { 41976 contextStrokeState.lineDashOffset = strokeState.lineDashOffset; 41977 context.lineDashOffset = strokeState.lineDashOffset; 41978 } 41979 if (contextStrokeState.lineJoin != strokeState.lineJoin) { 41980 contextStrokeState.lineJoin = strokeState.lineJoin; 41981 context.lineJoin = strokeState.lineJoin; 41982 } 41983 if (contextStrokeState.lineWidth != strokeState.lineWidth) { 41984 contextStrokeState.lineWidth = strokeState.lineWidth; 41985 context.lineWidth = strokeState.lineWidth; 41986 } 41987 if (contextStrokeState.miterLimit != strokeState.miterLimit) { 41988 contextStrokeState.miterLimit = strokeState.miterLimit; 41989 context.miterLimit = strokeState.miterLimit; 41990 } 41991 if (contextStrokeState.strokeStyle != strokeState.strokeStyle) { 41992 contextStrokeState.strokeStyle = strokeState.strokeStyle; 41993 context.strokeStyle = strokeState.strokeStyle; 41994 } 41995 } 41996 } 41997 41998 /** 41999 * @param {import("../canvas.js").TextState} textState Text state. 42000 * @private 42001 */ 42002 setContextTextState_(textState) { 42003 const context = this.context_; 42004 const contextTextState = this.contextTextState_; 42005 const textAlign = textState.textAlign 42006 ? textState.textAlign 42007 : defaultTextAlign; 42008 if (!contextTextState) { 42009 context.font = textState.font; 42010 context.textAlign = textAlign; 42011 context.textBaseline = textState.textBaseline; 42012 this.contextTextState_ = { 42013 font: textState.font, 42014 textAlign: textAlign, 42015 textBaseline: textState.textBaseline, 42016 }; 42017 } else { 42018 if (contextTextState.font != textState.font) { 42019 contextTextState.font = textState.font; 42020 context.font = textState.font; 42021 } 42022 if (contextTextState.textAlign != textAlign) { 42023 contextTextState.textAlign = textAlign; 42024 context.textAlign = textAlign; 42025 } 42026 if (contextTextState.textBaseline != textState.textBaseline) { 42027 contextTextState.textBaseline = textState.textBaseline; 42028 context.textBaseline = textState.textBaseline; 42029 } 42030 } 42031 } 42032 42033 /** 42034 * Set the fill and stroke style for subsequent draw operations. To clear 42035 * either fill or stroke styles, pass null for the appropriate parameter. 42036 * 42037 * @param {import("../../style/Fill.js").default} fillStyle Fill style. 42038 * @param {import("../../style/Stroke.js").default} strokeStyle Stroke style. 42039 */ 42040 setFillStrokeStyle(fillStyle, strokeStyle) { 42041 if (!fillStyle) { 42042 this.fillState_ = null; 42043 } else { 42044 const fillStyleColor = fillStyle.getColor(); 42045 this.fillState_ = { 42046 fillStyle: asColorLike( 42047 fillStyleColor ? fillStyleColor : defaultFillStyle 42048 ), 42049 }; 42050 } 42051 if (!strokeStyle) { 42052 this.strokeState_ = null; 42053 } else { 42054 const strokeStyleColor = strokeStyle.getColor(); 42055 const strokeStyleLineCap = strokeStyle.getLineCap(); 42056 const strokeStyleLineDash = strokeStyle.getLineDash(); 42057 const strokeStyleLineDashOffset = strokeStyle.getLineDashOffset(); 42058 const strokeStyleLineJoin = strokeStyle.getLineJoin();
42059 const strokeStyleWidth = strokeStyle.getWidth(); 42060 const strokeStyleMiterLimit = strokeStyle.getMiterLimit(); 42061 const lineDash = strokeStyleLineDash 42062 ? strokeStyleLineDash 42063 : defaultLineDash; 42064 this.strokeState_ = { 42065 lineCap: 42066 strokeStyleLineCap !== undefined 42067 ? strokeStyleLineCap 42068 : defaultLineCap, 42069 lineDash: 42070 this.pixelRatio_ === 1 42071 ? lineDash 42072 : lineDash.map((n) => n * this.pixelRatio_), 42073 lineDashOffset: 42074 (strokeStyleLineDashOffset 42075 ? strokeStyleLineDashOffset 42076 : defaultLineDashOffset) * this.pixelRatio_, 42077 lineJoin: 42078 strokeStyleLineJoin !== undefined 42079 ? strokeStyleLineJoin 42080 : defaultLineJoin, 42081 lineWidth: 42082 (strokeStyleWidth !== undefined 42083 ? strokeStyleWidth 42084 : defaultLineWidth) * this.pixelRatio_, 42085 miterLimit: 42086 strokeStyleMiterLimit !== undefined 42087 ? strokeStyleMiterLimit 42088 : defaultMiterLimit, 42089 strokeStyle: asColorLike( 42090 strokeStyleColor ? strokeStyleColor : defaultStrokeStyle 42091 ), 42092 }; 42093 } 42094 } 42095 42096 /** 42097 * Set the image style for subsequent draw operations. Pass null to remove 42098 * the image style. 42099 * 42100 * @param {import("../../style/Image.js").default} imageStyle Image style. 42101 */ 42102 setImageStyle(imageStyle) { 42103 let imageSize; 42104 if (!imageStyle || !(imageSize = imageStyle.getSize())) { 42105 this.image_ = null; 42106 return; 42107 } 42108 const imagePixelRatio = imageStyle.getPixelRatio(this.pixelRatio_); 42109 const imageAnchor = imageStyle.getAnchor(); 42110 const imageOrigin = imageStyle.getOrigin(); 42111 this.image_ = imageStyle.getImage(this.pixelRatio_); 42112 this.imageAnchorX_ = imageAnchor[0] * imagePixelRatio; 42113 this.imageAnchorY_ = imageAnchor[1] * imagePixelRatio; 42114 this.imageHeight_ = imageSize[1] * imagePixelRatio; 42115 this.imageOpacity_ = imageStyle.getOpacity(); 42116 this.imageOriginX_ = imageOrigin[0]; 42117 this.imageOriginY_ = imageOrigin[1]; 42118 this.imageRotateWithView_ = imageStyle.getRotateWithView(); 42119 this.imageRotation_ = imageStyle.getRotation(); 42120 const imageScale = imageStyle.getScaleArray(); 42121 this.imageScale_ = [ 42122 (imageScale[0] * this.pixelRatio_) / imagePixelRatio, 42123 (imageScale[1] * this.pixelRatio_) / imagePixelRatio, 42124 ]; 42125 this.imageWidth_ = imageSize[0] * imagePixelRatio; 42126 } 42127 42128 /** 42129 * Set the text style for subsequent draw operations. Pass null to 42130 * remove the text style. 42131 * 42132 * @param {import("../../style/Text.js").default} textStyle Text style. 42133 */ 42134 setTextStyle(textStyle) { 42135 if (!textStyle) { 42136 this.text_ = ''; 42137 } else { 42138 const textFillStyle = textStyle.getFill(); 42139 if (!textFillStyle) { 42140 this.textFillState_ = null; 42141 } else { 42142 const textFillStyleColor = textFillStyle.getColor(); 42143 this.textFillState_ = { 42144 fillStyle: asColorLike( 42145 textFillStyleColor ? textFillStyleColor : defaultFillStyle 42146 ), 42147 }; 42148 } 42149 const textStrokeStyle = textStyle.getStroke(); 42150 if (!textStrokeStyle) { 42151 this.textStrokeState_ = null; 42152 } else { 42153 const textStrokeStyleColor = textStrokeStyle.getColor(); 42154 const textStrokeStyleLineCap = textStrokeStyle.getLineCap(); 42155 const textStrokeStyleLineDash = textStrokeStyle.getLineDash(); 42156 const textStrokeStyleLineDashOffset = 42157 textStrokeStyle.getLineDashOffset(); 42158 const textStrokeStyleLineJoin = textStrokeStyle.getLineJoin(); 42159 const textStrokeStyleWidth = textStrokeStyle.getWidth(); 42160 const textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit(); 42161 this.textStrokeState_ = { 42162 lineCap: 42163 textStrokeStyleLineCap !== undefined 42164 ? textStrokeStyleLineCap 42165 : defaultLineCap, 42166 lineDash: textStrokeStyleLineDash 42167 ? textStrokeStyleLineDash 42168 : defaultLineDash, 42169 lineDashOffset: textStrokeStyleLineDashOffset 42170 ? textStrokeStyleLineDashOffset 42171 : defaultLineDashOffset, 42172 lineJoin: 42173 textStrokeStyleLineJoin !== undefined 42174 ? textStrokeStyleLineJoin 42175 : defaultLineJoin, 42176 lineWidth: 42177 textStrokeStyleWidth !== undefined 42178 ? textStrokeStyleWidth 42179 : defaultLineWidth, 42180 miterLimit: 42181 textStrokeStyleMiterLimit !== undefined 42182 ? textStrokeStyleMiterLimit 42183 : defaultMiterLimit, 42184 strokeStyle: asColorLike( 42185 textStrokeStyleColor ? textStrokeStyleColor : defaultStrokeStyle 42186 ), 42187 }; 42188 } 42189 const textFont = textStyle.getFont(); 42190 const textOffsetX = textStyle.getOffsetX(); 42191 const textOffsetY = textStyle.getOffsetY(); 42192 const textRotateWithView = textStyle.getRotateWithView(); 42193 const textRotation = textStyle.getRotation(); 42194 const textScale = textStyle.getScaleArray(); 42195 const textText = textStyle.getText(); 42196 const textTextAlign = textStyle.getTextAlign(); 42197 const textTextBaseline = textStyle.getTextBaseline(); 42198 this.textState_ = { 42199 font: textFont !== undefined ? textFont : defaultFont, 42200 textAlign: 42201 textTextAlign !== undefined ? textTextAlign : defaultTextAlign, 42202 textBaseline: 42203 textTextBaseline !== undefined 42204 ? textTextBaseline 42205 : defaultTextBaseline, 42206 }; 42207 this.text_ = 42208 textText !== undefined 42209 ? Array.isArray(textText) 42210 ? textText.reduce((acc, t, i) => (acc += i % 2 ? ' ' : t), '') 42211 : textText 42212 : ''; 42213 this.textOffsetX_ = 42214 textOffsetX !== undefined ? this.pixelRatio_ * textOffsetX : 0; 42215 this.textOffsetY_ = 42216 textOffsetY !== undefined ? this.pixelRatio_ * textOffsetY : 0; 42217 this.textRotateWithView_ = 42218 textRotateWithView !== undefined ? textRotateWithView : false;
42219 this.textRotation_ = textRotation !== undefined ? textRotation : 0; 42220 this.textScale_ = [ 42221 this.pixelRatio_ * textScale[0], 42222 this.pixelRatio_ * textScale[1], 42223 ]; 42224 } 42225 } 42226} 42227 42228/* harmony default export */ const Immediate = (CanvasImmediateRenderer); 42229 42230;// CONCATENATED MODULE: ./node_modules/ol/render/canvas/hitdetect.js 42231/** 42232 * @module ol/render/canvas/hitdetect 42233 */ 42234 42235 42236 42237 42238 42239 42240 42241 42242const HIT_DETECT_RESOLUTION = 0.5; 42243 42244/** 42245 * @param {import("../../size.js").Size} size Canvas size in css pixels. 42246 * @param {Array<import("../../transform.js").Transform>} transforms Transforms 42247 * for rendering features to all worlds of the viewport, from coordinates to css 42248 * pixels. 42249 * @param {Array<import("../../Feature.js").FeatureLike>} features 42250 * Features to consider for hit detection. 42251 * @param {import("../../style/Style.js").StyleFunction|undefined} styleFunction 42252 * Layer style function. 42253 * @param {import("../../extent.js").Extent} extent Extent. 42254 * @param {number} resolution Resolution. 42255 * @param {number} rotation Rotation. 42256 * @return {ImageData} Hit detection image data. 42257 */ 42258function createHitDetectionImageData( 42259 size, 42260 transforms, 42261 features, 42262 styleFunction, 42263 extent, 42264 resolution, 42265 rotation 42266) { 42267 const width = size[0] * HIT_DETECT_RESOLUTION; 42268 const height = size[1] * HIT_DETECT_RESOLUTION; 42269 const context = createCanvasContext2D(width, height); 42270 context.imageSmoothingEnabled = false; 42271 const canvas = context.canvas; 42272 const renderer = new Immediate( 42273 context, 42274 HIT_DETECT_RESOLUTION, 42275 extent, 42276 null, 42277 rotation 42278 ); 42279 const featureCount = features.length; 42280 // Stretch hit detection index to use the whole available color range 42281 const indexFactor = Math.floor((256 * 256 * 256 - 1) / featureCount); 42282 const featuresByZIndex = {}; 42283 for (let i = 1; i <= featureCount; ++i) { 42284 const feature = features[i - 1]; 42285 const featureStyleFunction = feature.getStyleFunction() || styleFunction; 42286 if (!styleFunction) { 42287 continue; 42288 } 42289 let styles = featureStyleFunction(feature, resolution); 42290 if (!styles) { 42291 continue; 42292 } 42293 if (!Array.isArray(styles)) { 42294 styles = [styles]; 42295 } 42296 const index = i * indexFactor; 42297 const color = '#' + ('000000' + index.toString(16)).slice(-6); 42298 for (let j = 0, jj = styles.length; j < jj; ++j) { 42299 const originalStyle = styles[j]; 42300 const geometry = originalStyle.getGeometryFunction()(feature); 42301 if (!geometry || !intersects(extent, geometry.getExtent())) { 42302 continue; 42303 } 42304 const style = originalStyle.clone(); 42305 const fill = style.getFill(); 42306 if (fill) { 42307 fill.setColor(color); 42308 } 42309 const stroke = style.getStroke(); 42310 if (stroke) { 42311 stroke.setColor(color); 42312 stroke.setLineDash(null); 42313 } 42314 style.setText(undefined); 42315 const image = originalStyle.getImage(); 42316 if (image && image.getOpacity() !== 0) { 42317 const imgSize = image.getImageSize(); 42318 if (!imgSize) { 42319 continue; 42320 } 42321 42322 const imgContext = createCanvasContext2D( 42323 imgSize[0], 42324 imgSize[1], 42325 undefined, 42326 {alpha: false} 42327 ); 42328 const img = imgContext.canvas; 42329 imgContext.fillStyle = color; 42330 imgContext.fillRect(0, 0, img.width, img.height); 42331 style.setImage( 42332 new style_Icon({ 42333 img: img, 42334 imgSize: imgSize, 42335 anchor: image.getAnchor(), 42336 anchorXUnits: 'pixels', 42337 anchorYUnits: 'pixels', 42338 offset: image.getOrigin(), 42339 opacity: 1, 42340 size: image.getSize(), 42341 scale: image.getScale(), 42342 rotation: image.getRotation(), 42343 rotateWithView: image.getRotateWithView(), 42344 }) 42345 ); 42346 } 42347 const zIndex = style.getZIndex() || 0; 42348 let byGeometryType = featuresByZIndex[zIndex]; 42349 if (!byGeometryType) { 42350 byGeometryType = {}; 42351 featuresByZIndex[zIndex] = byGeometryType; 42352 byGeometryType['Polygon'] = []; 42353 byGeometryType['Circle'] = []; 42354 byGeometryType['LineString'] = []; 42355 byGeometryType['Point'] = []; 42356 } 42357 byGeometryType[geometry.getType().replace('Multi', '')].push( 42358 geometry, 42359 style 42360 ); 42361 } 42362 } 42363 42364 const zIndexKeys = Object.keys(featuresByZIndex) 42365 .map(Number) 42366 .sort(numberSafeCompareFunction); 42367 for (let i = 0, ii = zIndexKeys.length; i < ii; ++i) { 42368 const byGeometryType = featuresByZIndex[zIndexKeys[i]]; 42369 for (const type in byGeometryType) { 42370 const geomAndStyle = byGeometryType[type]; 42371 for (let j = 0, jj = geomAndStyle.length; j < jj; j += 2) { 42372 renderer.setStyle(geomAndStyle[j + 1]); 42373 for (let k = 0, kk = transforms.length; k < kk; ++k) { 42374 renderer.setTransform(transforms[k]); 42375 renderer.drawGeometry(geomAndStyle[j]); 42376 } 42377 } 42378 } 42379 } 42380 return context.getImageData(0, 0, canvas.width, canvas.height); 42381} 42382 42383/** 42384 * @param {import("../../pixel").Pixel} pixel Pixel coordinate on the hit 42385 * detection canvas in css pixels. 42386 * @param {Array<import("../../Feature").FeatureLike>} features Features. Has to 42387 * match the `features` array that was passed to `createHitDetectionImageData()`. 42388 * @param {ImageData} imageData Hit detection image data generated by 42389 * `createHitDetectionImageData()`. 42390 * @return {Array<import("../../Feature").FeatureLike>} features Features. 42391 */ 42392function hitDetect(pixel, features, imageData) { 42393 const resultFeatures = []; 42394 if (imageData) { 42395 const x = Math.floor(Math.round(pixel[0]) * HIT_DETECT_RESOLUTION); 42396 const y = Math.floor(Math.round(pixel[1]) * HIT_DETECT_RESOLUTION); 42397 // The pixel coordinate is clamped down to the hit-detect canvas' size to account 42398 // for browsers returning coordinates slightly larger than the actual canvas size 42399 // due to a non-integer pixel ratio. 42400 const index = 42401 (math_clamp(x, 0, imageData.width - 1) + 42402 math_clamp(y, 0, imageData.height - 1) * imageData.width) * 42403 4; 42404 const r = imageData.data[index]; 42405 const g = imageData.data[index + 1]; 42406 const b = imageData.data[index + 2]; 42407 const i = b + 256 * (g + 256 * r); 42408 const indexFactor = Math.floor((256 * 256 * 256 - 1) / features.length); 42409 if (i && i % indexFactor === 0) { 42410 resultFeatures.push(features[i / indexFactor - 1]); 42411 } 42412 } 42413 return resultFeatures; 42414} 42415 42416;// CONCATENATED MODULE: ./node_modules/ol/renderer/vector.js 42417/** 42418 * @module ol/renderer/vector 42419 */ 42420 42421 42422 42423/** 42424 * Feature callback. The callback will be called with three arguments. The first 42425 * argument is one {@link module:ol/Feature~Feature feature} or {@link module:ol/render/Feature~RenderFeature render feature} 42426 * at the pixel, the second is the {@link module:ol/layer/Layer~Layer layer} of the feature and will be null for 42427 * unmanaged layers. The third is the {@link module:ol/geom/SimpleGeometry~SimpleGeometry} of the feature. For features 42428 * with a GeometryCollection geometry, it will be the first detected geometry from the collection. 42429 * @template T 42430 * @typedef {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default<import("../source/Source").default>, import("../geom/SimpleGeometry.js").default): T} FeatureCallback 42431 */ 42432 42433/** 42434 * Tolerance for geometry simplification in device pixels. 42435 * @type {number} 42436 */ 42437const SIMPLIFY_TOLERANCE = 0.5; 42438 42439/** 42440 * @const 42441 * @type {Object<import("../geom/Geometry.js").Type, 42442 * function(import("../render/canvas/BuilderGroup.js").default, import("../geom/Geometry.js").default, 42443 * import("../style/Style.js").default, Object): void>} 42444 */ 42445const GEOMETRY_RENDERERS = { 42446 'Point': renderPointGeometry, 42447 'LineString': renderLineStringGeometry, 42448 'Polygon': renderPolygonGeometry, 42449 'MultiPoint': renderMultiPointGeometry, 42450 'MultiLineString': renderMultiLineStringGeometry, 42451 'MultiPolygon': renderMultiPolygonGeometry, 42452 'GeometryCollection': renderGeometryCollectionGeometry, 42453 'Circle': renderCircleGeometry, 42454}; 42455 42456/** 42457 * @param {import("../Feature.js").FeatureLike} feature1 Feature 1. 42458 * @param {import("../Feature.js").FeatureLike} feature2 Feature 2. 42459 * @return {number} Order. 42460 */ 42461function defaultOrder(feature1, feature2) { 42462 return parseInt(getUid(feature1), 10) - parseInt(getUid(feature2), 10); 42463} 42464 42465/** 42466 * @param {number} resolution Resolution. 42467 * @param {number} pixelRatio Pixel ratio. 42468 * @return {number} Squared pixel tolerance. 42469 */ 42470function getSquaredTolerance(resolution, pixelRatio) { 42471 const tolerance = getTolerance(resolution, pixelRatio); 42472 return tolerance * tolerance; 42473} 42474 42475/** 42476 * @param {number} resolution Resolution. 42477 * @param {number} pixelRatio Pixel ratio. 42478 * @return {number} Pixel tolerance. 42479 */ 42480function getTolerance(resolution, pixelRatio) { 42481 return (SIMPLIFY_TOLERANCE * resolution) / pixelRatio; 42482} 42483 42484/** 42485 * @param {import("../render/canvas/BuilderGroup.js").default} builderGroup Builder group. 42486 * @param {import("../geom/Circle.js").default} geometry Geometry. 42487 * @param {import("../style/Style.js").default} style Style. 42488 * @param {import("../Feature.js").default} feature Feature. 42489 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42490 */ 42491function renderCircleGeometry( 42492 builderGroup, 42493 geometry, 42494 style, 42495 feature, 42496 declutterBuilderGroup 42497) {
42498 const fillStyle = style.getFill(); 42499 const strokeStyle = style.getStroke(); 42500 if (fillStyle || strokeStyle) { 42501 const circleReplay = builderGroup.getBuilder(style.getZIndex(), 'Circle'); 42502 circleReplay.setFillStrokeStyle(fillStyle, strokeStyle); 42503 circleReplay.drawCircle(geometry, feature); 42504 } 42505 const textStyle = style.getText(); 42506 if (textStyle && textStyle.getText()) { 42507 const textReplay = (declutterBuilderGroup || builderGroup).getBuilder( 42508 style.getZIndex(), 42509 'Text' 42510 ); 42511 textReplay.setTextStyle(textStyle); 42512 textReplay.drawText(geometry, feature); 42513 } 42514} 42515 42516/** 42517 * @param {import("../render/canvas/BuilderGroup.js").default} replayGroup Replay group. 42518 * @param {import("../Feature.js").FeatureLike} feature Feature. 42519 * @param {import("../style/Style.js").default} style Style. 42520 * @param {number} squaredTolerance Squared tolerance. 42521 * @param {function(import("../events/Event.js").default): void} listener Listener function. 42522 * @param {import("../proj.js").TransformFunction} [transform] Transform from user to view projection. 42523 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42524 * @return {boolean} `true` if style is loading. 42525 */ 42526function renderFeature( 42527 replayGroup, 42528 feature, 42529 style, 42530 squaredTolerance, 42531 listener, 42532 transform, 42533 declutterBuilderGroup 42534) { 42535 let loading = false; 42536 const imageStyle = style.getImage(); 42537 if (imageStyle) { 42538 const imageState = imageStyle.getImageState(); 42539 if (imageState == ol_ImageState.LOADED || imageState == ol_ImageState.ERROR) { 42540 imageStyle.unlistenImageChange(listener); 42541 } else { 42542 if (imageState == ol_ImageState.IDLE) { 42543 imageStyle.load(); 42544 } 42545 imageStyle.listenImageChange(listener); 42546 loading = true; 42547 } 42548 } 42549 renderFeatureInternal( 42550 replayGroup, 42551 feature, 42552 style, 42553 squaredTolerance, 42554 transform, 42555 declutterBuilderGroup 42556 ); 42557 42558 return loading; 42559} 42560 42561/** 42562 * @param {import("../render/canvas/BuilderGroup.js").default} replayGroup Replay group. 42563 * @param {import("../Feature.js").FeatureLike} feature Feature. 42564 * @param {import("../style/Style.js").default} style Style. 42565 * @param {number} squaredTolerance Squared tolerance. 42566 * @param {import("../proj.js").TransformFunction} [transform] Optional transform function. 42567 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42568 */ 42569function renderFeatureInternal( 42570 replayGroup, 42571 feature, 42572 style, 42573 squaredTolerance, 42574 transform, 42575 declutterBuilderGroup 42576) { 42577 const geometry = style.getGeometryFunction()(feature); 42578 if (!geometry) { 42579 return; 42580 } 42581 const simplifiedGeometry = geometry.simplifyTransformed( 42582 squaredTolerance, 42583 transform 42584 ); 42585 const renderer = style.getRenderer(); 42586 if (renderer) { 42587 renderGeometry(replayGroup, simplifiedGeometry, style, feature); 42588 } else { 42589 const geometryRenderer = GEOMETRY_RENDERERS[simplifiedGeometry.getType()]; 42590 geometryRenderer( 42591 replayGroup, 42592 simplifiedGeometry, 42593 style, 42594 feature, 42595 declutterBuilderGroup 42596 ); 42597 } 42598} 42599 42600/** 42601 * @param {import("../render/canvas/BuilderGroup.js").default} replayGroup Replay group. 42602 * @param {import("../geom/Geometry.js").default|import("../render/Feature.js").default} geometry Geometry. 42603 * @param {import("../style/Style.js").default} style Style. 42604 * @param {import("../Feature.js").FeatureLike} feature Feature. 42605 */ 42606function renderGeometry(replayGroup, geometry, style, feature) { 42607 if (geometry.getType() == 'GeometryCollection') { 42608 const geometries = 42609 /** @type {import("../geom/GeometryCollection.js").default} */ ( 42610 geometry 42611 ).getGeometries(); 42612 for (let i = 0, ii = geometries.length; i < ii; ++i) { 42613 renderGeometry(replayGroup, geometries[i], style, feature); 42614 } 42615 return; 42616 } 42617 const replay = replayGroup.getBuilder(style.getZIndex(), 'Default'); 42618 replay.drawCustom( 42619 /** @type {import("../geom/SimpleGeometry.js").default} */ (geometry), 42620 feature, 42621 style.getRenderer(), 42622 style.getHitDetectionRenderer() 42623 ); 42624} 42625 42626/** 42627 * @param {import("../render/canvas/BuilderGroup.js").default} replayGroup Replay group. 42628 * @param {import("../geom/GeometryCollection.js").default} geometry Geometry. 42629 * @param {import("../style/Style.js").default} style Style. 42630 * @param {import("../Feature.js").default} feature Feature. 42631 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42632 */ 42633function renderGeometryCollectionGeometry( 42634 replayGroup, 42635 geometry, 42636 style, 42637 feature, 42638 declutterBuilderGroup 42639) { 42640 const geometries = geometry.getGeometriesArray(); 42641 let i, ii; 42642 for (i = 0, ii = geometries.length; i < ii; ++i) { 42643 const geometryRenderer = GEOMETRY_RENDERERS[geometries[i].getType()]; 42644 geometryRenderer( 42645 replayGroup, 42646 geometries[i], 42647 style, 42648 feature, 42649 declutterBuilderGroup 42650 ); 42651 } 42652} 42653 42654/** 42655 * @param {import("../render/canvas/BuilderGroup.js").default} builderGroup Replay group. 42656 * @param {import("../geom/LineString.js").default|import("../render/Feature.js").default} geometry Geometry. 42657 * @param {import("../style/Style.js").default} style Style. 42658 * @param {import("../Feature.js").FeatureLike} feature Feature. 42659 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42660 */ 42661function renderLineStringGeometry( 42662 builderGroup, 42663 geometry, 42664 style, 42665 feature, 42666 declutterBuilderGroup 42667) { 42668 const strokeStyle = style.getStroke(); 42669 if (strokeStyle) { 42670 const lineStringReplay = builderGroup.getBuilder( 42671 style.getZIndex(), 42672 'LineString' 42673 ); 42674 lineStringReplay.setFillStrokeStyle(null, strokeStyle); 42675 lineStringReplay.drawLineString(geometry, feature); 42676 } 42677 const textStyle = style.getText(); 42678 if (textStyle && textStyle.getText()) { 42679 const textReplay = (declutterBuilderGroup || builderGroup).getBuilder( 42680 style.getZIndex(), 42681 'Text' 42682 ); 42683 textReplay.setTextStyle(textStyle); 42684 textReplay.drawText(geometry, feature); 42685 } 42686} 42687 42688/** 42689 * @param {import("../render/canvas/BuilderGroup.js").default} builderGroup Replay group. 42690 * @param {import("../geom/MultiLineString.js").default|import("../render/Feature.js").default} geometry Geometry. 42691 * @param {import("../style/Style.js").default} style Style. 42692 * @param {import("../Feature.js").FeatureLike} feature Feature. 42693 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42694 */ 42695function renderMultiLineStringGeometry( 42696 builderGroup, 42697 geometry, 42698 style, 42699 feature, 42700 declutterBuilderGroup 42701) { 42702 const strokeStyle = style.getStroke(); 42703 if (strokeStyle) { 42704 const lineStringReplay = builderGroup.getBuilder( 42705 style.getZIndex(), 42706 'LineString' 42707 ); 42708 lineStringReplay.setFillStrokeStyle(null, strokeStyle); 42709 lineStringReplay.drawMultiLineString(geometry, feature); 42710 } 42711 const textStyle = style.getText(); 42712 if (textStyle && textStyle.getText()) { 42713 const textReplay = (declutterBuilderGroup || builderGroup).getBuilder( 42714 style.getZIndex(), 42715 'Text' 42716 ); 42717 textReplay.setTextStyle(textStyle); 42718 textReplay.drawText(geometry, feature); 42719 } 42720} 42721 42722/** 42723 * @param {import("../render/canvas/BuilderGroup.js").default} builderGroup Replay group. 42724 * @param {import("../geom/MultiPolygon.js").default} geometry Geometry. 42725 * @param {import("../style/Style.js").default} style Style. 42726 * @param {import("../Feature.js").default} feature Feature. 42727 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42728 */ 42729function renderMultiPolygonGeometry( 42730 builderGroup, 42731 geometry, 42732 style, 42733 feature, 42734 declutterBuilderGroup 42735) {
42736 const fillStyle = style.getFill(); 42737 const strokeStyle = style.getStroke(); 42738 if (strokeStyle || fillStyle) { 42739 const polygonReplay = builderGroup.getBuilder(style.getZIndex(), 'Polygon'); 42740 polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); 42741 polygonReplay.drawMultiPolygon(geometry, feature); 42742 } 42743 const textStyle = style.getText(); 42744 if (textStyle && textStyle.getText()) { 42745 const textReplay = (declutterBuilderGroup || builderGroup).getBuilder( 42746 style.getZIndex(), 42747 'Text' 42748 ); 42749 textReplay.setTextStyle(textStyle); 42750 textReplay.drawText(geometry, feature); 42751 } 42752} 42753 42754/** 42755 * @param {import("../render/canvas/BuilderGroup.js").default} builderGroup Replay group. 42756 * @param {import("../geom/Point.js").default|import("../render/Feature.js").default} geometry Geometry. 42757 * @param {import("../style/Style.js").default} style Style. 42758 * @param {import("../Feature.js").FeatureLike} feature Feature. 42759 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42760 */ 42761function renderPointGeometry( 42762 builderGroup, 42763 geometry, 42764 style, 42765 feature, 42766 declutterBuilderGroup 42767) { 42768 const imageStyle = style.getImage(); 42769 const textStyle = style.getText(); 42770 /** @type {import("../render/canvas.js").DeclutterImageWithText} */ 42771 let declutterImageWithText; 42772 if (imageStyle) { 42773 if (imageStyle.getImageState() != ol_ImageState.LOADED) { 42774 return; 42775 } 42776 let imageBuilderGroup = builderGroup; 42777 if (declutterBuilderGroup) { 42778 const declutterMode = imageStyle.getDeclutterMode(); 42779 if (declutterMode !== 'none') { 42780 imageBuilderGroup = declutterBuilderGroup; 42781 if (declutterMode === 'obstacle') { 42782 // draw in non-declutter group: 42783 const imageReplay = builderGroup.getBuilder( 42784 style.getZIndex(), 42785 'Image' 42786 ); 42787 imageReplay.setImageStyle(imageStyle, declutterImageWithText); 42788 imageReplay.drawPoint(geometry, feature); 42789 } else if (textStyle && textStyle.getText()) { 42790 declutterImageWithText = {}; 42791 } 42792 } 42793 } 42794 const imageReplay = imageBuilderGroup.getBuilder( 42795 style.getZIndex(), 42796 'Image' 42797 ); 42798 imageReplay.setImageStyle(imageStyle, declutterImageWithText); 42799 imageReplay.drawPoint(geometry, feature); 42800 } 42801 if (textStyle && textStyle.getText()) { 42802 let textBuilderGroup = builderGroup; 42803 if (declutterBuilderGroup) { 42804 textBuilderGroup = declutterBuilderGroup; 42805 } 42806 const textReplay = textBuilderGroup.getBuilder(style.getZIndex(), 'Text'); 42807 textReplay.setTextStyle(textStyle, declutterImageWithText); 42808 textReplay.drawText(geometry, feature); 42809 } 42810} 42811 42812/** 42813 * @param {import("../render/canvas/BuilderGroup.js").default} builderGroup Replay group. 42814 * @param {import("../geom/MultiPoint.js").default|import("../render/Feature.js").default} geometry Geometry. 42815 * @param {import("../style/Style.js").default} style Style. 42816 * @param {import("../Feature.js").FeatureLike} feature Feature. 42817 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42818 */ 42819function renderMultiPointGeometry( 42820 builderGroup, 42821 geometry, 42822 style, 42823 feature, 42824 declutterBuilderGroup 42825) { 42826 const imageStyle = style.getImage(); 42827 const textStyle = style.getText(); 42828 /** @type {import("../render/canvas.js").DeclutterImageWithText} */ 42829 let declutterImageWithText; 42830 if (imageStyle) { 42831 if (imageStyle.getImageState() != ol_ImageState.LOADED) { 42832 return; 42833 } 42834 let imageBuilderGroup = builderGroup; 42835 if (declutterBuilderGroup) { 42836 const declutterMode = imageStyle.getDeclutterMode(); 42837 if (declutterMode !== 'none') { 42838 imageBuilderGroup = declutterBuilderGroup; 42839 if (declutterMode === 'obstacle') { 42840 // draw in non-declutter group: 42841 const imageReplay = builderGroup.getBuilder( 42842 style.getZIndex(), 42843 'Image' 42844 ); 42845 imageReplay.setImageStyle(imageStyle, declutterImageWithText); 42846 imageReplay.drawMultiPoint(geometry, feature); 42847 } else if (textStyle && textStyle.getText()) { 42848 declutterImageWithText = {}; 42849 } 42850 } 42851 } 42852 const imageReplay = imageBuilderGroup.getBuilder( 42853 style.getZIndex(), 42854 'Image' 42855 ); 42856 imageReplay.setImageStyle(imageStyle, declutterImageWithText); 42857 imageReplay.drawMultiPoint(geometry, feature); 42858 } 42859 if (textStyle && textStyle.getText()) { 42860 let textBuilderGroup = builderGroup; 42861 if (declutterBuilderGroup) { 42862 textBuilderGroup = declutterBuilderGroup; 42863 } 42864 const textReplay = textBuilderGroup.getBuilder(style.getZIndex(), 'Text'); 42865 textReplay.setTextStyle(textStyle, declutterImageWithText); 42866 textReplay.drawText(geometry, feature); 42867 } 42868} 42869 42870/** 42871 * @param {import("../render/canvas/BuilderGroup.js").default} builderGroup Replay group. 42872 * @param {import("../geom/Polygon.js").default|import("../render/Feature.js").default} geometry Geometry. 42873 * @param {import("../style/Style.js").default} style Style. 42874 * @param {import("../Feature.js").FeatureLike} feature Feature. 42875 * @param {import("../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 42876 */ 42877function renderPolygonGeometry( 42878 builderGroup, 42879 geometry, 42880 style, 42881 feature, 42882 declutterBuilderGroup 42883) {
42884 const fillStyle = style.getFill(); 42885 const strokeStyle = style.getStroke(); 42886 if (fillStyle || strokeStyle) { 42887 const polygonReplay = builderGroup.getBuilder(style.getZIndex(), 'Polygon'); 42888 polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle); 42889 polygonReplay.drawPolygon(geometry, feature); 42890 } 42891 const textStyle = style.getText(); 42892 if (textStyle && textStyle.getText()) { 42893 const textReplay = (declutterBuilderGroup || builderGroup).getBuilder( 42894 style.getZIndex(), 42895 'Text' 42896 ); 42897 textReplay.setTextStyle(textStyle); 42898 textReplay.drawText(geometry, feature); 42899 } 42900} 42901 42902;// CONCATENATED MODULE: ./node_modules/ol/renderer/canvas/VectorLayer.js 42903/** 42904 * @module ol/renderer/canvas/VectorLayer 42905 */ 42906 42907 42908 42909 42910 42911 42912 42913 42914 42915 42916 42917 42918 42919 42920/** 42921 * @classdesc 42922 * Canvas renderer for vector layers. 42923 * @api 42924 */ 42925class CanvasVectorLayerRenderer extends canvas_Layer { 42926 /** 42927 * @param {import("../../layer/BaseVector.js").default} vectorLayer Vector layer. 42928 */ 42929 constructor(vectorLayer) { 42930 super(vectorLayer); 42931 42932 /** @private */ 42933 this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this); 42934 42935 /** 42936 * @type {boolean} 42937 */ 42938 this.animatingOrInteracting_; 42939 42940 /** 42941 * @type {ImageData} 42942 */ 42943 this.hitDetectionImageData_ = null; 42944 42945 /** 42946 * @type {Array<import("../../Feature.js").default>} 42947 */ 42948 this.renderedFeatures_ = null; 42949 42950 /** 42951 * @private 42952 * @type {number} 42953 */ 42954 this.renderedRevision_ = -1; 42955 42956 /** 42957 * @private 42958 * @type {number} 42959 */ 42960 this.renderedResolution_ = NaN; 42961 42962 /** 42963 * @private 42964 * @type {import("../../extent.js").Extent} 42965 */ 42966 this.renderedExtent_ = createEmpty(); 42967 42968 /** 42969 * @private 42970 * @type {import("../../extent.js").Extent} 42971 */ 42972 this.wrappedRenderedExtent_ = createEmpty(); 42973 42974 /** 42975 * @private 42976 * @type {number} 42977 */ 42978 this.renderedRotation_; 42979 42980 /** 42981 * @private 42982 * @type {import("../../coordinate").Coordinate} 42983 */ 42984 this.renderedCenter_ = null; 42985 42986 /** 42987 * @private 42988 * @type {import("../../proj/Projection").default} 42989 */ 42990 this.renderedProjection_ = null; 42991 42992 /** 42993 * @private 42994 * @type {function(import("../../Feature.js").default, import("../../Feature.js").default): number|null} 42995 */ 42996 this.renderedRenderOrder_ = null; 42997 42998 /** 42999 * @private 43000 * @type {import("../../render/canvas/ExecutorGroup").default} 43001 */ 43002 this.replayGroup_ = null; 43003 43004 /** 43005 * A new replay group had to be created by `prepareFrame()` 43006 * @type {boolean} 43007 */ 43008 this.replayGroupChanged = true; 43009 43010 /** 43011 * @type {import("../../render/canvas/ExecutorGroup").default} 43012 */ 43013 this.declutterExecutorGroup = null; 43014 43015 /** 43016 * Clipping to be performed by `renderFrame()` 43017 * @type {boolean} 43018 */ 43019 this.clipping = true; 43020 43021 /** 43022 * @private 43023 * @type {CanvasRenderingContext2D} 43024 */ 43025 this.compositionContext_ = null; 43026 43027 /** 43028 * @private 43029 * @type {number} 43030 */ 43031 this.opacity_ = 1; 43032 } 43033 43034 /** 43035 * @param {ExecutorGroup} executorGroup Executor group. 43036 * @param {import("../../Map.js").FrameState} frameState Frame state. 43037 * @param {import("rbush").default} [declutterTree] Declutter tree. 43038 */ 43039 renderWorlds(executorGroup, frameState, declutterTree) { 43040 const extent = frameState.extent; 43041 const viewState = frameState.viewState; 43042 const center = viewState.center; 43043 const resolution = viewState.resolution; 43044 const projection = viewState.projection; 43045 const rotation = viewState.rotation; 43046 const projectionExtent = projection.getExtent(); 43047 const vectorSource = this.getLayer().getSource(); 43048 const pixelRatio = frameState.pixelRatio; 43049 const viewHints = frameState.viewHints; 43050 const snapToPixel = !( 43051 viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING] 43052 ); 43053 const context = this.compositionContext_; 43054 const width = Math.round(frameState.size[0] * pixelRatio); 43055 const height = Math.round(frameState.size[1] * pixelRatio); 43056 43057 const multiWorld = vectorSource.getWrapX() && projection.canWrapX(); 43058 const worldWidth = multiWorld ? extent_getWidth(projectionExtent) : null; 43059 const endWorld = multiWorld 43060 ? Math.ceil((extent[2] - projectionExtent[2]) / worldWidth) + 1 43061 : 1; 43062 let world = multiWorld 43063 ? Math.floor((extent[0] - projectionExtent[0]) / worldWidth) 43064 : 0; 43065 do { 43066 const transform = this.getRenderTransform( 43067 center, 43068 resolution, 43069 rotation, 43070 pixelRatio, 43071 width, 43072 height, 43073 world * worldWidth 43074 ); 43075 executorGroup.execute( 43076 context, 43077 1, 43078 transform, 43079 rotation, 43080 snapToPixel, 43081 undefined, 43082 declutterTree 43083 ); 43084 } while (++world < endWorld); 43085 } 43086 43087 setupCompositionContext_() { 43088 if (this.opacity_ !== 1) { 43089 const compositionContext = createCanvasContext2D( 43090 this.context.canvas.width, 43091 this.context.canvas.height, 43092 canvasPool 43093 ); 43094 this.compositionContext_ = compositionContext; 43095 } else { 43096 this.compositionContext_ = this.context; 43097 } 43098 } 43099 43100 releaseCompositionContext_() { 43101 if (this.opacity_ !== 1) {
43102 const alpha = this.context.globalAlpha; 43103 this.context.globalAlpha = this.opacity_; 43104 this.context.drawImage(this.compositionContext_.canvas, 0, 0); 43105 this.context.globalAlpha = alpha; 43106 releaseCanvas(this.compositionContext_); 43107 canvasPool.push(this.compositionContext_.canvas); 43108 this.compositionContext_ = null; 43109 } 43110 } 43111 43112 /** 43113 * Render declutter items for this layer 43114 * @param {import("../../Map.js").FrameState} frameState Frame state. 43115 */ 43116 renderDeclutter(frameState) { 43117 if (this.declutterExecutorGroup) { 43118 this.setupCompositionContext_(); 43119 this.renderWorlds( 43120 this.declutterExecutorGroup, 43121 frameState, 43122 frameState.declutterTree 43123 ); 43124 this.releaseCompositionContext_(); 43125 } 43126 } 43127 43128 /** 43129 * Render the layer. 43130 * @param {import("../../Map.js").FrameState} frameState Frame state. 43131 * @param {HTMLElement} target Target that may be used to render content to. 43132 * @return {HTMLElement} The rendered element. 43133 */ 43134 renderFrame(frameState, target) { 43135 const pixelRatio = frameState.pixelRatio; 43136 const layerState = frameState.layerStatesArray[frameState.layerIndex]; 43137 43138 // set forward and inverse pixel transforms 43139 makeScale(this.pixelTransform, 1 / pixelRatio, 1 / pixelRatio); 43140 makeInverse(this.inversePixelTransform, this.pixelTransform); 43141 43142 const canvasTransform = transform_toString(this.pixelTransform); 43143 43144 this.useContainer(target, canvasTransform, this.getBackground(frameState)); 43145 const context = this.context; 43146 const canvas = context.canvas; 43147 43148 const replayGroup = this.replayGroup_; 43149 const declutterExecutorGroup = this.declutterExecutorGroup; 43150 if ( 43151 (!replayGroup || replayGroup.isEmpty()) && 43152 (!declutterExecutorGroup || declutterExecutorGroup.isEmpty()) 43153 ) { 43154 return null; 43155 } 43156 43157 // resize and clear 43158 const width = Math.round(frameState.size[0] * pixelRatio); 43159 const height = Math.round(frameState.size[1] * pixelRatio); 43160 if (canvas.width != width || canvas.height != height) { 43161 canvas.width = width; 43162 canvas.height = height; 43163 if (canvas.style.transform !== canvasTransform) { 43164 canvas.style.transform = canvasTransform; 43165 } 43166 } else if (!this.containerReused) { 43167 context.clearRect(0, 0, width, height); 43168 } 43169 43170 this.preRender(context, frameState); 43171 43172 const viewState = frameState.viewState; 43173 const projection = viewState.projection; 43174 43175 this.opacity_ = layerState.opacity; 43176 this.setupCompositionContext_(); 43177 43178 // clipped rendering if layer extent is set 43179 let clipped = false; 43180 let render = true; 43181 if (layerState.extent && this.clipping) { 43182 const layerExtent = proj_fromUserExtent(layerState.extent, projection); 43183 render = intersects(layerExtent, frameState.extent); 43184 clipped = render && !containsExtent(layerExtent, frameState.extent); 43185 if (clipped) { 43186 this.clipUnrotated(this.compositionContext_, frameState, layerExtent); 43187 } 43188 } 43189 43190 if (render) { 43191 this.renderWorlds(replayGroup, frameState); 43192 } 43193 43194 if (clipped) { 43195 this.compositionContext_.restore(); 43196 } 43197 43198 this.releaseCompositionContext_(); 43199 43200 this.postRender(context, frameState); 43201 43202 if (this.renderedRotation_ !== viewState.rotation) { 43203 this.renderedRotation_ = viewState.rotation; 43204 this.hitDetectionImageData_ = null; 43205 } 43206 return this.container; 43207 } 43208 43209 /** 43210 * Asynchronous layer level hit detection. 43211 * @param {import("../../pixel.js").Pixel} pixel Pixel. 43212 * @return {Promise<Array<import("../../Feature").default>>} Promise that resolves with an array of features. 43213 */ 43214 getFeatures(pixel) { 43215 return new Promise( 43216 /** 43217 * @param {function(Array<import("../../Feature").default|import("../../render/Feature").default>): void} resolve Resolver function. 43218 * @this {CanvasVectorLayerRenderer} 43219 */ 43220 function (resolve) { 43221 if (!this.hitDetectionImageData_ && !this.animatingOrInteracting_) { 43222 const size = [this.context.canvas.width, this.context.canvas.height]; 43223 apply(this.pixelTransform, size); 43224 const center = this.renderedCenter_; 43225 const resolution = this.renderedResolution_; 43226 const rotation = this.renderedRotation_; 43227 const projection = this.renderedProjection_; 43228 const extent = this.wrappedRenderedExtent_; 43229 const layer = this.getLayer(); 43230 const transforms = []; 43231 const width = size[0] * HIT_DETECT_RESOLUTION; 43232 const height = size[1] * HIT_DETECT_RESOLUTION; 43233 transforms.push( 43234 this.getRenderTransform( 43235 center, 43236 resolution, 43237 rotation, 43238 HIT_DETECT_RESOLUTION, 43239 width, 43240 height, 43241 0 43242 ).slice() 43243 ); 43244 const source = layer.getSource(); 43245 const projectionExtent = projection.getExtent(); 43246 if ( 43247 source.getWrapX() && 43248 projection.canWrapX() && 43249 !containsExtent(projectionExtent, extent) 43250 ) { 43251 let startX = extent[0]; 43252 const worldWidth = extent_getWidth(projectionExtent); 43253 let world = 0; 43254 let offsetX; 43255 while (startX < projectionExtent[0]) { 43256 --world; 43257 offsetX = worldWidth * world; 43258 transforms.push( 43259 this.getRenderTransform( 43260 center, 43261 resolution, 43262 rotation, 43263 HIT_DETECT_RESOLUTION, 43264 width, 43265 height, 43266 offsetX 43267 ).slice() 43268 ); 43269 startX += worldWidth; 43270 } 43271 world = 0; 43272 startX = extent[2]; 43273 while (startX > projectionExtent[2]) { 43274 ++world; 43275 offsetX = worldWidth * world; 43276 transforms.push( 43277 this.getRenderTransform( 43278 center, 43279 resolution, 43280 rotation, 43281 HIT_DETECT_RESOLUTION, 43282 width, 43283 height, 43284 offsetX 43285 ).slice() 43286 ); 43287 startX -= worldWidth; 43288 } 43289 } 43290 43291 this.hitDetectionImageData_ = createHitDetectionImageData( 43292 size, 43293 transforms, 43294 this.renderedFeatures_, 43295 layer.getStyleFunction(), 43296 extent, 43297 resolution, 43298 rotation 43299 ); 43300 } 43301 resolve( 43302 hitDetect(pixel, this.renderedFeatures_, this.hitDetectionImageData_) 43303 ); 43304 }.bind(this) 43305 ); 43306 } 43307 43308 /** 43309 * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate. 43310 * @param {import("../../Map.js").FrameState} frameState Frame state. 43311 * @param {number} hitTolerance Hit tolerance in pixels. 43312 * @param {import("../vector.js").FeatureCallback<T>}
43312 callback Feature callback. 43313 * @param {Array<import("../Map.js").HitMatch<T>>} matches The hit detected matches with tolerance. 43314 * @return {T|undefined} Callback result. 43315 * @template T 43316 */ 43317 forEachFeatureAtCoordinate( 43318 coordinate, 43319 frameState, 43320 hitTolerance, 43321 callback, 43322 matches 43323 ) { 43324 if (!this.replayGroup_) { 43325 return undefined; 43326 } 43327 const resolution = frameState.viewState.resolution; 43328 const rotation = frameState.viewState.rotation; 43329 const layer = this.getLayer(); 43330 43331 /** @type {!Object<string, import("../Map.js").HitMatch<T>|true>} */ 43332 const features = {}; 43333 43334 /** 43335 * @param {import("../../Feature.js").FeatureLike} feature Feature. 43336 * @param {import("../../geom/SimpleGeometry.js").default} geometry Geometry. 43337 * @param {number} distanceSq The squared distance to the click position 43338 * @return {T|undefined} Callback result. 43339 */ 43340 const featureCallback = function (feature, geometry, distanceSq) { 43341 const key = getUid(feature); 43342 const match = features[key]; 43343 if (!match) { 43344 if (distanceSq === 0) { 43345 features[key] = true; 43346 return callback(feature, layer, geometry); 43347 } 43348 matches.push( 43349 (features[key] = { 43350 feature: feature, 43351 layer: layer, 43352 geometry: geometry, 43353 distanceSq: distanceSq, 43354 callback: callback, 43355 }) 43356 ); 43357 } else if (match !== true && distanceSq < match.distanceSq) { 43358 if (distanceSq === 0) { 43359 features[key] = true; 43360 matches.splice(matches.lastIndexOf(match), 1); 43361 return callback(feature, layer, geometry); 43362 } 43363 match.geometry = geometry; 43364 match.distanceSq = distanceSq; 43365 } 43366 return undefined; 43367 }; 43368 43369 let result; 43370 const executorGroups = [this.replayGroup_]; 43371 if (this.declutterExecutorGroup) { 43372 executorGroups.push(this.declutterExecutorGroup); 43373 } 43374 executorGroups.some((executorGroup) => { 43375 return (result = executorGroup.forEachFeatureAtCoordinate( 43376 coordinate, 43377 resolution, 43378 rotation, 43379 hitTolerance, 43380 featureCallback, 43381 executorGroup === this.declutterExecutorGroup && 43382 frameState.declutterTree 43383 ? frameState.declutterTree.all().map((item) => item.value) 43384 : null 43385 )); 43386 }); 43387 43388 return result; 43389 } 43390 43391 /** 43392 * Perform action necessary to get the layer rendered after new fonts have loaded 43393 */ 43394 handleFontsChanged() { 43395 const layer = this.getLayer(); 43396 if (layer.getVisible() && this.replayGroup_) { 43397 layer.changed(); 43398 } 43399 } 43400 43401 /** 43402 * Handle changes in image style state. 43403 * @param {import("../../events/Event.js").default} event Image style change event. 43404 * @private 43405 */ 43406 handleStyleImageChange_(event) { 43407 this.renderIfReadyAndVisible(); 43408 } 43409 43410 /** 43411 * Determine whether render should be called. 43412 * @param {import("../../Map.js").FrameState} frameState Frame state. 43413 * @return {boolean} Layer is ready to be rendered. 43414 */ 43415 prepareFrame(frameState) { 43416 const vectorLayer = this.getLayer(); 43417 const vectorSource = vectorLayer.getSource(); 43418 if (!vectorSource) { 43419 return false; 43420 } 43421 43422 const animating = frameState.viewHints[ViewHint.ANIMATING]; 43423 const interacting = frameState.viewHints[ViewHint.INTERACTING]; 43424 const updateWhileAnimating = vectorLayer.getUpdateWhileAnimating(); 43425 const updateWhileInteracting = vectorLayer.getUpdateWhileInteracting(); 43426 43427 if ( 43428 (this.ready && !updateWhileAnimating && animating) || 43429 (!updateWhileInteracting && interacting) 43430 ) { 43431 this.animatingOrInteracting_ = true; 43432 return true; 43433 } 43434 this.animatingOrInteracting_ = false; 43435 43436 const frameStateExtent = frameState.extent; 43437 const viewState = frameState.viewState; 43438 const projection = viewState.projection; 43439 const resolution = viewState.resolution; 43440 const pixelRatio = frameState.pixelRatio; 43441 const vectorLayerRevision = vectorLayer.getRevision(); 43442 const vectorLayerRenderBuffer = vectorLayer.getRenderBuffer(); 43443 let vectorLayerRenderOrder = vectorLayer.getRenderOrder(); 43444 43445 if (vectorLayerRenderOrder === undefined) { 43446 vectorLayerRenderOrder = defaultOrder; 43447 } 43448 43449 const center = viewState.center.slice(); 43450 const extent = buffer( 43451 frameStateExtent, 43452 vectorLayerRenderBuffer * resolution 43453 ); 43454 const renderedExtent = extent.slice(); 43455 const loadExtents = [extent.slice()]; 43456 const projectionExtent = projection.getExtent(); 43457 43458 if ( 43459 vectorSource.getWrapX() && 43460 projection.canWrapX() && 43461 !containsExtent(projectionExtent, frameState.extent) 43462 ) { 43463 // For the replay group, we need an extent that intersects the real world 43464 // (-180° to +180°). To support geometries in a coordinate range from -540°
43465 // to +540°, we add at least 1 world width on each side of the projection 43466 // extent. If the viewport is wider than the world, we need to add half of 43467 // the viewport width to make sure we cover the whole viewport. 43468 const worldWidth = extent_getWidth(projectionExtent); 43469 const gutter = Math.max(extent_getWidth(extent) / 2, worldWidth); 43470 extent[0] = projectionExtent[0] - gutter; 43471 extent[2] = projectionExtent[2] + gutter; 43472 coordinate_wrapX(center, projection); 43473 const loadExtent = wrapX(loadExtents[0], projection); 43474 // If the extent crosses the date line, we load data for both edges of the worlds 43475 if ( 43476 loadExtent[0] < projectionExtent[0] && 43477 loadExtent[2] < projectionExtent[2] 43478 ) { 43479 loadExtents.push([ 43480 loadExtent[0] + worldWidth, 43481 loadExtent[1], 43482 loadExtent[2] + worldWidth, 43483 loadExtent[3], 43484 ]); 43485 } else if ( 43486 loadExtent[0] > projectionExtent[0] && 43487 loadExtent[2] > projectionExtent[2] 43488 ) { 43489 loadExtents.push([ 43490 loadExtent[0] - worldWidth, 43491 loadExtent[1], 43492 loadExtent[2] - worldWidth, 43493 loadExtent[3], 43494 ]); 43495 } 43496 } 43497 43498 if ( 43499 this.ready && 43500 this.renderedResolution_ == resolution && 43501 this.renderedRevision_ == vectorLayerRevision && 43502 this.renderedRenderOrder_ == vectorLayerRenderOrder && 43503 containsExtent(this.wrappedRenderedExtent_, extent) 43504 ) { 43505 if (!equals(this.renderedExtent_, renderedExtent)) { 43506 this.hitDetectionImageData_ = null; 43507 this.renderedExtent_ = renderedExtent; 43508 } 43509 this.renderedCenter_ = center; 43510 this.replayGroupChanged = false; 43511 return true; 43512 } 43513 43514 this.replayGroup_ = null; 43515 43516 const replayGroup = new canvas_BuilderGroup( 43517 getTolerance(resolution, pixelRatio), 43518 extent, 43519 resolution, 43520 pixelRatio 43521 ); 43522 43523 let declutterBuilderGroup; 43524 if (this.getLayer().getDeclutter()) { 43525 declutterBuilderGroup = new canvas_BuilderGroup( 43526 getTolerance(resolution, pixelRatio), 43527 extent, 43528 resolution, 43529 pixelRatio 43530 ); 43531 } 43532 43533 const userProjection = getUserProjection(); 43534 let userTransform; 43535 if (userProjection) { 43536 for (let i = 0, ii = loadExtents.length; i < ii; ++i) { 43537 const extent = loadExtents[i]; 43538 const userExtent = proj_toUserExtent(extent, projection); 43539 vectorSource.loadFeatures( 43540 userExtent, 43541 toUserResolution(resolution, projection), 43542 userProjection 43543 ); 43544 } 43545 userTransform = getTransformFromProjections(userProjection, projection); 43546 } else { 43547 for (let i = 0, ii = loadExtents.length; i < ii; ++i) { 43548 vectorSource.loadFeatures(loadExtents[i], resolution, projection); 43549 } 43550 } 43551 43552 const squaredTolerance = getSquaredTolerance(resolution, pixelRatio); 43553 let ready = true; 43554 const render = 43555 /** 43556 * @param {import("../../Feature.js").default} feature Feature. 43557 * @this {CanvasVectorLayerRenderer} 43558 */ 43559 function (feature) { 43560 let styles; 43561 const styleFunction = 43562 feature.getStyleFunction() || vectorLayer.getStyleFunction(); 43563 if (styleFunction) { 43564 styles = styleFunction(feature, resolution); 43565 } 43566 if (styles) { 43567 const dirty = this.renderFeature( 43568 feature, 43569 squaredTolerance, 43570 styles, 43571 replayGroup, 43572 userTransform, 43573 declutterBuilderGroup 43574 ); 43575 ready = ready && !dirty; 43576 } 43577 }.bind(this); 43578 43579 const userExtent = proj_toUserExtent(extent, projection); 43580 /** @type {Array<import("../../Feature.js").default>} */ 43581 const features = vectorSource.getFeaturesInExtent(userExtent); 43582 if (vectorLayerRenderOrder) { 43583 features.sort(vectorLayerRenderOrder); 43584 } 43585 for (let i = 0, ii = features.length; i < ii; ++i) { 43586 render(features[i]); 43587 } 43588 this.renderedFeatures_ = features; 43589 this.ready = ready; 43590 43591 const replayGroupInstructions = replayGroup.finish(); 43592 const executorGroup = new canvas_ExecutorGroup( 43593 extent, 43594 resolution, 43595 pixelRatio, 43596 vectorSource.getOverlaps(), 43597 replayGroupInstructions, 43598 vectorLayer.getRenderBuffer() 43599 ); 43600 43601 if (declutterBuilderGroup) { 43602 this.declutterExecutorGroup = new canvas_ExecutorGroup( 43603 extent, 43604 resolution, 43605 pixelRatio, 43606 vectorSource.getOverlaps(), 43607 declutterBuilderGroup.finish(), 43608 vectorLayer.getRenderBuffer() 43609 ); 43610 } 43611 43612 this.renderedResolution_ = resolution; 43613 this.renderedRevision_ = vectorLayerRevision; 43614 this.renderedRenderOrder_ = vectorLayerRenderOrder; 43615 this.renderedExtent_ = renderedExtent; 43616 this.wrappedRenderedExtent_ = extent; 43617 this.renderedCenter_ = center; 43618 this.renderedProjection_ = projection; 43619 this.replayGroup_ = executorGroup; 43620 this.hitDetectionImageData_ = null; 43621 43622 this.replayGroupChanged = true; 43623 return true; 43624 } 43625 43626 /** 43627 * @param {import("../../Feature.js").default} feature Feature. 43628 * @param {number} squaredTolerance Squared render tolerance. 43629 * @param {import("../../style/Style.js").default|Array<import("../../style/Style.js").default>} styles The style or array of styles. 43630 * @param {import("../../render/canvas/BuilderGroup.js").default} builderGroup Builder group. 43631 * @param {import("../../proj.js").TransformFunction} [transform] Transform from user to view projection. 43632 * @param {import("../../render/canvas/BuilderGroup.js").default} [declutterBuilderGroup] Builder for decluttering. 43633 * @return {boolean} `true` if an image is loading. 43634 */ 43635 renderFeature( 43636 feature, 43637 squaredTolerance, 43638 styles, 43639 builderGroup, 43640 transform, 43641 declutterBuilderGroup 43642 ) { 43643 if (!styles) { 43644 return false;
43645 } 43646 let loading = false; 43647 if (Array.isArray(styles)) { 43648 for (let i = 0, ii = styles.length; i < ii; ++i) { 43649 loading = 43650 renderFeature( 43651 builderGroup, 43652 feature, 43653 styles[i], 43654 squaredTolerance, 43655 this.boundHandleStyleImageChange_, 43656 transform, 43657 declutterBuilderGroup 43658 ) || loading; 43659 } 43660 } else { 43661 loading = renderFeature( 43662 builderGroup, 43663 feature, 43664 styles, 43665 squaredTolerance, 43666 this.boundHandleStyleImageChange_, 43667 transform, 43668 declutterBuilderGroup 43669 ); 43670 } 43671 return loading; 43672 } 43673} 43674 43675/* harmony default export */ const canvas_VectorLayer = (CanvasVectorLayerRenderer); 43676 43677;// CONCATENATED MODULE: ./node_modules/ol/layer/Vector.js 43678/** 43679 * @module ol/layer/Vector 43680 */ 43681 43682 43683 43684/** 43685 * @classdesc 43686 * Vector data is rendered client-side, as vectors. This layer type provides most accurate rendering 43687 * even during animations. Points and labels stay upright on rotated views. For very large 43688 * amounts of vector data, performance may suffer during pan and zoom animations. In this case, 43689 * try {@link module:ol/layer/VectorImage~VectorImageLayer}. 43690 * 43691 * Note that any property set in the options is set as a {@link module:ol/Object~BaseObject} 43692 * property on the layer object; for example, setting `title: 'My Title'` in the 43693 * options means that `title` is observable, and has get/set accessors. 43694 * 43695 * @template {import("../source/Vector.js").default} VectorSourceType 43696 * @extends {BaseVectorLayer<VectorSourceType, CanvasVectorLayerRenderer>} 43697 * @api 43698 */ 43699class VectorLayer extends BaseVector { 43700 /** 43701 * @param {import("./BaseVector.js").Options<VectorSourceType>} [options] Options. 43702 */ 43703 constructor(options) { 43704 super(options); 43705 } 43706 43707 createRenderer() { 43708 return new canvas_VectorLayer(this); 43709 } 43710} 43711 43712/* harmony default export */ const Vector = (VectorLayer); 43713 43714;// CONCATENATED MODULE: ./node_modules/ol/layer/TileProperty.js 43715/** 43716 * @module ol/layer/TileProperty 43717 */ 43718 43719/** 43720 * @enum {string} 43721 */ 43722/* harmony default export */ const TileProperty = ({ 43723 PRELOAD: 'preload', 43724 USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError', 43725}); 43726 43727;// CONCATENATED MODULE: ./node_modules/ol/layer/BaseTile.js 43728/** 43729 * @module ol/layer/BaseTile 43730 */ 43731 43732 43733 43734/*** 43735 * @template Return 43736 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 43737 * import("../Observable").OnSignature<import("./Base").BaseLayerObjectEventTypes| 43738 * 'change:source'|'change:preload'|'change:useInterimTilesOnError', import("../Object").ObjectEvent, Return> & 43739 * import("../Observable").OnSignature<import("../render/EventType").LayerRenderEventTypes, import("../render/Event").default, Return> & 43740 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("./Base").BaseLayerObjectEventTypes| 43741 * 'change:source'|'change:preload'|'change:useInterimTilesOnError'|import("../render/EventType").LayerRenderEventTypes, Return>} BaseTileLayerOnSignature 43742 */ 43743 43744/** 43745 * @template {import("../source/Tile.js").default} TileSourceType 43746 * @typedef {Object} Options 43747 * @property {string} [className='ol-layer'] A CSS class name to set to the layer element. 43748 * @property {number} [opacity=1] Opacity (0, 1). 43749 * @property {boolean} [visible=true] Visibility. 43750 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be 43751 * rendered outside of this extent. 43752 * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers 43753 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed 43754 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()` 43755 * method was used. 43756 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be 43757 * visible. 43758 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will 43759 * be visible. 43760 * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be 43761 * visible. 43762 * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will 43763 * be visible. 43764 * @property {number} [preload=0] Preload. Load low-resolution tiles up to `preload` levels. `0` 43765 * means no preloading. 43766 * @property {TileSourceType} [source] Source for this layer. 43767 * @property {import("../Map.js").default} [map] Sets the layer as overlay on a map. The map will not manage
43768 * this layer in its layers collection, and the layer will be rendered on top. This is useful for 43769 * temporary layers. The standard way to add a layer to a map and have it managed by the map is to 43770 * use {@link import("../Map.js").default#addLayer map.addLayer()}. 43771 * @property {boolean} [useInterimTilesOnError=true] Use interim tiles on error. 43772 * @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`. 43773 */ 43774 43775/** 43776 * @classdesc 43777 * For layer sources that provide pre-rendered, tiled images in grids that are 43778 * organized by zoom levels for specific resolutions. 43779 * Note that any property set in the options is set as a {@link module:ol/Object~BaseObject} 43780 * property on the layer object; for example, setting `title: 'My Title'` in the 43781 * options means that `title` is observable, and has get/set accessors. 43782 * 43783 * @template {import("../source/Tile.js").default} TileSourceType 43784 * @template {import("../renderer/Layer.js").default} RendererType 43785 * @extends {Layer<TileSourceType, RendererType>} 43786 * @api 43787 */ 43788class BaseTileLayer extends layer_Layer { 43789 /** 43790 * @param {Options<TileSourceType>} [options] Tile layer options. 43791 */ 43792 constructor(options) { 43793 options = options ? options : {}; 43794 43795 const baseOptions = Object.assign({}, options); 43796 43797 delete baseOptions.preload; 43798 delete baseOptions.useInterimTilesOnError; 43799 super(baseOptions); 43800 43801 /*** 43802 * @type {BaseTileLayerOnSignature<import("../events").EventsKey>} 43803 */ 43804 this.on; 43805 43806 /*** 43807 * @type {BaseTileLayerOnSignature<import("../events").EventsKey>} 43808 */ 43809 this.once; 43810 43811 /*** 43812 * @type {BaseTileLayerOnSignature<void>} 43813 */ 43814 this.un; 43815 43816 this.setPreload(options.preload !== undefined ? options.preload : 0); 43817 this.setUseInterimTilesOnError( 43818 options.useInterimTilesOnError !== undefined 43819 ? options.useInterimTilesOnError 43820 : true 43821 ); 43822 } 43823 43824 /** 43825 * Return the level as number to which we will preload tiles up to. 43826 * @return {number} The level to preload tiles up to. 43827 * @observable 43828 * @api 43829 */ 43830 getPreload() { 43831 return /** @type {number} */ (this.get(TileProperty.PRELOAD)); 43832 } 43833 43834 /** 43835 * Set the level as number to which we will preload tiles up to. 43836 * @param {number} preload The level to preload tiles up to. 43837 * @observable 43838 * @api 43839 */ 43840 setPreload(preload) { 43841 this.set(TileProperty.PRELOAD, preload); 43842 } 43843 43844 /** 43845 * Whether we use interim tiles on error. 43846 * @return {boolean} Use interim tiles on error. 43847 * @observable 43848 * @api 43849 */ 43850 getUseInterimTilesOnError() { 43851 return /** @type {boolean} */ ( 43852 this.get(TileProperty.USE_INTERIM_TILES_ON_ERROR) 43853 ); 43854 } 43855 43856 /** 43857 * Set whether we use interim tiles on error. 43858 * @param {boolean} useInterimTilesOnError Use interim tiles on error. 43859 * @observable 43860 * @api 43861 */ 43862 setUseInterimTilesOnError(useInterimTilesOnError) { 43863 this.set(TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); 43864 } 43865 43866 /** 43867 * Get data for a pixel location. The return type depends on the source data. For image tiles, 43868 * a four element RGBA array will be returned. For data tiles, the array length will match the 43869 * number of bands in the dataset. For requests outside the layer extent, `null` will be returned. 43870 * Data for a image tiles can only be retrieved if the source's `crossOrigin` property is set. 43871 * 43872 * ```js 43873 * // display layer data on every pointer move 43874 * map.on('pointermove', (event) => { 43875 * console.log(layer.getData(event.pixel)); 43876 * }); 43877 * ``` 43878 * @param {import("../pixel").Pixel} pixel Pixel. 43879 * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data. 43880 * @api 43881 */ 43882 getData(pixel) { 43883 return super.getData(pixel); 43884 } 43885} 43886 43887/* harmony default export */ const BaseTile = (BaseTileLayer); 43888 43889;// CONCATENATED MODULE: ./node_modules/ol/Tile.js 43890/** 43891 * @module ol/Tile 43892 */ 43893 43894 43895 43896 43897 43898 43899/** 43900 * A function that takes an {@link module:ol/Tile~Tile} for the tile and a 43901 * `{string}` for the url as arguments. The default is 43902 * ```js 43903 * source.setTileLoadFunction(function(tile, src) { 43904 * tile.getImage().src = src; 43905 * }); 43906 * ``` 43907 * For more fine grained control, the load function can use fetch or XMLHttpRequest and involve 43908 * error handling: 43909 * 43910 * ```js 43911 * import TileState from 'ol/TileState'; 43912 * 43913 * source.setTileLoadFunction(function(tile, src) { 43914 * const xhr = new XMLHttpRequest(); 43915 * xhr.responseType = 'blob'; 43916 * xhr.addEventListener('loadend', function (evt) { 43917 * const data = this.response; 43918 * if (data !== undefined) { 43919 * tile.getImage().src = URL.createObjectURL(data); 43920 * } else { 43921 * tile.setState(TileState.ERROR); 43922 * } 43923 * }); 43924 * xhr.addEventListener('error', function () { 43925 * tile.setState(TileState.ERROR); 43926 * }); 43927 * xhr.open('GET', src); 43928 * xhr.send(); 43929 * }); 43930 * ``` 43931 * 43932 * @typedef {function(Tile, string): void} LoadFunction 43933 * @api 43934 */ 43935 43936/** 43937 * {@link module:ol/source/Tile~TileSource} sources use a function of this type to get 43938 * the url that provides a tile for a given tile coordinate. 43939 * 43940 * This function takes an {@link module:ol/tilecoord~TileCoord} for the tile 43941 * coordinate, a `{number}` representing the pixel ratio and a 43942 * {@link module:ol/proj/Projection~Projection} for the projection as arguments 43943 * and returns a `{string}` representing the tile URL, or undefined if no tile 43944 * should be requested for the passed tile coordinate. 43945 * 43946 * @typedef {function(import("./tilecoord.js").TileCoord, number, 43947 * import("./proj/Projection.js").default): (string|undefined)} UrlFunction 43948 * @api 43949 */ 43950 43951/** 43952 * @typedef {Object} Options 43953 * @property {number} [transition=250] A duration for tile opacity 43954 * transitions in milliseconds. A duration of 0 disables the opacity transition. 43955 * @property {boolean} [interpolate=false] Use interpolated values when resampling. By default, 43956 * the nearest neighbor is used when resampling. 43957 * @api 43958 */ 43959 43960/** 43961 * @classdesc 43962 * Base class for tiles. 43963 * 43964 * @abstract 43965 */ 43966class Tile extends events_Target { 43967 /** 43968 * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate. 43969 * @param {import("./TileState.js").default} state State. 43970 * @param {Options} [options] Tile options. 43971 */ 43972 constructor(tileCoord, state, options) { 43973 super(); 43974 43975 options = options ? options : {}; 43976 43977 /** 43978 * @type {import("./tilecoord.js").TileCoord} 43979 */ 43980 this.tileCoord = tileCoord; 43981 43982 /** 43983 * @protected 43984 * @type {import("./TileState.js").default} 43985 */ 43986 this.state = state; 43987 43988 /** 43989 * An "interim" tile for this tile. The interim tile may be used while this 43990 * one is loading, for "smooth" transitions when changing params/dimensions 43991 * on the source. 43992 * @type {Tile} 43993 */ 43994 this.interimTile = null; 43995 43996 /** 43997 * A key assigned to the tile. This is used by the tile source to determine 43998 * if this tile can effectively be used, or if a new tile should be created 43999 * and this one be used as an interim tile for this new tile. 44000 * @type {string} 44001 */ 44002 this.key = ''; 44003 44004 /** 44005 * The duration for the opacity transition. 44006 * @type {number} 44007 */ 44008 this.transition_ = 44009 options.transition === undefined ? 250 : options.transition; 44010 44011 /** 44012 * Lookup of start times for rendering transitions. If the start time is 44013 * equal to -1, the transition is complete. 44014 * @type {Object<string, number>} 44015 */ 44016 this.transitionStarts_ = {}; 44017 44018 /** 44019 * @type {boolean} 44020 */ 44021 this.interpolate = !!options.interpolate; 44022 } 44023 44024 /** 44025 * @protected 44026 */ 44027 changed() { 44028 this.dispatchEvent(EventType.CHANGE); 44029 } 44030 44031 /** 44032 * Called by the tile cache when the tile is removed from the cache due to expiry 44033 */ 44034 release() { 44035 if (this.state === TileState.ERROR) { 44036 // to remove the `change` listener on this tile in `ol/TileQueue#handleTileChange` 44037 this.setState(TileState.EMPTY); 44038 } 44039 } 44040 44041 /** 44042 * @return {string} Key. 44043 */ 44044 getKey() { 44045 return this.key + '/' + this.tileCoord; 44046 } 44047 44048 /** 44049 * Get the interim tile most suitable for rendering using the chain of interim 44050 * tiles. This corresponds to the most recent tile that has been loaded, if no 44051 * such tile exists, the original tile is returned. 44052 * @return {!Tile} Best tile for rendering. 44053 */ 44054 getInterimTile() { 44055 if (!this.interimTile) { 44056 //empty chain 44057 return this; 44058 } 44059 let tile = this.interimTile; 44060 44061 // find the first loaded tile and return it. Since the chain is sorted in 44062 // decreasing order of creation time, there is no need to search the remainder 44063 // of the list (all those tiles correspond to older requests and will be 44064 // cleaned up by refreshInterimChain) 44065 do { 44066 if (tile.getState() == TileState.LOADED) { 44067 // Show tile immediately instead of fading it in after loading, because 44068 // the interim tile is in place already 44069 this.transition_ = 0; 44070 return tile; 44071 } 44072 tile = tile.interimTile; 44073 } while (tile); 44074 44075 // we can not find a better tile 44076 return this; 44077 } 44078 44079 /** 44080 * Goes through the chain of interim tiles and discards sections of the chain 44081 * that are no longer relevant. 44082 */ 44083 refreshInterimChain() { 44084 if (!this.interimTile) { 44085 return; 44086 } 44087 44088 let tile = this.interimTile; 44089 44090 /** 44091 * @type {Tile} 44092 */ 44093 let prev = this; 44094 44095 do { 44096 if (tile.getState() == TileState.LOADED) { 44097 //we have a loaded tile, we can discard the rest of the list 44098 //we would could abort any LOADING tile request 44099 //older than this tile (i.e. any LOADING tile following this entry in the chain) 44100 tile.interimTile = null; 44101 break; 44102 } else if (tile.getState() == TileState.LOADING) { 44103 //keep this LOADING tile any loaded tiles later in the chain are 44104 //older than this tile, so we're still interested in the request 44105 prev = tile; 44106 } else if (tile.getState() == TileState.IDLE) { 44107 //the head of the list is the most current tile, we don't need 44108 //to start any other requests for this chain 44109 prev.interimTile = tile.interimTile; 44110 } else { 44111 prev = tile; 44112 } 44113 tile = prev.interimTile; 44114 } while (tile); 44115 } 44116 44117 /** 44118 * Get the tile coordinate for this tile. 44119 * @return {import("./tilecoord.js").TileCoord} The tile coordinate. 44120 * @api 44121 */ 44122 getTileCoord() { 44123 return this.tileCoord; 44124 } 44125 44126 /** 44127 * @return {import("./TileState.js").default} State. 44128 */ 44129 getState() { 44130 return this.state; 44131 } 44132 44133 /** 44134 * Sets the state of this tile. If you write your own {@link module:ol/Tile~LoadFunction tileLoadFunction} , 44135 * it is important to set the state correctly to {@link module:ol/TileState~ERROR} 44136 * when the tile cannot be loaded. Otherwise the tile cannot be removed from 44137 * the tile queue and will block other requests. 44138 * @param {import("./TileState.js").default} state State. 44139 * @api 44140 */ 44141 setState(state) { 44142 if (this.state !== TileState.ERROR && this.state > state) { 44143 throw new Error('Tile load sequence violation'); 44144 } 44145 this.state = state; 44146 this.changed(); 44147 } 44148 44149 /** 44150 * Load the image or retry if loading previously failed.
44151 * Loading is taken care of by the tile queue, and calling this method is 44152 * only needed for preloading or for reloading in case of an error. 44153 * @abstract 44154 * @api 44155 */ 44156 load() { 44157 util_abstract(); 44158 } 44159 44160 /** 44161 * Get the alpha value for rendering. 44162 * @param {string} id An id for the renderer. 44163 * @param {number} time The render frame time. 44164 * @return {number} A number between 0 and 1. 44165 */ 44166 getAlpha(id, time) { 44167 if (!this.transition_) { 44168 return 1; 44169 } 44170 44171 let start = this.transitionStarts_[id]; 44172 if (!start) { 44173 start = time; 44174 this.transitionStarts_[id] = start; 44175 } else if (start === -1) { 44176 return 1; 44177 } 44178 44179 const delta = time - start + 1000 / 60; // avoid rendering at 0 44180 if (delta >= this.transition_) { 44181 return 1; 44182 } 44183 return easeIn(delta / this.transition_); 44184 } 44185 44186 /** 44187 * Determine if a tile is in an alpha transition. A tile is considered in 44188 * transition if tile.getAlpha() has not yet been called or has been called 44189 * and returned 1. 44190 * @param {string} id An id for the renderer. 44191 * @return {boolean} The tile is in transition. 44192 */ 44193 inTransition(id) { 44194 if (!this.transition_) { 44195 return false; 44196 }
44197 return this.transitionStarts_[id] !== -1; 44198 } 44199 44200 /** 44201 * Mark a transition as complete. 44202 * @param {string} id An id for the renderer. 44203 */ 44204 endTransition(id) { 44205 if (this.transition_) { 44206 this.transitionStarts_[id] = -1; 44207 } 44208 } 44209} 44210 44211/* harmony default export */ const ol_Tile = (Tile); 44212 44213;// CONCATENATED MODULE: ./node_modules/ol/ImageTile.js 44214/** 44215 * @module ol/ImageTile 44216 */ 44217 44218 44219 44220 44221 44222class ImageTile extends ol_Tile { 44223 /** 44224 * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate. 44225 * @param {import("./TileState.js").default} state State. 44226 * @param {string} src Image source URI. 44227 * @param {?string} crossOrigin Cross origin. 44228 * @param {import("./Tile.js").LoadFunction} tileLoadFunction Tile load function. 44229 * @param {import("./Tile.js").Options} [options] Tile options. 44230 */ 44231 constructor(tileCoord, state, src, crossOrigin, tileLoadFunction, options) { 44232 super(tileCoord, state, options); 44233 44234 /** 44235 * @private 44236 * @type {?string} 44237 */ 44238 this.crossOrigin_ = crossOrigin; 44239 44240 /** 44241 * Image URI 44242 * 44243 * @private 44244 * @type {string} 44245 */ 44246 this.src_ = src; 44247 44248 this.key = src; 44249 44250 /** 44251 * @private 44252 * @type {HTMLImageElement|HTMLCanvasElement} 44253 */ 44254 this.image_ = new Image(); 44255 if (crossOrigin !== null) { 44256 this.image_.crossOrigin = crossOrigin; 44257 } 44258 44259 /** 44260 * @private 44261 * @type {?function():void} 44262 */ 44263 this.unlisten_ = null; 44264 44265 /** 44266 * @private 44267 * @type {import("./Tile.js").LoadFunction} 44268 */ 44269 this.tileLoadFunction_ = tileLoadFunction; 44270 } 44271 44272 /** 44273 * Get the HTML image element for this tile (may be a Canvas, Image, or Video). 44274 * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image. 44275 * @api 44276 */ 44277 getImage() { 44278 return this.image_; 44279 } 44280 44281 /** 44282 * Sets an HTML image element for this tile (may be a Canvas or preloaded Image). 44283 * @param {HTMLCanvasElement|HTMLImageElement} element Element. 44284 */ 44285 setImage(element) { 44286 this.image_ = element; 44287 this.state = TileState.LOADED; 44288 this.unlistenImage_(); 44289 this.changed(); 44290 } 44291 44292 /** 44293 * Tracks loading or read errors. 44294 * 44295 * @private 44296 */ 44297 handleImageError_() { 44298 this.state = TileState.ERROR; 44299 this.unlistenImage_(); 44300 this.image_ = getBlankImage(); 44301 this.changed(); 44302 } 44303 44304 /** 44305 * Tracks successful image load. 44306 * 44307 * @private 44308 */ 44309 handleImageLoad_() { 44310 const image = /** @type {HTMLImageElement} */ (this.image_); 44311 if (image.naturalWidth && image.naturalHeight) { 44312 this.state = TileState.LOADED; 44313 } else { 44314 this.state = TileState.EMPTY; 44315 } 44316 this.unlistenImage_(); 44317 this.changed(); 44318 } 44319 44320 /** 44321 * Load the image or retry if loading previously failed. 44322 * Loading is taken care of by the tile queue, and calling this method is 44323 * only needed for preloading or for reloading in case of an error. 44324 * 44325 * To retry loading tiles on failed requests, use a custom `tileLoadFunction` 44326 * that checks for error status codes and reloads only when the status code is 44327 * 408, 429, 500, 502, 503 and 504, and only when not too many retries have been 44328 * made already: 44329 * 44330 * ```js 44331 * const retryCodes = [408, 429, 500, 502, 503, 504]; 44332 * const retries = {}; 44333 * source.setTileLoadFunction((tile, src) => { 44334 * const image = tile.getImage(); 44335 * fetch(src) 44336 * .then((response) => { 44337 * if (retryCodes.includes(response.status)) { 44338 * retries[src] = (retries[src] || 0) + 1; 44339 * if (retries[src] <= 3) { 44340 * setTimeout(() => tile.load(), retries[src] * 1000); 44341 * } 44342 * return Promise.reject(); 44343 * } 44344 * return response.blob(); 44345 * }) 44346 * .then((blob) => { 44347 * const imageUrl = URL.createObjectURL(blob); 44348 * image.src = imageUrl; 44349 * setTimeout(() => URL.revokeObjectURL(imageUrl), 5000); 44350 * }) 44351 * .catch(() => tile.setState(3)); // error 44352 * }); 44353 * ``` 44354 * 44355 * @api 44356 */ 44357 load() { 44358 if (this.state == TileState.ERROR) { 44359 this.state = TileState.IDLE; 44360 this.image_ = new Image(); 44361 if (this.crossOrigin_ !== null) { 44362 this.image_.crossOrigin = this.crossOrigin_; 44363 } 44364 } 44365 if (this.state == TileState.IDLE) { 44366 this.state = TileState.LOADING; 44367 this.changed(); 44368 this.tileLoadFunction_(this, this.src_); 44369 this.unlisten_ = listenImage( 44370 this.image_, 44371 this.handleImageLoad_.bind(this), 44372 this.handleImageError_.bind(this) 44373 ); 44374 } 44375 } 44376 44377 /** 44378 * Discards event handlers which listen for load completion or errors. 44379 * 44380 * @private 44381 */ 44382 unlistenImage_() { 44383 if (this.unlisten_) { 44384 this.unlisten_(); 44385 this.unlisten_ = null; 44386 } 44387 } 44388} 44389 44390/** 44391 * Get a 1-pixel blank image. 44392 * @return {HTMLCanvasElement} Blank image. 44393 */ 44394function getBlankImage() { 44395 const ctx = createCanvasContext2D(1, 1); 44396 ctx.fillStyle = 'rgba(0,0,0,0)'; 44397 ctx.fillRect(0, 0, 1, 1); 44398 return ctx.canvas; 44399} 44400 44401/* harmony default export */ const ol_ImageTile = (ImageTile); 44402 44403;// CONCATENATED MODULE: ./node_modules/ol/reproj/common.js 44404/** 44405 * @module ol/reproj/common 44406 */ 44407 44408/** 44409 * Default maximum allowed threshold (in pixels) for reprojection 44410 * triangulation. 44411 * @type {number} 44412 */ 44413const ERROR_THRESHOLD = 0.5; 44414 44415;// CONCATENATED MODULE: ./node_modules/ol/reproj/Triangulation.js 44416/** 44417 * @module ol/reproj/Triangulation 44418 */ 44419 44420 44421 44422 44423/** 44424 * Single triangle; consists of 3 source points and 3 target points. 44425 * @typedef {Object} Triangle 44426 * @property {Array<import("../coordinate.js").Coordinate>} source Source. 44427 * @property {Array<import("../coordinate.js").Coordinate>} target Target. 44428 */ 44429 44430/** 44431 * Maximum number of subdivision steps during raster reprojection triangulation. 44432 * Prevents high memory usage and large number of proj4 calls (for certain 44433 * transformations and areas). At most `2*(2^this)` triangles are created for 44434 * each triangulated extent (tile/image). 44435 * @type {number} 44436 */ 44437const MAX_SUBDIVISION = 10; 44438 44439/** 44440 * Maximum allowed size of triangle relative to world width. When transforming 44441 * corners of world extent between certain projections, the resulting 44442 * triangulation seems to have zero error and no subdivision is performed. If 44443 * the triangle width is more than this (relative to world width; 0-1), 44444 * subdivison is forced (up to `MAX_SUBDIVISION`). Default is `0.25`. 44445 * @type {number} 44446 */ 44447const MAX_TRIANGLE_WIDTH = 0.25; 44448 44449/** 44450 * @classdesc 44451 * Class containing triangulation of the given target extent. 44452 * Used for determining source data and the reprojection itself. 44453 */ 44454class Triangulation { 44455 /** 44456 * @param {import("../proj/Projection.js").default} sourceProj Source projection. 44457 * @param {import("../proj/Projection.js").default} targetProj Target projection. 44458 * @param {import("../extent.js").Extent} targetExtent Target extent to triangulate. 44459 * @param {import("../extent.js").Extent} maxSourceExtent Maximal source extent that can be used. 44460 * @param {number} errorThreshold Acceptable error (in source units). 44461 * @param {?number} destinationResolution The (optional) resolution of the destination. 44462 */ 44463 constructor( 44464 sourceProj, 44465 targetProj, 44466 targetExtent, 44467 maxSourceExtent, 44468 errorThreshold, 44469 destinationResolution 44470 ) { 44471 /** 44472 * @type {import("../proj/Projection.js").default} 44473 * @private 44474 */ 44475 this.sourceProj_ = sourceProj; 44476 44477 /** 44478 * @type {import("../proj/Projection.js").default} 44479 * @private 44480 */ 44481 this.targetProj_ = targetProj; 44482
vendor: 11,012 bytes, lines 44483-44803
44483 /** @type {!Object<string, import("../coordinate.js").Coordinate>} */ 44484 let transformInvCache = {}; 44485 const transformInv = getTransform(this.targetProj_, this.sourceProj_); 44486 44487 /** 44488 * @param {import("../coordinate.js").Coordinate} c A coordinate. 44489 * @return {import("../coordinate.js").Coordinate} Transformed coordinate. 44490 * @private 44491 */ 44492 this.transformInv_ = function (c) { 44493 const key = c[0] + '/' + c[1]; 44494 if (!transformInvCache[key]) { 44495 transformInvCache[key] = transformInv(c); 44496 } 44497 return transformInvCache[key]; 44498 }; 44499 44500 /** 44501 * @type {import("../extent.js").Extent} 44502 * @private 44503 */ 44504 this.maxSourceExtent_ = maxSourceExtent; 44505 44506 /** 44507 * @type {number} 44508 * @private 44509 */ 44510 this.errorThresholdSquared_ = errorThreshold * errorThreshold; 44511 44512 /** 44513 * @type {Array<Triangle>} 44514 * @private 44515 */ 44516 this.triangles_ = []; 44517 44518 /** 44519 * Indicates that the triangulation crosses edge of the source projection. 44520 * @type {boolean} 44521 * @private 44522 */ 44523 this.wrapsXInSource_ = false; 44524 44525 /** 44526 * @type {boolean} 44527 * @private 44528 */ 44529 this.canWrapXInSource_ = 44530 this.sourceProj_.canWrapX() && 44531 !!maxSourceExtent && 44532 !!this.sourceProj_.getExtent() && 44533 extent_getWidth(maxSourceExtent) == extent_getWidth(this.sourceProj_.getExtent()); 44534 44535 /** 44536 * @type {?number} 44537 * @private 44538 */ 44539 this.sourceWorldWidth_ = this.sourceProj_.getExtent() 44540 ? extent_getWidth(this.sourceProj_.getExtent()) 44541 : null; 44542 44543 /** 44544 * @type {?number} 44545 * @private 44546 */ 44547 this.targetWorldWidth_ = this.targetProj_.getExtent() 44548 ? extent_getWidth(this.targetProj_.getExtent()) 44549 : null; 44550 44551 const destinationTopLeft = getTopLeft(targetExtent); 44552 const destinationTopRight = getTopRight(targetExtent); 44553 const destinationBottomRight = getBottomRight(targetExtent); 44554 const destinationBottomLeft = getBottomLeft(targetExtent); 44555 const sourceTopLeft = this.transformInv_(destinationTopLeft); 44556 const sourceTopRight = this.transformInv_(destinationTopRight); 44557 const sourceBottomRight = this.transformInv_(destinationBottomRight); 44558 const sourceBottomLeft = this.transformInv_(destinationBottomLeft); 44559 44560 /* 44561 * The maxSubdivision controls how many splittings of the target area can 44562 * be done. The idea here is to do a linear mapping of the target areas 44563 * but the actual overal reprojection (can be) extremely non-linear. The 44564 * default value of MAX_SUBDIVISION was chosen based on mapping a 256x256 44565 * tile size. However this function is also called to remap canvas rendered 44566 * layers which can be much larger. This calculation increases the maxSubdivision 44567 * value by the right factor so that each 256x256 pixel area has 44568 * MAX_SUBDIVISION divisions. 44569 */ 44570 const maxSubdivision = 44571 MAX_SUBDIVISION + 44572 (destinationResolution 44573 ? Math.max( 44574 0, 44575 Math.ceil( 44576 Math.log2( 44577 getArea(targetExtent) / 44578 (destinationResolution * destinationResolution * 256 * 256) 44579 ) 44580 ) 44581 ) 44582 : 0); 44583 44584 this.addQuad_( 44585 destinationTopLeft, 44586 destinationTopRight, 44587 destinationBottomRight, 44588 destinationBottomLeft, 44589 sourceTopLeft, 44590 sourceTopRight, 44591 sourceBottomRight, 44592 sourceBottomLeft, 44593 maxSubdivision 44594 ); 44595 44596 if (this.wrapsXInSource_) { 44597 let leftBound = Infinity; 44598 this.triangles_.forEach(function (triangle, i, arr) { 44599 leftBound = Math.min( 44600 leftBound, 44601 triangle.source[0][0], 44602 triangle.source[1][0], 44603 triangle.source[2][0] 44604 ); 44605 }); 44606 44607 // Shift triangles to be as close to `leftBound` as possible 44608 // (if the distance is more than `worldWidth / 2` it can be closer. 44609 this.triangles_.forEach( 44610 function (triangle) { 44611 if ( 44612 Math.max( 44613 triangle.source[0][0], 44614 triangle.source[1][0], 44615 triangle.source[2][0] 44616 ) - 44617 leftBound > 44618 this.sourceWorldWidth_ / 2 44619 ) { 44620 const newTriangle = [ 44621 [triangle.source[0][0], triangle.source[0][1]], 44622 [triangle.source[1][0], triangle.source[1][1]], 44623 [triangle.source[2][0], triangle.source[2][1]], 44624 ]; 44625 if (newTriangle[0][0] - leftBound > this.sourceWorldWidth_ / 2) { 44626 newTriangle[0][0] -= this.sourceWorldWidth_; 44627 } 44628 if (newTriangle[1][0] - leftBound > this.sourceWorldWidth_ / 2) { 44629 newTriangle[1][0] -= this.sourceWorldWidth_; 44630 } 44631 if (newTriangle[2][0] - leftBound > this.sourceWorldWidth_ / 2) { 44632 newTriangle[2][0] -= this.sourceWorldWidth_; 44633 } 44634 44635 // Rarely (if the extent contains both the dateline and prime meridian) 44636 // the shift can in turn break some triangles. 44637 // Detect this here and don't shift in such cases. 44638 const minX = Math.min( 44639 newTriangle[0][0], 44640 newTriangle[1][0], 44641 newTriangle[2][0] 44642 ); 44643 const maxX = Math.max( 44644 newTriangle[0][0], 44645 newTriangle[1][0], 44646 newTriangle[2][0] 44647 ); 44648 if (maxX - minX < this.sourceWorldWidth_ / 2) { 44649 triangle.source = newTriangle; 44650 } 44651 } 44652 }.bind(this) 44653 ); 44654 } 44655 44656 transformInvCache = {}; 44657 } 44658 44659 /** 44660 * Adds triangle to the triangulation. 44661 * @param {import("../coordinate.js").Coordinate} a The target a coordinate. 44662 * @param {import("../coordinate.js").Coordinate} b The target b coordinate. 44663 * @param {import("../coordinate.js").Coordinate} c The target c coordinate. 44664 * @param {import("../coordinate.js").Coordinate} aSrc The source a coordinate. 44665 * @param {import("../coordinate.js").Coordinate} bSrc The source b coordinate. 44666 * @param {import("../coordinate.js").Coordinate} cSrc The source c coordinate. 44667 * @private 44668 */ 44669 addTriangle_(a, b, c, aSrc, bSrc, cSrc) { 44670 this.triangles_.push({ 44671 source: [aSrc, bSrc, cSrc], 44672 target: [a, b, c], 44673 }); 44674 } 44675 44676 /** 44677 * Adds quad (points in clock-wise order) to the triangulation 44678 * (and reprojects the vertices) if valid. 44679 * Performs quad subdivision if needed to increase precision. 44680 * 44681 * @param {import("../coordinate.js").Coordinate} a The target a coordinate. 44682 * @param {import("../coordinate.js").Coordinate} b The target b coordinate. 44683 * @param {import("../coordinate.js").Coordinate} c The target c coordinate. 44684 * @param {import("../coordinate.js").Coordinate} d The target d coordinate. 44685 * @param {import("../coordinate.js").Coordinate} aSrc The source a coordinate. 44686 * @param {import("../coordinate.js").Coordinate} bSrc The source b coordinate. 44687 * @param {import("../coordinate.js").Coordinate} cSrc The source c coordinate. 44688 * @param {import("../coordinate.js").Coordinate} dSrc The source d coordinate. 44689 * @param {number} maxSubdivision Maximal allowed subdivision of the quad. 44690 * @private 44691 */ 44692 addQuad_(a, b, c, d, aSrc, bSrc, cSrc, dSrc, maxSubdivision) { 44693 const sourceQuadExtent = boundingExtent([aSrc, bSrc, cSrc, dSrc]); 44694 const sourceCoverageX = this.sourceWorldWidth_ 44695 ? extent_getWidth(sourceQuadExtent) / this.sourceWorldWidth_ 44696 : null; 44697 const sourceWorldWidth = /** @type {number} */ (this.sourceWorldWidth_); 44698 44699 // when the quad is wrapped in the source projection 44700 // it covers most of the projection extent, but not fully 44701 const wrapsX = 44702 this.sourceProj_.canWrapX() && 44703 sourceCoverageX > 0.5 && 44704 sourceCoverageX < 1; 44705 44706 let needsSubdivision = false; 44707 44708 if (maxSubdivision > 0) { 44709 if (this.targetProj_.isGlobal() && this.targetWorldWidth_) { 44710 const targetQuadExtent = boundingExtent([a, b, c, d]); 44711 const targetCoverageX = 44712 extent_getWidth(targetQuadExtent) / this.targetWorldWidth_; 44713 needsSubdivision = 44714 targetCoverageX > MAX_TRIANGLE_WIDTH || needsSubdivision; 44715 } 44716 if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) { 44717 needsSubdivision = 44718 sourceCoverageX > MAX_TRIANGLE_WIDTH || needsSubdivision; 44719 } 44720 } 44721 44722 if (!needsSubdivision && this.maxSourceExtent_) { 44723 if ( 44724 isFinite(sourceQuadExtent[0]) && 44725 isFinite(sourceQuadExtent[1]) && 44726 isFinite(sourceQuadExtent[2]) && 44727 isFinite(sourceQuadExtent[3]) 44728 ) { 44729 if (!intersects(sourceQuadExtent, this.maxSourceExtent_)) { 44730 // whole quad outside source projection extent -> ignore 44731 return; 44732 } 44733 } 44734 } 44735 44736 let isNotFinite = 0; 44737 44738 if (!needsSubdivision) { 44739 if ( 44740 !isFinite(aSrc[0]) || 44741 !isFinite(aSrc[1]) || 44742 !isFinite(bSrc[0]) || 44743 !isFinite(bSrc[1]) || 44744 !isFinite(cSrc[0]) || 44745 !isFinite(cSrc[1]) || 44746 !isFinite(dSrc[0]) || 44747 !isFinite(dSrc[1]) 44748 ) { 44749 if (maxSubdivision > 0) { 44750 needsSubdivision = true; 44751 } else { 44752 // It might be the case that only 1 of the points is infinite. In this case 44753 // we can draw a single triangle with the other three points 44754 isNotFinite = 44755 (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) ? 8 : 0) + 44756 (!isFinite(bSrc[0]) || !isFinite(bSrc[1]) ? 4 : 0) + 44757 (!isFinite(cSrc[0]) || !isFinite(cSrc[1]) ? 2 : 0) + 44758 (!isFinite(dSrc[0]) || !isFinite(dSrc[1]) ? 1 : 0); 44759 if ( 44760 isNotFinite != 1 && 44761 isNotFinite != 2 && 44762 isNotFinite != 4 && 44763 isNotFinite != 8 44764 ) { 44765 return; 44766 } 44767 } 44768 } 44769 } 44770 44771 if (maxSubdivision > 0) { 44772 if (!needsSubdivision) { 44773 const center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2]; 44774 const centerSrc = this.transformInv_(center); 44775 44776 let dx; 44777 if (wrapsX) { 44778 const centerSrcEstimX = 44779 (math_modulo(aSrc[0], sourceWorldWidth) + 44780 math_modulo(cSrc[0], sourceWorldWidth)) / 44781 2; 44782 dx = centerSrcEstimX - math_modulo(centerSrc[0], sourceWorldWidth); 44783 } else { 44784 dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0]; 44785 } 44786 const dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1]; 44787 const centerSrcErrorSquared = dx * dx + dy * dy; 44788 needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_; 44789 } 44790 if (needsSubdivision) { 44791 if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) { 44792 // split horizontally (top & bottom) 44793 const bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2]; 44794 const bcSrc = this.transformInv_(bc); 44795 const da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2]; 44796 const daSrc = this.transformInv_(da); 44797 44798 this.addQuad_( 44799 a, 44800 b, 44801 bc, 44802 da, 44803 aSrc,
44804 bSrc, 44805 bcSrc, 44806 daSrc, 44807 maxSubdivision - 1 44808 ); 44809 this.addQuad_( 44810 da, 44811 bc, 44812 c, 44813 d, 44814 daSrc, 44815 bcSrc, 44816 cSrc, 44817 dSrc, 44818 maxSubdivision - 1 44819 ); 44820 } else { 44821 // split vertically (left & right) 44822 const ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2]; 44823 const abSrc = this.transformInv_(ab); 44824 const cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2]; 44825 const cdSrc = this.transformInv_(cd); 44826 44827 this.addQuad_( 44828 a, 44829 ab, 44830 cd, 44831 d, 44832 aSrc, 44833 abSrc, 44834 cdSrc, 44835 dSrc, 44836 maxSubdivision - 1 44837 ); 44838 this.addQuad_( 44839 ab, 44840 b, 44841 c, 44842 cd, 44843 abSrc, 44844 bSrc, 44845 cSrc, 44846 cdSrc, 44847 maxSubdivision - 1 44848 ); 44849 } 44850 return; 44851 } 44852 } 44853 44854 if (wrapsX) { 44855 if (!this.canWrapXInSource_) { 44856 return; 44857 } 44858 this.wrapsXInSource_ = true; 44859 } 44860 44861 // Exactly zero or one of *Src is not finite 44862 // The triangles must have the diagonal line as the first side 44863 // This is to allow easy code in reproj.s to make it straight for broken 44864 // browsers that can't handle diagonal clipping 44865 if ((isNotFinite & 0xb) == 0) { 44866 this.addTriangle_(a, c, d, aSrc, cSrc, dSrc); 44867 } 44868 if ((isNotFinite & 0xe) == 0) { 44869 this.addTriangle_(a, c, b, aSrc, cSrc, bSrc); 44870 } 44871 if (isNotFinite) { 44872 // Try the other two triangles 44873 if ((isNotFinite & 0xd) == 0) { 44874 this.addTriangle_(b, d, a, bSrc, dSrc, aSrc); 44875 } 44876 if ((isNotFinite & 0x7) == 0) { 44877 this.addTriangle_(b, d, c, bSrc, dSrc, cSrc); 44878 } 44879 } 44880 } 44881 44882 /** 44883 * Calculates extent of the `source` coordinates from all the triangles. 44884 * 44885 * @return {import("../extent.js").Extent} Calculated extent. 44886 */ 44887 calculateSourceExtent() { 44888 const extent = createEmpty(); 44889 44890 this.triangles_.forEach(function (triangle, i, arr) { 44891 const src = triangle.source; 44892 extendCoordinate(extent, src[0]); 44893 extendCoordinate(extent, src[1]); 44894 extendCoordinate(extent, src[2]); 44895 }); 44896 44897 return extent; 44898 } 44899 44900 /** 44901 * @return {Array<Triangle>} Array of the calculated triangles. 44902 */ 44903 getTriangles() { 44904 return this.triangles_; 44905 } 44906} 44907 44908/* harmony default export */ const reproj_Triangulation = (Triangulation); 44909 44910;// CONCATENATED MODULE: ./node_modules/ol/reproj.js 44911/** 44912 * @module ol/reproj 44913 */ 44914 44915 44916 44917 44918 44919let brokenDiagonalRendering_; 44920 44921/** 44922 * @type {Array<HTMLCanvasElement>} 44923 */ 44924const reproj_canvasPool = []; 44925 44926/** 44927 * This draws a small triangle into a canvas by setting the triangle as the clip region 44928 * and then drawing a (too large) rectangle 44929 * 44930 * @param {CanvasRenderingContext2D} ctx The context in which to draw the triangle 44931 * @param {number} u1 The x-coordinate of the second point. The first point is 0,0. 44932 * @param {number} v1 The y-coordinate of the second point. 44933 * @param {number} u2 The x-coordinate of the third point. 44934 * @param {number} v2 The y-coordinate of the third point. 44935 */ 44936function drawTestTriangle(ctx, u1, v1, u2, v2) { 44937 ctx.beginPath(); 44938 ctx.moveTo(0, 0); 44939 ctx.lineTo(u1, v1); 44940 ctx.lineTo(u2, v2); 44941 ctx.closePath(); 44942 ctx.save(); 44943 ctx.clip(); 44944 ctx.fillRect(0, 0, Math.max(u1, u2) + 1, Math.max(v1, v2)); 44945 ctx.restore(); 44946} 44947 44948/** 44949 * Given the data from getImageData, see if the right values appear at the provided offset. 44950 * Returns true if either the color or transparency is off 44951 * 44952 * @param {Uint8ClampedArray} data The data returned from getImageData 44953 * @param {number} offset The pixel offset from the start of data. 44954 * @return {boolean} true if the diagonal rendering is broken 44955 */ 44956function verifyBrokenDiagonalRendering(data, offset) { 44957 // the values ought to be close to the rgba(210, 0, 0, 0.75) 44958 return ( 44959 Math.abs(data[offset * 4] - 210) > 2 || 44960 Math.abs(data[offset * 4 + 3] - 0.75 * 255) > 2 44961 ); 44962} 44963 44964/** 44965 * Determines if the current browser configuration can render triangular clip regions correctly. 44966 * This value is cached so the function is only expensive the first time called. 44967 * Firefox on Windows (as of now) does not if HWA is enabled. See https://bugzilla.mozilla.org/show_bug.cgi?id=1606976 44968 * Chrome works, and everything seems to work on OSX and Android. This function caches the 44969 * result. I suppose that it is conceivably possible that a browser might flip modes while the app is 44970 * running, but lets hope not. 44971 * 44972 * @return {boolean} true if the Diagonal Rendering is broken. 44973 */ 44974function isBrokenDiagonalRendering() { 44975 if (brokenDiagonalRendering_ === undefined) { 44976 const ctx = document.createElement('canvas').getContext('2d'); 44977 ctx.globalCompositeOperation = 'lighter'; 44978 ctx.fillStyle = 'rgba(210, 0, 0, 0.75)'; 44979 drawTestTriangle(ctx, 4, 5, 4, 0); 44980 drawTestTriangle(ctx, 4, 5, 0, 5); 44981 const data = ctx.getImageData(0, 0, 3, 3).data; 44982 brokenDiagonalRendering_ = 44983 verifyBrokenDiagonalRendering(data, 0) || 44984 verifyBrokenDiagonalRendering(data, 4) || 44985 verifyBrokenDiagonalRendering(data, 8); 44986 } 44987 44988 return brokenDiagonalRendering_; 44989} 44990 44991/** 44992 * Calculates ideal resolution to use from the source in order to achieve 44993 * pixel mapping as close as possible to 1:1 during reprojection. 44994 * The resolution is calculated regardless of what resolutions 44995 * are actually available in the dataset (TileGrid, Image, ...). 44996 * 44997 * @param {import("./proj/Projection.js").default} sourceProj Source projection. 44998 * @param {import("./proj/Projection.js").default} targetProj Target projection. 44999 * @param {import("./coordinate.js").Coordinate} targetCenter Target center. 45000 * @param {number} targetResolution Target resolution. 45001 * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0. 45002 */ 45003function calculateSourceResolution( 45004 sourceProj, 45005 targetProj, 45006 targetCenter, 45007 targetResolution 45008) { 45009 const sourceCenter = transform(targetCenter, targetProj, sourceProj); 45010 45011 // calculate the ideal resolution of the source data 45012 let sourceResolution = getPointResolution( 45013 targetProj, 45014 targetResolution, 45015 targetCenter 45016 ); 45017 45018 const targetMetersPerUnit = targetProj.getMetersPerUnit(); 45019 if (targetMetersPerUnit !== undefined) { 45020 sourceResolution *= targetMetersPerUnit; 45021 } 45022 const sourceMetersPerUnit = sourceProj.getMetersPerUnit(); 45023 if (sourceMetersPerUnit !== undefined) { 45024 sourceResolution /= sourceMetersPerUnit; 45025 } 45026 45027 // Based on the projection properties, the point resolution at the specified 45028 // coordinates may be slightly different. We need to reverse-compensate this 45029 // in order to achieve optimal results. 45030 45031 const sourceExtent = sourceProj.getExtent(); 45032 if (!sourceExtent || containsCoordinate(sourceExtent, sourceCenter)) { 45033 const compensationFactor = 45034 getPointResolution(sourceProj, sourceResolution, sourceCenter) / 45035 sourceResolution; 45036 if (isFinite(compensationFactor) && compensationFactor > 0) { 45037 sourceResolution /= compensationFactor; 45038 } 45039 } 45040 45041 return sourceResolution; 45042} 45043 45044/** 45045 * Calculates ideal resolution to use from the source in order to achieve 45046 * pixel mapping as close as possible to 1:1 during reprojection. 45047 * The resolution is calculated regardless of what resolutions 45048 * are actually available in the dataset (TileGrid, Image, ...). 45049 * 45050 * @param {import("./proj/Projection.js").default} sourceProj Source projection. 45051 * @param {import("./proj/Projection.js").default} targetProj Target projection. 45052 * @param {import("./extent.js").Extent} targetExtent Target extent 45053 * @param {number} targetResolution Target resolution. 45054 * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0. 45055 */ 45056function calculateSourceExtentResolution( 45057 sourceProj, 45058 targetProj, 45059 targetExtent, 45060 targetResolution 45061) { 45062 const targetCenter = getCenter(targetExtent); 45063 let sourceResolution = calculateSourceResolution( 45064 sourceProj, 45065 targetProj, 45066 targetCenter, 45067 targetResolution 45068 ); 45069 45070 if (!isFinite(sourceResolution) || sourceResolution <= 0) {
45071 forEachCorner(targetExtent, function (corner) { 45072 sourceResolution = calculateSourceResolution( 45073 sourceProj, 45074 targetProj, 45075 corner, 45076 targetResolution 45077 ); 45078 return isFinite(sourceResolution) && sourceResolution > 0; 45079 }); 45080 } 45081 45082 return sourceResolution; 45083} 45084 45085/** 45086 * @typedef {Object} ImageExtent 45087 * @property {import("./extent.js").Extent} extent Extent. 45088 * @property {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image. 45089 */ 45090 45091/** 45092 * Renders the source data into new canvas based on the triangulation. 45093 * 45094 * @param {number} width Width of the canvas. 45095 * @param {number} height Height of the canvas. 45096 * @param {number} pixelRatio Pixel ratio. 45097 * @param {number} sourceResolution Source resolution. 45098 * @param {import("./extent.js").Extent} sourceExtent Extent of the data source. 45099 * @param {number} targetResolution Target resolution. 45100 * @param {import("./extent.js").Extent} targetExtent Target extent. 45101 * @param {import("./reproj/Triangulation.js").default} triangulation Calculated triangulation. 45102 * @param {Array<ImageExtent>} sources Array of sources. 45103 * @param {number} gutter Gutter of the sources. 45104 * @param {boolean} [renderEdges] Render reprojection edges. 45105 * @param {boolean} [interpolate] Use linear interpolation when resampling. 45106 * @return {HTMLCanvasElement} Canvas with reprojected data. 45107 */ 45108function render( 45109 width, 45110 height, 45111 pixelRatio, 45112 sourceResolution, 45113 sourceExtent, 45114 targetResolution, 45115 targetExtent, 45116 triangulation, 45117 sources, 45118 gutter, 45119 renderEdges, 45120 interpolate 45121) { 45122 const context = createCanvasContext2D( 45123 Math.round(pixelRatio * width), 45124 Math.round(pixelRatio * height), 45125 reproj_canvasPool 45126 ); 45127 45128 if (!interpolate) { 45129 context.imageSmoothingEnabled = false; 45130 } 45131 45132 if (sources.length === 0) { 45133 return context.canvas; 45134 } 45135 45136 context.scale(pixelRatio, pixelRatio); 45137 45138 function pixelRound(value) { 45139 return Math.round(value * pixelRatio) / pixelRatio; 45140 } 45141 45142 context.globalCompositeOperation = 'lighter'; 45143 45144 const sourceDataExtent = createEmpty(); 45145 sources.forEach(function (src, i, arr) { 45146 extent_extend(sourceDataExtent, src.extent); 45147 }); 45148 45149 const canvasWidthInUnits = extent_getWidth(sourceDataExtent); 45150 const canvasHeightInUnits = extent_getHeight(sourceDataExtent); 45151 const stitchContext = createCanvasContext2D( 45152 Math.round((pixelRatio * canvasWidthInUnits) / sourceResolution), 45153 Math.round((pixelRatio * canvasHeightInUnits) / sourceResolution) 45154 ); 45155 45156 if (!interpolate) { 45157 stitchContext.imageSmoothingEnabled = false; 45158 } 45159 45160 const stitchScale = pixelRatio / sourceResolution; 45161 45162 sources.forEach(function (src, i, arr) { 45163 const xPos = src.extent[0] - sourceDataExtent[0]; 45164 const yPos = -(src.extent[3] - sourceDataExtent[3]); 45165 const srcWidth = extent_getWidth(src.extent); 45166 const srcHeight = extent_getHeight(src.extent); 45167 45168 // This test should never fail -- but it does. Need to find a fix the upstream condition 45169 if (src.image.width > 0 && src.image.height > 0) { 45170 stitchContext.drawImage( 45171 src.image, 45172 gutter, 45173 gutter, 45174 src.image.width - 2 * gutter, 45175 src.image.height - 2 * gutter, 45176 xPos * stitchScale, 45177 yPos * stitchScale, 45178 srcWidth * stitchScale, 45179 srcHeight * stitchScale 45180 ); 45181 } 45182 }); 45183 45184 const targetTopLeft = getTopLeft(targetExtent); 45185
vendor: 3,364 bytes, lines 45186-45286
45186 triangulation.getTriangles().forEach(function (triangle, i, arr) { 45187 /* Calculate affine transform (src -> dst) 45188 * Resulting matrix can be used to transform coordinate 45189 * from `sourceProjection` to destination pixels. 45190 * 45191 * To optimize number of context calls and increase numerical stability, 45192 * we also do the following operations: 45193 * trans(-topLeftExtentCorner), scale(1 / targetResolution), scale(1, -1) 45194 * here before solving the linear system so [ui, vi] are pixel coordinates. 45195 * 45196 * Src points: xi, yi 45197 * Dst points: ui, vi 45198 * Affine coefficients: aij 45199 * 45200 * | x0 y0 1 0 0 0 | |a00| |u0| 45201 * | x1 y1 1 0 0 0 | |a01| |u1| 45202 * | x2 y2 1 0 0 0 | x |a02| = |u2| 45203 * | 0 0 0 x0 y0 1 | |a10| |v0| 45204 * | 0 0 0 x1 y1 1 | |a11| |v1| 45205 * | 0 0 0 x2 y2 1 | |a12| |v2| 45206 */ 45207 const source = triangle.source; 45208 const target = triangle.target; 45209 let x0 = source[0][0], 45210 y0 = source[0][1]; 45211 let x1 = source[1][0], 45212 y1 = source[1][1]; 45213 let x2 = source[2][0], 45214 y2 = source[2][1]; 45215 // Make sure that everything is on pixel boundaries 45216 const u0 = pixelRound((target[0][0] - targetTopLeft[0]) / targetResolution); 45217 const v0 = pixelRound( 45218 -(target[0][1] - targetTopLeft[1]) / targetResolution 45219 ); 45220 const u1 = pixelRound((target[1][0] - targetTopLeft[0]) / targetResolution); 45221 const v1 = pixelRound( 45222 -(target[1][1] - targetTopLeft[1]) / targetResolution 45223 ); 45224 const u2 = pixelRound((target[2][0] - targetTopLeft[0]) / targetResolution); 45225 const v2 = pixelRound( 45226 -(target[2][1] - targetTopLeft[1]) / targetResolution 45227 ); 45228 45229 // Shift all the source points to improve numerical stability 45230 // of all the subsequent calculations. The [x0, y0] is used here. 45231 // This is also used to simplify the linear system. 45232 const sourceNumericalShiftX = x0; 45233 const sourceNumericalShiftY = y0; 45234 x0 = 0; 45235 y0 = 0; 45236 x1 -= sourceNumericalShiftX; 45237 y1 -= sourceNumericalShiftY; 45238 x2 -= sourceNumericalShiftX; 45239 y2 -= sourceNumericalShiftY; 45240 45241 const augmentedMatrix = [ 45242 [x1, y1, 0, 0, u1 - u0], 45243 [x2, y2, 0, 0, u2 - u0], 45244 [0, 0, x1, y1, v1 - v0], 45245 [0, 0, x2, y2, v2 - v0], 45246 ]; 45247 const affineCoefs = solveLinearSystem(augmentedMatrix); 45248 if (!affineCoefs) { 45249 return; 45250 } 45251 45252 context.save(); 45253 context.beginPath(); 45254 45255 if (isBrokenDiagonalRendering() || !interpolate) { 45256 // Make sure that all lines are horizontal or vertical 45257 context.moveTo(u1, v1); 45258 // This is the diagonal line. Do it in 4 steps 45259 const steps = 4; 45260 const ud = u0 - u1; 45261 const vd = v0 - v1; 45262 for (let step = 0; step < steps; step++) { 45263 // Go horizontally 45264 context.lineTo( 45265 u1 + pixelRound(((step + 1) * ud) / steps), 45266 v1 + pixelRound((step * vd) / (steps - 1)) 45267 ); 45268 // Go vertically 45269 if (step != steps - 1) { 45270 context.lineTo( 45271 u1 + pixelRound(((step + 1) * ud) / steps), 45272 v1 + pixelRound(((step + 1) * vd) / (steps - 1)) 45273 ); 45274 } 45275 } 45276 // We are almost at u0r, v0r 45277 context.lineTo(u2, v2); 45278 } else { 45279 context.moveTo(u1, v1); 45280 context.lineTo(u0, v0); 45281 context.lineTo(u2, v2); 45282 } 45283 45284 context.clip(); 45285 45286 context.transform(
45287 affineCoefs[0], 45288 affineCoefs[2], 45289 affineCoefs[1], 45290 affineCoefs[3], 45291 u0, 45292 v0 45293 ); 45294 45295 context.translate( 45296 sourceDataExtent[0] - sourceNumericalShiftX, 45297 sourceDataExtent[3] - sourceNumericalShiftY 45298 ); 45299 45300 context.scale( 45301 sourceResolution / pixelRatio, 45302 -sourceResolution / pixelRatio 45303 ); 45304 45305 context.drawImage(stitchContext.canvas, 0, 0); 45306 context.restore(); 45307 }); 45308 45309 if (renderEdges) { 45310 context.save(); 45311 45312 context.globalCompositeOperation = 'source-over'; 45313 context.strokeStyle = 'black'; 45314 context.lineWidth = 1; 45315 45316 triangulation.getTriangles().forEach(function (triangle, i, arr) { 45317 const target = triangle.target; 45318 const u0 = (target[0][0] - targetTopLeft[0]) / targetResolution; 45319 const v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution; 45320 const u1 = (target[1][0] - targetTopLeft[0]) / targetResolution; 45321 const v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution; 45322 const u2 = (target[2][0] - targetTopLeft[0]) / targetResolution; 45323 const v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution; 45324 45325 context.beginPath(); 45326 context.moveTo(u1, v1); 45327 context.lineTo(u0, v0); 45328 context.lineTo(u2, v2); 45329 context.closePath(); 45330 context.stroke(); 45331 }); 45332 45333 context.restore(); 45334 } 45335 return context.canvas; 45336} 45337 45338;// CONCATENATED MODULE: ./node_modules/ol/reproj/Tile.js 45339/** 45340 * @module ol/reproj/Tile 45341 */ 45342 45343 45344 45345 45346 45347 45348 45349 45350 45351 45352 45353 45354/** 45355 * @typedef {function(number, number, number, number) : import("../Tile.js").default} FunctionType 45356 */ 45357 45358/** 45359 * @classdesc 45360 * Class encapsulating single reprojected tile. 45361 * See {@link module:ol/source/TileImage~TileImage}. 45362 * 45363 */ 45364class ReprojTile extends ol_Tile { 45365 /** 45366 * @param {import("../proj/Projection.js").default} sourceProj Source projection. 45367 * @param {import("../tilegrid/TileGrid.js").default} sourceTileGrid Source tile grid. 45368 * @param {import("../proj/Projection.js").default} targetProj Target projection. 45369 * @param {import("../tilegrid/TileGrid.js").default} targetTileGrid Target tile grid. 45370 * @param {import("../tilecoord.js").TileCoord} tileCoord Coordinate of the tile. 45371 * @param {import("../tilecoord.js").TileCoord} wrappedTileCoord Coordinate of the tile wrapped in X. 45372 * @param {number} pixelRatio Pixel ratio. 45373 * @param {number} gutter Gutter of the source tiles. 45374 * @param {FunctionType} getTileFunction 45375 * Function returning source tiles (z, x, y, pixelRatio). 45376 * @param {number} [errorThreshold] Acceptable reprojection error (in px). 45377 * @param {boolean} [renderEdges] Render reprojection edges. 45378 * @param {boolean} [interpolate] Use linear interpolation when resampling. 45379 */ 45380 constructor( 45381 sourceProj, 45382 sourceTileGrid, 45383 targetProj, 45384 targetTileGrid, 45385 tileCoord, 45386 wrappedTileCoord, 45387 pixelRatio, 45388 gutter, 45389 getTileFunction, 45390 errorThreshold, 45391 renderEdges, 45392 interpolate 45393 ) { 45394 super(tileCoord, TileState.IDLE, {interpolate: !!interpolate}); 45395 45396 /** 45397 * @private 45398 * @type {boolean} 45399 */ 45400 this.renderEdges_ = renderEdges !== undefined ? renderEdges : false; 45401 45402 /** 45403 * @private 45404 * @type {number} 45405 */ 45406 this.pixelRatio_ = pixelRatio; 45407 45408 /** 45409 * @private 45410 * @type {number} 45411 */ 45412 this.gutter_ = gutter; 45413 45414 /** 45415 * @private 45416 * @type {HTMLCanvasElement} 45417 */ 45418 this.canvas_ = null; 45419 45420 /** 45421 * @private 45422 * @type {import("../tilegrid/TileGrid.js").default} 45423 */ 45424 this.sourceTileGrid_ = sourceTileGrid; 45425 45426 /** 45427 * @private 45428 * @type {import("../tilegrid/TileGrid.js").default} 45429 */ 45430 this.targetTileGrid_ = targetTileGrid; 45431 45432 /** 45433 * @private 45434 * @type {import("../tilecoord.js").TileCoord} 45435 */ 45436 this.wrappedTileCoord_ = wrappedTileCoord ? wrappedTileCoord : tileCoord; 45437 45438 /** 45439 * @private 45440 * @type {!Array<import("../Tile.js").default>} 45441 */ 45442 this.sourceTiles_ = []; 45443 45444 /** 45445 * @private 45446 * @type {?Array<import("../events.js").EventsKey>} 45447 */ 45448 this.sourcesListenerKeys_ = null; 45449 45450 /** 45451 * @private 45452 * @type {number} 45453 */ 45454 this.sourceZ_ = 0; 45455 45456 const targetExtent = targetTileGrid.getTileCoordExtent( 45457 this.wrappedTileCoord_ 45458 ); 45459 const maxTargetExtent = this.targetTileGrid_.getExtent(); 45460 let maxSourceExtent = this.sourceTileGrid_.getExtent(); 45461 45462 const limitedTargetExtent = maxTargetExtent 45463 ? getIntersection(targetExtent, maxTargetExtent) 45464 : targetExtent; 45465 45466 if (getArea(limitedTargetExtent) === 0) { 45467 // Tile is completely outside range -> EMPTY 45468 // TODO: is it actually correct that the source even creates the tile ? 45469 this.state = TileState.EMPTY; 45470 return; 45471 } 45472 45473 const sourceProjExtent = sourceProj.getExtent(); 45474 if (sourceProjExtent) { 45475 if (!maxSourceExtent) { 45476 maxSourceExtent = sourceProjExtent; 45477 } else { 45478 maxSourceExtent = getIntersection(maxSourceExtent, sourceProjExtent); 45479 } 45480 } 45481 45482 const targetResolution = targetTileGrid.getResolution( 45483 this.wrappedTileCoord_[0] 45484 ); 45485 45486 const sourceResolution = calculateSourceExtentResolution( 45487 sourceProj, 45488 targetProj, 45489 limitedTargetExtent, 45490 targetResolution 45491 ); 45492 45493 if (!isFinite(sourceResolution) || sourceResolution <= 0) { 45494 // invalid sourceResolution -> EMPTY 45495 // probably edges of the projections when no extent is defined 45496 this.state = TileState.EMPTY; 45497 return; 45498 } 45499 45500 const errorThresholdInPixels = 45501 errorThreshold !== undefined ? errorThreshold : ERROR_THRESHOLD; 45502 45503 /** 45504 * @private
45505 * @type {!import("./Triangulation.js").default} 45506 */ 45507 this.triangulation_ = new reproj_Triangulation( 45508 sourceProj, 45509 targetProj, 45510 limitedTargetExtent, 45511 maxSourceExtent, 45512 sourceResolution * errorThresholdInPixels, 45513 targetResolution 45514 ); 45515 45516 if (this.triangulation_.getTriangles().length === 0) { 45517 // no valid triangles -> EMPTY 45518 this.state = TileState.EMPTY; 45519 return; 45520 } 45521 45522 this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution); 45523 let sourceExtent = this.triangulation_.calculateSourceExtent(); 45524 45525 if (maxSourceExtent) { 45526 if (sourceProj.canWrapX()) { 45527 sourceExtent[1] = math_clamp( 45528 sourceExtent[1], 45529 maxSourceExtent[1], 45530 maxSourceExtent[3] 45531 ); 45532 sourceExtent[3] = math_clamp( 45533 sourceExtent[3], 45534 maxSourceExtent[1], 45535 maxSourceExtent[3] 45536 ); 45537 } else { 45538 sourceExtent = getIntersection(sourceExtent, maxSourceExtent); 45539 } 45540 } 45541 45542 if (!getArea(sourceExtent)) { 45543 this.state = TileState.EMPTY; 45544 } else {
45545 const sourceRange = sourceTileGrid.getTileRangeForExtentAndZ( 45546 sourceExtent, 45547 this.sourceZ_ 45548 ); 45549 45550 for (let srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) { 45551 for (let srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) { 45552 const tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio); 45553 if (tile) { 45554 this.sourceTiles_.push(tile); 45555 } 45556 } 45557 } 45558 45559 if (this.sourceTiles_.length === 0) { 45560 this.state = TileState.EMPTY; 45561 } 45562 } 45563 } 45564 45565 /** 45566 * Get the HTML Canvas element for this tile. 45567 * @return {HTMLCanvasElement} Canvas. 45568 */ 45569 getImage() { 45570 return this.canvas_; 45571 } 45572 45573 /** 45574 * @private 45575 */ 45576 reproject_() { 45577 const sources = []; 45578 this.sourceTiles_.forEach( 45579 function (tile, i, arr) { 45580 if (tile && tile.getState() == TileState.LOADED) { 45581 sources.push({ 45582 extent: this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord), 45583 image: tile.getImage(), 45584 }); 45585 } 45586 }.bind(this) 45587 ); 45588 this.sourceTiles_.length = 0; 45589 45590 if (sources.length === 0) { 45591 this.state = TileState.ERROR; 45592 } else { 45593 const z = this.wrappedTileCoord_[0]; 45594 const size = this.targetTileGrid_.getTileSize(z); 45595 const width = typeof size === 'number' ? size : size[0]; 45596 const height = typeof size === 'number' ? size : size[1]; 45597 const targetResolution = this.targetTileGrid_.getResolution(z); 45598 const sourceResolution = this.sourceTileGrid_.getResolution( 45599 this.sourceZ_ 45600 ); 45601 45602 const targetExtent = this.targetTileGrid_.getTileCoordExtent( 45603 this.wrappedTileCoord_ 45604 ); 45605 45606 this.canvas_ = render( 45607 width, 45608 height, 45609 this.pixelRatio_, 45610 sourceResolution, 45611 this.sourceTileGrid_.getExtent(), 45612 targetResolution, 45613 targetExtent, 45614 this.triangulation_, 45615 sources, 45616 this.gutter_, 45617 this.renderEdges_, 45618 this.interpolate 45619 ); 45620 45621 this.state = TileState.LOADED; 45622 } 45623 this.changed(); 45624 } 45625 45626 /** 45627 * Load not yet loaded URI. 45628 */ 45629 load() { 45630 if (this.state == TileState.IDLE) { 45631 this.state = TileState.LOADING; 45632 this.changed(); 45633 45634 let leftToLoad = 0; 45635 45636 this.sourcesListenerKeys_ = []; 45637 this.sourceTiles_.forEach( 45638 function (tile, i, arr) { 45639 const state = tile.getState(); 45640 if (state == TileState.IDLE || state == TileState.LOADING) { 45641 leftToLoad++; 45642 45643 const sourceListenKey = listen( 45644 tile, 45645 EventType.CHANGE, 45646 function (e) { 45647 const state = tile.getState(); 45648 if ( 45649 state == TileState.LOADED || 45650 state == TileState.ERROR || 45651 state == TileState.EMPTY 45652 ) { 45653 unlistenByKey(sourceListenKey); 45654 leftToLoad--; 45655 if (leftToLoad === 0) { 45656 this.unlistenSources_(); 45657 this.reproject_(); 45658 } 45659 } 45660 }, 45661 this 45662 ); 45663 this.sourcesListenerKeys_.push(sourceListenKey); 45664 } 45665 }.bind(this) 45666 ); 45667 45668 if (leftToLoad === 0) { 45669 setTimeout(this.reproject_.bind(this), 0); 45670 } else { 45671 this.sourceTiles_.forEach(function (tile, i, arr) { 45672 const state = tile.getState(); 45673 if (state == TileState.IDLE) { 45674 tile.load(); 45675 } 45676 }); 45677 } 45678 } 45679 } 45680 45681 /** 45682 * @private 45683 */ 45684 unlistenSources_() { 45685 this.sourcesListenerKeys_.forEach(unlistenByKey); 45686 this.sourcesListenerKeys_ = null; 45687 } 45688 45689 /** 45690 * Remove from the cache due to expiry 45691 */ 45692 release() { 45693 if (this.canvas_) { 45694 releaseCanvas(this.canvas_.getContext('2d')); 45695 reproj_canvasPool.push(this.canvas_); 45696 this.canvas_ = null; 45697 } 45698 super.release(); 45699 } 45700} 45701 45702/* harmony default export */ const reproj_Tile = (ReprojTile); 45703 45704;// CONCATENATED MODULE: ./node_modules/ol/TileRange.js 45705/** 45706 * @module ol/TileRange 45707 */ 45708 45709/** 45710 * A representation of a contiguous block of tiles. A tile range is specified 45711 * by its min/max tile coordinates and is inclusive of coordinates. 45712 */ 45713class TileRange { 45714 /** 45715 * @param {number} minX Minimum X. 45716 * @param {number} maxX Maximum X. 45717 * @param {number} minY Minimum Y. 45718 * @param {number} maxY Maximum Y. 45719 */ 45720 constructor(minX, maxX, minY, maxY) { 45721 /** 45722 * @type {number} 45723 */ 45724 this.minX = minX; 45725 45726 /** 45727 * @type {number} 45728 */ 45729 this.maxX = maxX; 45730 45731 /** 45732 * @type {number} 45733 */ 45734 this.minY = minY; 45735 45736 /** 45737 * @type {number} 45738 */ 45739 this.maxY = maxY; 45740 } 45741 45742 /** 45743 * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate. 45744 * @return {boolean} Contains tile coordinate. 45745 */ 45746 contains(tileCoord) { 45747 return this.containsXY(tileCoord[1], tileCoord[2]); 45748 } 45749 45750 /** 45751 * @param {TileRange} tileRange Tile range. 45752 * @return {boolean} Contains. 45753 */ 45754 containsTileRange(tileRange) { 45755 return ( 45756 this.minX <= tileRange.minX && 45757 tileRange.maxX <= this.maxX && 45758 this.minY <= tileRange.minY && 45759 tileRange.maxY <= this.maxY 45760 ); 45761 } 45762 45763 /** 45764 * @param {number} x Tile coordinate x. 45765 * @param {number} y Tile coordinate y. 45766 * @return {boolean} Contains coordinate. 45767 */ 45768 containsXY(x, y) { 45769 return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY; 45770 } 45771 45772 /** 45773 * @param {TileRange} tileRange Tile range. 45774 * @return {boolean} Equals. 45775 */ 45776 equals(tileRange) { 45777 return ( 45778 this.minX == tileRange.minX && 45779 this.minY == tileRange.minY && 45780 this.maxX == tileRange.maxX && 45781 this.maxY == tileRange.maxY 45782 ); 45783 } 45784 45785 /** 45786 * @param {TileRange} tileRange Tile range. 45787 */ 45788 extend(tileRange) { 45789 if (tileRange.minX < this.minX) { 45790 this.minX = tileRange.minX; 45791 } 45792 if (tileRange.maxX > this.maxX) { 45793 this.maxX = tileRange.maxX; 45794 } 45795 if (tileRange.minY < this.minY) { 45796 this.minY = tileRange.minY; 45797 } 45798 if (tileRange.maxY > this.maxY) { 45799 this.maxY = tileRange.maxY; 45800 } 45801 } 45802 45803 /** 45804 * @return {number} Height. 45805 */ 45806 getHeight() { 45807 return this.maxY - this.minY + 1; 45808 } 45809 45810 /** 45811 * @return {import("./size.js").Size} Size. 45812 */ 45813 getSize() { 45814 return [this.getWidth(), this.getHeight()]; 45815 } 45816 45817 /** 45818 * @return {number} Width. 45819 */ 45820 getWidth() { 45821 return this.maxX - this.minX + 1; 45822 } 45823 45824 /** 45825 * @param {TileRange} tileRange Tile range. 45826 * @return {boolean} Intersects. 45827 */ 45828 intersects(tileRange) { 45829 return ( 45830 this.minX <= tileRange.maxX && 45831 this.maxX >= tileRange.minX && 45832 this.minY <= tileRange.maxY && 45833 this.maxY >= tileRange.minY 45834 ); 45835 } 45836} 45837 45838/** 45839 * @param {number} minX Minimum X. 45840 * @param {number} maxX Maximum X. 45841 * @param {number} minY Minimum Y. 45842 * @param {number} maxY Maximum Y. 45843 * @param {TileRange} [tileRange] TileRange. 45844 * @return {TileRange} Tile range. 45845 */ 45846function TileRange_createOrUpdate(minX, maxX, minY, maxY, tileRange) { 45847 if (tileRange !== undefined) { 45848 tileRange.minX = minX; 45849 tileRange.maxX = maxX; 45850 tileRange.minY = minY; 45851 tileRange.maxY = maxY; 45852 return tileRange; 45853 } else { 45854 return new TileRange(minX, maxX, minY, maxY); 45855 } 45856} 45857 45858/* harmony default export */ const ol_TileRange = (TileRange); 45859 45860;// CONCATENATED MODULE: ./node_modules/ol/renderer/canvas/TileLayer.js 45861/** 45862 * @module ol/renderer/canvas/TileLayer 45863 */ 45864 45865 45866 45867 45868 45869 45870 45871 45872 45873 45874 45875 45876/** 45877 * @classdesc 45878 * Canvas renderer for tile layers. 45879 * @api 45880 * @template {import("../../layer/Tile.js").default<import("../../source/Tile.js").default>|import("../../layer/VectorTile.js").default} [LayerType=import("../../layer/Tile.js").default<import("../../source/Tile.js").default>|import("../../layer/VectorTile.js").default] 45881 * @extends {CanvasLayerRenderer<LayerType>} 45882 */ 45883class CanvasTileLayerRenderer extends canvas_Layer { 45884 /** 45885 * @param {LayerType} tileLayer Tile layer. 45886 */ 45887 constructor(tileLayer) { 45888 super(tileLayer); 45889 45890 /**
45891 * Rendered extent has changed since the previous `renderFrame()` call 45892 * @type {boolean} 45893 */ 45894 this.extentChanged = true; 45895 45896 /** 45897 * @private 45898 * @type {?import("../../extent.js").Extent} 45899 */ 45900 this.renderedExtent_ = null; 45901 45902 /** 45903 * @protected 45904 * @type {number} 45905 */ 45906 this.renderedPixelRatio; 45907 45908 /** 45909 * @protected 45910 * @type {import("../../proj/Projection.js").default} 45911 */ 45912 this.renderedProjection = null; 45913 45914 /** 45915 * @protected 45916 * @type {number} 45917 */ 45918 this.renderedRevision; 45919 45920 /** 45921 * @protected 45922 * @type {!Array<import("../../Tile.js").default>} 45923 */ 45924 this.renderedTiles = []; 45925 45926 /** 45927 * @private 45928 * @type {boolean} 45929 */ 45930 this.newTiles_ = false; 45931 45932 /** 45933 * @protected 45934 * @type {import("../../extent.js").Extent} 45935 */ 45936 this.tmpExtent = createEmpty(); 45937 45938 /** 45939 * @private 45940 * @type {import("../../TileRange.js").default} 45941 */ 45942 this.tmpTileRange_ = new ol_TileRange(0, 0, 0, 0); 45943 } 45944 45945 /** 45946 * @protected 45947 * @param {import("../../Tile.js").default} tile Tile. 45948 * @return {boolean} Tile is drawable. 45949 */ 45950 isDrawableTile(tile) { 45951 const tileLayer = this.getLayer(); 45952 const tileState = tile.getState(); 45953 const useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); 45954 return ( 45955 tileState == TileState.LOADED || 45956 tileState == TileState.EMPTY || 45957 (tileState == TileState.ERROR && !useInterimTilesOnError) 45958 ); 45959 } 45960 45961 /** 45962 * @param {number} z Tile coordinate z. 45963 * @param {number} x Tile coordinate x. 45964 * @param {number} y Tile coordinate y. 45965 * @param {import("../../Map.js").FrameState} frameState Frame state. 45966 * @return {!import("../../Tile.js").default} Tile. 45967 */ 45968 getTile(z, x, y, frameState) { 45969 const pixelRatio = frameState.pixelRatio; 45970 const projection = frameState.viewState.projection; 45971 const tileLayer = this.getLayer(); 45972 const tileSource = tileLayer.getSource(); 45973 let tile = tileSource.getTile(z, x, y, pixelRatio, projection); 45974 if (tile.getState() == TileState.ERROR) { 45975 if (tileLayer.getUseInterimTilesOnError() && tileLayer.getPreload() > 0) { 45976 // Preloaded tiles for lower resolutions might have finished loading. 45977 this.newTiles_ = true; 45978 } 45979 } 45980 if (!this.isDrawableTile(tile)) { 45981 tile = tile.getInterimTile(); 45982 } 45983 return tile; 45984 } 45985 45986 /** 45987 * @param {import("../../pixel.js").Pixel} pixel Pixel. 45988 * @return {Uint8ClampedArray} Data at the pixel location. 45989 */ 45990 getData(pixel) { 45991 const frameState = this.frameState; 45992 if (!frameState) { 45993 return null; 45994 } 45995 45996 const layer = this.getLayer(); 45997 const coordinate = apply( 45998 frameState.pixelToCoordinateTransform, 45999 pixel.slice() 46000 ); 46001 46002 const layerExtent = layer.getExtent(); 46003 if (layerExtent) { 46004 if (!containsCoordinate(layerExtent, coordinate)) { 46005 return null; 46006 } 46007 } 46008 46009 const pixelRatio = frameState.pixelRatio; 46010 const projection = frameState.viewState.projection; 46011 const viewState = frameState.viewState; 46012 const source = layer.getRenderSource(); 46013 const tileGrid = source.getTileGridForProjection(viewState.projection); 46014 const tilePixelRatio = source.getTilePixelRatio(frameState.pixelRatio); 46015 46016 for ( 46017 let z = tileGrid.getZForResolution(viewState.resolution); 46018 z >= tileGrid.getMinZoom(); 46019 --z 46020 ) { 46021 const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z); 46022 const tile = source.getTile( 46023 z, 46024 tileCoord[1], 46025 tileCoord[2], 46026 pixelRatio, 46027 projection 46028 ); 46029 if (!(tile instanceof ol_ImageTile || tile instanceof reproj_Tile)) { 46030 return null; 46031 } 46032 46033 if (tile.getState() !== TileState.LOADED) { 46034 continue; 46035 } 46036 46037 const tileOrigin = tileGrid.getOrigin(z); 46038 const tileSize = toSize(tileGrid.getTileSize(z)); 46039 const tileResolution = tileGrid.getResolution(z); 46040 46041 const col = Math.floor( 46042 tilePixelRatio * 46043 ((coordinate[0] - tileOrigin[0]) / tileResolution - 46044 tileCoord[1] * tileSize[0]) 46045 ); 46046
46047 const row = Math.floor( 46048 tilePixelRatio * 46049 ((tileOrigin[1] - coordinate[1]) / tileResolution - 46050 tileCoord[2] * tileSize[1]) 46051 ); 46052 46053 const gutter = Math.round( 46054 tilePixelRatio * source.getGutterForProjection(viewState.projection) 46055 ); 46056 46057 return this.getImageData(tile.getImage(), col + gutter, row + gutter); 46058 } 46059 46060 return null; 46061 } 46062 46063 /** 46064 * @param {Object<number, Object<string, import("../../Tile.js").default>>} tiles Lookup of loaded tiles by zoom level. 46065 * @param {number} zoom Zoom level. 46066 * @param {import("../../Tile.js").default} tile Tile. 46067 * @return {boolean|void} If `false`, the tile will not be considered loaded. 46068 */ 46069 loadedTileCallback(tiles, zoom, tile) { 46070 if (this.isDrawableTile(tile)) { 46071 return super.loadedTileCallback(tiles, zoom, tile); 46072 } 46073 return false; 46074 } 46075 46076 /** 46077 * Determine whether render should be called. 46078 * @param {import("../../Map.js").FrameState} frameState Frame state. 46079 * @return {boolean} Layer is ready to be rendered. 46080 */ 46081 prepareFrame(frameState) { 46082 return !!this.getLayer().getSource(); 46083 } 46084 46085 /** 46086 * Render the layer. 46087 * @param {import("../../Map.js").FrameState} frameState Frame state. 46088 * @param {HTMLElement} target Target that may be used to render content to. 46089 * @return {HTMLElement} The rendered element. 46090 */ 46091 renderFrame(frameState, target) { 46092 const layerState = frameState.layerStatesArray[frameState.layerIndex]; 46093 const viewState = frameState.viewState; 46094 const projection = viewState.projection; 46095 const viewResolution = viewState.resolution; 46096 const viewCenter = viewState.center; 46097 const rotation = viewState.rotation; 46098 const pixelRatio = frameState.pixelRatio; 46099 46100 const tileLayer = this.getLayer(); 46101 const tileSource = tileLayer.getSource(); 46102 const sourceRevision = tileSource.getRevision(); 46103 const tileGrid = tileSource.getTileGridForProjection(projection); 46104 const z = tileGrid.getZForResolution(viewResolution, tileSource.zDirection); 46105 const tileResolution = tileGrid.getResolution(z); 46106 46107 let extent = frameState.extent; 46108 const resolution = frameState.viewState.resolution; 46109 const tilePixelRatio = tileSource.getTilePixelRatio(pixelRatio); 46110 // desired dimensions of the canvas in pixels 46111 const width = Math.round((extent_getWidth(extent) / resolution) * pixelRatio); 46112 const height = Math.round((extent_getHeight(extent) / resolution) * pixelRatio); 46113 46114 const layerExtent = 46115 layerState.extent && proj_fromUserExtent(layerState.extent, projection); 46116 if (layerExtent) { 46117 extent = getIntersection( 46118 extent, 46119 proj_fromUserExtent(layerState.extent, projection) 46120 ); 46121 } 46122 46123 const dx = (tileResolution * width) / 2 / tilePixelRatio; 46124 const dy = (tileResolution * height) / 2 / tilePixelRatio; 46125 const canvasExtent = [ 46126 viewCenter[0] - dx, 46127 viewCenter[1] - dy, 46128 viewCenter[0] + dx, 46129 viewCenter[1] + dy, 46130 ]; 46131 46132 const tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); 46133 46134 /** 46135 * @type {Object<number, Object<string, import("../../Tile.js").default>>} 46136 */ 46137 const tilesToDrawByZ = {}; 46138 tilesToDrawByZ[z] = {}; 46139 46140 const findLoadedTiles = this.createLoadedTileFinder( 46141 tileSource, 46142 projection, 46143 tilesToDrawByZ 46144 ); 46145 46146 const tmpExtent = this.tmpExtent; 46147 const tmpTileRange = this.tmpTileRange_; 46148 this.newTiles_ = false;
46149 const viewport = rotation 46150 ? getRotatedViewport( 46151 viewState.center, 46152 resolution, 46153 rotation, 46154 frameState.size 46155 ) 46156 : undefined; 46157 for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { 46158 for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { 46159 if ( 46160 rotation && 46161 !tileGrid.tileCoordIntersectsViewport([z, x, y], viewport) 46162 ) { 46163 continue; 46164 } 46165 const tile = this.getTile(z, x, y, frameState); 46166 if (this.isDrawableTile(tile)) { 46167 const uid = getUid(this); 46168 if (tile.getState() == TileState.LOADED) { 46169 tilesToDrawByZ[z][tile.tileCoord.toString()] = tile; 46170 let inTransition = tile.inTransition(uid); 46171 if (inTransition && layerState.opacity !== 1) { 46172 // Skipping transition when layer is not fully opaque avoids visual artifacts. 46173 tile.endTransition(uid); 46174 inTransition = false; 46175 } 46176 if ( 46177 !this.newTiles_ && 46178 (inTransition || !this.renderedTiles.includes(tile)) 46179 ) { 46180 this.newTiles_ = true; 46181 } 46182 } 46183 if (tile.getAlpha(uid, frameState.time) === 1) { 46184 // don't look for alt tiles if alpha is 1 46185 continue; 46186 } 46187 } 46188 46189 const childTileRange = tileGrid.getTileCoordChildTileRange( 46190 tile.tileCoord, 46191 tmpTileRange, 46192 tmpExtent 46193 ); 46194 46195 let covered = false; 46196 if (childTileRange) { 46197 covered = findLoadedTiles(z + 1, childTileRange); 46198 } 46199 if (!covered) { 46200 tileGrid.forEachTileCoordParentTileRange( 46201 tile.tileCoord, 46202 findLoadedTiles, 46203 tmpTileRange, 46204 tmpExtent 46205 ); 46206 } 46207 } 46208 } 46209 46210 const canvasScale = 46211 ((tileResolution / viewResolution) * pixelRatio) / tilePixelRatio; 46212 46213 // set forward and inverse pixel transforms 46214 compose( 46215 this.pixelTransform, 46216 frameState.size[0] / 2, 46217 frameState.size[1] / 2, 46218 1 / pixelRatio, 46219 1 / pixelRatio, 46220 rotation, 46221 -width / 2, 46222 -height / 2 46223 ); 46224 46225 const canvasTransform = transform_toString(this.pixelTransform); 46226 46227 this.useContainer(target, canvasTransform, this.getBackground(frameState)); 46228 const context = this.context; 46229 const canvas = context.canvas; 46230 46231 makeInverse(this.inversePixelTransform, this.pixelTransform); 46232 46233 // set scale transform for calculating tile positions on the canvas 46234 compose( 46235 this.tempTransform, 46236 width / 2, 46237 height / 2, 46238 canvasScale, 46239 canvasScale, 46240 0, 46241 -width / 2, 46242 -height / 2 46243 ); 46244 46245 if (canvas.width != width || canvas.height != height) { 46246 canvas.width = width; 46247 canvas.height = height; 46248 } else if (!this.containerReused) { 46249 context.clearRect(0, 0, width, height); 46250 } 46251 46252 if (layerExtent) { 46253 this.clipUnrotated(context, frameState, layerExtent); 46254 } 46255 46256 if (!tileSource.getInterpolate()) { 46257 context.imageSmoothingEnabled = false; 46258 } 46259 46260 this.preRender(context, frameState); 46261 46262 this.renderedTiles.length = 0; 46263 /** @type {Array<number>} */ 46264 let zs = Object.keys(tilesToDrawByZ).map(Number); 46265 zs.sort(numberSafeCompareFunction); 46266 46267 let clips, clipZs, currentClip; 46268 if ( 46269 layerState.opacity === 1 && 46270 (!this.containerReused || 46271 tileSource.getOpaque(frameState.viewState.projection)) 46272 ) { 46273 zs = zs.reverse(); 46274 } else { 46275 clips = []; 46276 clipZs = []; 46277 } 46278 for (let i = zs.length - 1; i >= 0; --i) { 46279 const currentZ = zs[i]; 46280 const currentTilePixelSize = tileSource.getTilePixelSize( 46281 currentZ, 46282 pixelRatio, 46283 projection 46284 ); 46285 const currentResolution = tileGrid.getResolution(currentZ); 46286 const currentScale = currentResolution / tileResolution; 46287 const dx = currentTilePixelSize[0] * currentScale * canvasScale; 46288 const dy = currentTilePixelSize[1] * currentScale * canvasScale; 46289 const originTileCoord = tileGrid.getTileCoordForCoordAndZ( 46290 getTopLeft(canvasExtent), 46291 currentZ 46292 ); 46293 const originTileExtent = tileGrid.getTileCoordExtent(originTileCoord); 46294 const origin = apply(this.tempTransform, [ 46295 (tilePixelRatio * (originTileExtent[0] - canvasExtent[0])) / 46296 tileResolution, 46297 (tilePixelRatio * (canvasExtent[3] - originTileExtent[3])) / 46298 tileResolution, 46299 ]); 46300 const tileGutter = 46301 tilePixelRatio * tileSource.getGutterForProjection(projection); 46302 const tilesToDraw = tilesToDrawByZ[currentZ]; 46303 for (const tileCoordKey in tilesToDraw) { 46304 const tile = /** @type {import("../../ImageTile.js").default} */ ( 46305 tilesToDraw[tileCoordKey] 46306 ); 46307 const tileCoord = tile.tileCoord; 46308 46309 // Calculate integer positions and sizes so that tiles align 46310 const xIndex = originTileCoord[1] - tileCoord[1]; 46311 const nextX = Math.round(origin[0] - (xIndex - 1) * dx); 46312 const yIndex = originTileCoord[2] - tileCoord[2]; 46313 const nextY = Math.round(origin[1] - (yIndex - 1) * dy); 46314 const x = Math.round(origin[0] - xIndex * dx); 46315 const y = Math.round(origin[1] - yIndex * dy); 46316 const w = nextX - x; 46317 const h = nextY - y; 46318 const transition = z === currentZ; 46319 46320 const inTransition = 46321 transition && tile.getAlpha(getUid(this), frameState.time) !== 1; 46322 let contextSaved = false;
46323 if (!inTransition) { 46324 if (clips) { 46325 // Clip mask for regions in this tile that already filled by a higher z tile 46326 currentClip = [x, y, x + w, y, x + w, y + h, x, y + h]; 46327 for (let i = 0, ii = clips.length; i < ii; ++i) { 46328 if (z !== currentZ && currentZ < clipZs[i]) { 46329 const clip = clips[i]; 46330 if ( 46331 intersects( 46332 [x, y, x + w, y + h], 46333 [clip[0], clip[3], clip[4], clip[7]] 46334 ) 46335 ) { 46336 if (!contextSaved) { 46337 context.save(); 46338 contextSaved = true; 46339 } 46340 context.beginPath(); 46341 // counter-clockwise (outer ring) for current tile 46342 context.moveTo(currentClip[0], currentClip[1]); 46343 context.lineTo(currentClip[2], currentClip[3]); 46344 context.lineTo(currentClip[4], currentClip[5]); 46345 context.lineTo(currentClip[6], currentClip[7]); 46346 // clockwise (inner ring) for higher z tile 46347 context.moveTo(clip[6], clip[7]); 46348 context.lineTo(clip[4], clip[5]); 46349 context.lineTo(clip[2], clip[3]); 46350 context.lineTo(clip[0], clip[1]); 46351 context.clip(); 46352 } 46353 } 46354 } 46355 clips.push(currentClip); 46356 clipZs.push(currentZ); 46357 } else { 46358 context.clearRect(x, y, w, h); 46359 } 46360 } 46361 this.drawTileImage( 46362 tile, 46363 frameState, 46364 x, 46365 y, 46366 w, 46367 h, 46368 tileGutter, 46369 transition 46370 ); 46371 if (clips && !inTransition) { 46372 if (contextSaved) { 46373 context.restore(); 46374 } 46375 this.renderedTiles.unshift(tile); 46376 } else { 46377 this.renderedTiles.push(tile); 46378 } 46379 this.updateUsedTiles(frameState.usedTiles, tileSource, tile); 46380 } 46381 } 46382 46383 this.renderedRevision = sourceRevision; 46384 this.renderedResolution = tileResolution; 46385 this.extentChanged = 46386 !this.renderedExtent_ || !extent_equals(this.renderedExtent_, canvasExtent); 46387 this.renderedExtent_ = canvasExtent; 46388 this.renderedPixelRatio = pixelRatio; 46389 this.renderedProjection = projection; 46390 46391 this.manageTilePyramid( 46392 frameState, 46393 tileSource, 46394 tileGrid, 46395 pixelRatio, 46396 projection, 46397 extent, 46398 z, 46399 tileLayer.getPreload() 46400 ); 46401 this.scheduleExpireCache(frameState, tileSource); 46402 46403 this.postRender(context, frameState); 46404 46405 if (layerState.extent) { 46406 context.restore(); 46407 } 46408 context.imageSmoothingEnabled = true; 46409 46410 if (canvasTransform !== canvas.style.transform) { 46411 canvas.style.transform = canvasTransform; 46412 } 46413 46414 return this.container; 46415 } 46416 46417 /** 46418 * @param {import("../../ImageTile.js").default} tile Tile. 46419 * @param {import("../../Map.js").FrameState} frameState Frame state. 46420 * @param {number} x Left of the tile. 46421 * @param {number} y Top of the tile. 46422 * @param {number} w Width of the tile. 46423 * @param {number} h Height of the tile. 46424 * @param {number} gutter Tile gutter. 46425 * @param {boolean} transition Apply an alpha transition. 46426 */ 46427 drawTileImage(tile, frameState, x, y, w, h, gutter, transition) { 46428 const image = this.getTileImage(tile); 46429 if (!image) { 46430 return; 46431 } 46432 const uid = getUid(this); 46433 const layerState = frameState.layerStatesArray[frameState.layerIndex]; 46434 const alpha = 46435 layerState.opacity * 46436 (transition ? tile.getAlpha(uid, frameState.time) : 1); 46437 const alphaChanged = alpha !== this.context.globalAlpha; 46438 if (alphaChanged) { 46439 this.context.save(); 46440 this.context.globalAlpha = alpha; 46441 } 46442 this.context.drawImage( 46443 image, 46444 gutter, 46445 gutter, 46446 image.width - 2 * gutter, 46447 image.height - 2 * gutter, 46448 x, 46449 y, 46450 w, 46451 h 46452 ); 46453 46454 if (alphaChanged) { 46455 this.context.restore(); 46456 } 46457 if (alpha !== layerState.opacity) { 46458 frameState.animate = true; 46459 } else if (transition) { 46460 tile.endTransition(uid); 46461 } 46462 } 46463 46464 /** 46465 * @return {HTMLCanvasElement} Image 46466 */ 46467 getImage() { 46468 const context = this.context; 46469 return context ? context.canvas : null; 46470 } 46471 46472 /** 46473 * Get the image from a tile. 46474 * @param {import("../../ImageTile.js").default} tile Tile. 46475 * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image. 46476 * @protected 46477 */ 46478 getTileImage(tile) { 46479 return tile.getImage(); 46480 } 46481 46482 /** 46483 * @param {import("../../Map.js").FrameState} frameState Frame state. 46484 * @param {import("../../source/Tile.js").default} tileSource Tile source. 46485 * @protected 46486 */ 46487 scheduleExpireCache(frameState, tileSource) { 46488 if (tileSource.canExpireCache()) { 46489 /** 46490 * @param {import("../../source/Tile.js").default} tileSource Tile source. 46491 * @param {import("../../Map.js").default} map Map. 46492 * @param {import("../../Map.js").FrameState} frameState Frame state. 46493 */ 46494 const postRenderFunction = function (tileSource, map, frameState) { 46495 const tileSourceKey = getUid(tileSource); 46496 if (tileSourceKey in frameState.usedTiles) { 46497 tileSource.expireCache( 46498 frameState.viewState.projection, 46499 frameState.usedTiles[tileSourceKey] 46500 ); 46501 } 46502 }.bind(null, tileSource); 46503 46504 frameState.postRenderFunctions.push( 46505 /** @type {import("../../Map.js").PostRenderFunction} */ ( 46506 postRenderFunction 46507 ) 46508 ); 46509 } 46510 } 46511 46512 /** 46513 * @param {!Object<string, !Object<string, boolean>>} usedTiles Used tiles. 46514 * @param {import("../../source/Tile.js").default} tileSource Tile source. 46515 * @param {import('../../Tile.js').default} tile Tile. 46516 * @protected 46517 */ 46518 updateUsedTiles(usedTiles, tileSource, tile) { 46519 // FIXME should we use tilesToDrawByZ instead? 46520 const tileSourceKey = getUid(tileSource); 46521 if (!(tileSourceKey in usedTiles)) { 46522 usedTiles[tileSourceKey] = {}; 46523 } 46524 usedTiles[tileSourceKey][tile.getKey()] = true; 46525 } 46526 46527 /** 46528 * Manage tile pyramid. 46529 * This function performs a number of functions related to the tiles at the 46530 * current zoom and lower zoom levels: 46531 * - registers idle tiles in frameState.wantedTiles so that they are not 46532 * discarded by the tile queue 46533 * - enqueues missing tiles 46534 * @param {import("../../Map.js").FrameState} frameState Frame state. 46535 * @param {import("../../source/Tile.js").default} tileSource Tile source. 46536 * @param {import("../../tilegrid/TileGrid.js").default} tileGrid Tile grid. 46537 * @param {number} pixelRatio Pixel ratio. 46538 * @param {import("../../proj/Projection.js").default} projection Projection. 46539 * @param {import("../../extent.js").Extent} extent Extent. 46540 * @param {number} currentZ Current Z. 46541 * @param {number} preload Load low resolution tiles up to `preload` levels. 46542 * @param {function(import("../../Tile.js").default):void} [tileCallback] Tile callback. 46543 * @protected 46544 */ 46545 manageTilePyramid( 46546 frameState, 46547 tileSource, 46548 tileGrid, 46549 pixelRatio, 46550 projection, 46551 extent, 46552 currentZ, 46553 preload,
46554 tileCallback 46555 ) { 46556 const tileSourceKey = getUid(tileSource); 46557 if (!(tileSourceKey in frameState.wantedTiles)) { 46558 frameState.wantedTiles[tileSourceKey] = {}; 46559 } 46560 const wantedTiles = frameState.wantedTiles[tileSourceKey]; 46561 const tileQueue = frameState.tileQueue; 46562 const minZoom = tileGrid.getMinZoom(); 46563 const rotation = frameState.viewState.rotation; 46564 const viewport = rotation 46565 ? getRotatedViewport( 46566 frameState.viewState.center, 46567 frameState.viewState.resolution, 46568 rotation, 46569 frameState.size 46570 ) 46571 : undefined; 46572 let tileCount = 0; 46573 let tile, tileRange, tileResolution, x, y, z; 46574 for (z = minZoom; z <= currentZ; ++z) { 46575 tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange); 46576 tileResolution = tileGrid.getResolution(z); 46577 for (x = tileRange.minX; x <= tileRange.maxX; ++x) { 46578 for (y = tileRange.minY; y <= tileRange.maxY; ++y) { 46579 if ( 46580 rotation && 46581 !tileGrid.tileCoordIntersectsViewport([z, x, y], viewport) 46582 ) { 46583 continue; 46584 } 46585 if (currentZ - z <= preload) { 46586 ++tileCount; 46587 tile = tileSource.getTile(z, x, y, pixelRatio, projection); 46588 if (tile.getState() == TileState.IDLE) { 46589 wantedTiles[tile.getKey()] = true; 46590 if (!tileQueue.isKeyQueued(tile.getKey())) { 46591 tileQueue.enqueue([ 46592 tile, 46593 tileSourceKey, 46594 tileGrid.getTileCoordCenter(tile.tileCoord), 46595 tileResolution, 46596 ]); 46597 } 46598 } 46599 if (tileCallback !== undefined) { 46600 tileCallback(tile); 46601 } 46602 } else { 46603 tileSource.useTile(z, x, y, projection); 46604 } 46605 } 46606 } 46607 } 46608 tileSource.updateCacheSize(tileCount, projection); 46609 } 46610} 46611 46612/* harmony default export */ const canvas_TileLayer = (CanvasTileLayerRenderer); 46613 46614;// CONCATENATED MODULE: ./node_modules/ol/layer/Tile.js 46615/** 46616 * @module ol/layer/Tile 46617 */ 46618 46619 46620 46621/** 46622 * @classdesc 46623 * For layer sources that provide pre-rendered, tiled images in grids that are 46624 * organized by zoom levels for specific resolutions. 46625 * Note that any property set in the options is set as a {@link module:ol/Object~BaseObject} 46626 * property on the layer object; for example, setting `title: 'My Title'` in the 46627 * options means that `title` is observable, and has get/set accessors. 46628 * 46629 * @template {import("../source/Tile.js").default} TileSourceType 46630 * @extends BaseTileLayer<TileSourceType, CanvasTileLayerRenderer> 46631 * @api 46632 */ 46633class TileLayer extends BaseTile { 46634 /** 46635 * @param {import("./BaseTile.js").Options<TileSourceType>} [options] Tile layer options. 46636 */ 46637 constructor(options) { 46638 super(options); 46639 } 46640 46641 createRenderer() { 46642 return new canvas_TileLayer(this); 46643 } 46644} 46645 46646/* harmony default export */ const layer_Tile = (TileLayer); 46647 46648;// CONCATENATED MODULE: ./node_modules/ol/structs/LRUCache.js 46649/** 46650 * @module ol/structs/LRUCache 46651 */ 46652 46653 46654 46655/** 46656 * @typedef {Object} Entry 46657 * @property {string} key_ Key. 46658 * @property {Object} newer Newer. 46659 * @property {Object} older Older. 46660 * @property {*} value_ Value. 46661 */ 46662 46663/** 46664 * @classdesc 46665 * Implements a Least-Recently-Used cache where the keys do not conflict with 46666 * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring 46667 * items from the cache is the responsibility of the user. 46668 * 46669 * @fires import("../events/Event.js").default 46670 * @template T 46671 */ 46672class LRUCache { 46673 /** 46674 * @param {number} [highWaterMark] High water mark. 46675 */ 46676 constructor(highWaterMark) { 46677 /** 46678 * Desired max cache size after expireCache(). If set to 0, no cache entries 46679 * will be pruned at all. 46680 * @type {number} 46681 */ 46682 this.highWaterMark = highWaterMark !== undefined ? highWaterMark : 2048; 46683 46684 /** 46685 * @private 46686 * @type {number} 46687 */ 46688 this.count_ = 0; 46689 46690 /** 46691 * @private 46692 * @type {!Object<string, Entry>} 46693 */ 46694 this.entries_ = {}; 46695 46696 /** 46697 * @private 46698 * @type {?Entry} 46699 */ 46700 this.oldest_ = null; 46701 46702 /** 46703 * @private 46704 * @type {?Entry} 46705 */ 46706 this.newest_ = null; 46707 } 46708 46709 /** 46710 * @return {boolean} Can expire cache. 46711 */ 46712 canExpireCache() { 46713 return this.highWaterMark > 0 && this.getCount() > this.highWaterMark; 46714 } 46715 46716 /** 46717 * Expire the cache. 46718 * @param {!Object<string, boolean>} [keep] Keys to keep. To be implemented by subclasses. 46719 */ 46720 expireCache(keep) { 46721 while (this.canExpireCache()) { 46722 this.pop(); 46723 } 46724 } 46725 46726 /** 46727 * FIXME empty description for jsdoc 46728 */ 46729 clear() { 46730 this.count_ = 0; 46731 this.entries_ = {}; 46732 this.oldest_ = null; 46733 this.newest_ = null; 46734 } 46735 46736 /** 46737 * @param {string} key Key. 46738 * @return {boolean} Contains key. 46739 */ 46740 containsKey(key) { 46741 return this.entries_.hasOwnProperty(key); 46742 } 46743 46744 /** 46745 * @param {function(T, string, LRUCache<T>): ?} f The function 46746 * to call for every entry from the oldest to the newer. This function takes 46747 * 3 arguments (the entry value, the entry key and the LRUCache object). 46748 * The return value is ignored. 46749 */ 46750 forEach(f) { 46751 let entry = this.oldest_; 46752 while (entry) { 46753 f(entry.value_, entry.key_, this); 46754 entry = entry.newer; 46755 } 46756 } 46757 46758 /** 46759 * @param {string} key Key. 46760 * @param {*} [options] Options (reserved for subclasses). 46761 * @return {T} Value. 46762 */ 46763 get(key, options) { 46764 const entry = this.entries_[key]; 46765 asserts_assert(entry !== undefined, 15);
46765 // Tried to get a value for a key that does not exist in the cache 46766 if (entry === this.newest_) { 46767 return entry.value_; 46768 } else if (entry === this.oldest_) { 46769 this.oldest_ = /** @type {Entry} */ (this.oldest_.newer); 46770 this.oldest_.older = null; 46771 } else { 46772 entry.newer.older = entry.older; 46773 entry.older.newer = entry.newer; 46774 } 46775 entry.newer = null; 46776 entry.older = this.newest_; 46777 this.newest_.newer = entry; 46778 this.newest_ = entry; 46779 return entry.value_; 46780 } 46781 46782 /** 46783 * Remove an entry from the cache. 46784 * @param {string} key The entry key. 46785 * @return {T} The removed entry. 46786 */ 46787 remove(key) { 46788 const entry = this.entries_[key]; 46789 asserts_assert(entry !== undefined, 15); // Tried to get a value for a key that does not exist in the cache 46790 if (entry === this.newest_) { 46791 this.newest_ = /** @type {Entry} */ (entry.older); 46792 if (this.newest_) { 46793 this.newest_.newer = null; 46794 } 46795 } else if (entry === this.oldest_) { 46796 this.oldest_ = /** @type {Entry} */ (entry.newer); 46797 if (this.oldest_) { 46798 this.oldest_.older = null; 46799 } 46800 } else { 46801 entry.newer.older = entry.older; 46802 entry.older.newer = entry.newer; 46803 } 46804 delete this.entries_[key]; 46805 --this.count_; 46806 return entry.value_; 46807 } 46808 46809 /** 46810 * @return {number} Count. 46811 */ 46812 getCount() { 46813 return this.count_; 46814 } 46815 46816 /** 46817 * @return {Array<string>} Keys. 46818 */ 46819 getKeys() { 46820 const keys = new Array(this.count_); 46821 let i = 0; 46822 let entry; 46823 for (entry = this.newest_; entry; entry = entry.older) { 46824 keys[i++] = entry.key_; 46825 } 46826 return keys; 46827 } 46828 46829 /** 46830 * @return {Array<T>} Values. 46831 */ 46832 getValues() { 46833 const values = new Array(this.count_); 46834 let i = 0; 46835 let entry; 46836 for (entry = this.newest_; entry; entry = entry.older) { 46837 values[i++] = entry.value_; 46838 } 46839 return values; 46840 } 46841 46842 /** 46843 * @return {T} Last value. 46844 */ 46845 peekLast() { 46846 return this.oldest_.value_; 46847 } 46848 46849 /** 46850 * @return {string} Last key. 46851 */ 46852 peekLastKey() { 46853 return this.oldest_.key_; 46854 } 46855 46856 /** 46857 * Get the key of the newest item in the cache. Throws if the cache is empty. 46858 * @return {string} The newest key. 46859 */ 46860 peekFirstKey() { 46861 return this.newest_.key_; 46862 } 46863 46864 /** 46865 * Return an entry without updating least recently used time. 46866 * @param {string} key Key. 46867 * @return {T} Value. 46868 */ 46869 peek(key) { 46870 if (!this.containsKey(key)) { 46871 return undefined; 46872 } 46873 return this.entries_[key].value_; 46874 } 46875 46876 /** 46877 * @return {T} value Value. 46878 */ 46879 pop() { 46880 const entry = this.oldest_; 46881 delete this.entries_[entry.key_]; 46882 if (entry.newer) { 46883 entry.newer.older = null; 46884 } 46885 this.oldest_ = /** @type {Entry} */ (entry.newer); 46886 if (!this.oldest_) { 46887 this.newest_ = null; 46888 } 46889 --this.count_; 46890 return entry.value_; 46891 } 46892 46893 /** 46894 * @param {string} key Key. 46895 * @param {T} value Value. 46896 */ 46897 replace(key, value) { 46898 this.get(key); // update `newest_` 46899 this.entries_[key].value_ = value; 46900 } 46901 46902 /** 46903 * @param {string} key Key. 46904 * @param {T} value Value. 46905 */ 46906 set(key, value) { 46907 asserts_assert(!(key in this.entries_), 16); // Tried to set a value for a key that is used already 46908 const entry = { 46909 key_: key, 46910 newer: null, 46911 older: this.newest_, 46912 value_: value, 46913 }; 46914 if (!this.newest_) { 46915 this.oldest_ = entry; 46916 } else { 46917 this.newest_.newer = entry; 46918 } 46919 this.newest_ = entry; 46920 this.entries_[key] = entry; 46921 ++this.count_; 46922 } 46923 46924 /** 46925 * Set a maximum number of entries for the cache. 46926 * @param {number} size Cache size. 46927 * @api 46928 */ 46929 setSize(size) { 46930 this.highWaterMark = size; 46931 } 46932} 46933 46934/* harmony default export */ const structs_LRUCache = (LRUCache); 46935 46936;// CONCATENATED MODULE: ./node_modules/ol/tilecoord.js 46937/** 46938 * @module ol/tilecoord 46939 */ 46940 46941/** 46942 * An array of three numbers representing the location of a tile in a tile 46943 * grid. The order is `z` (zoom level), `x` (column), and `y` (row). 46944 * @typedef {Array<number>} TileCoord 46945 * @api 46946 */ 46947 46948/** 46949 * @param {number} z Z. 46950 * @param {number} x X. 46951 * @param {number} y Y. 46952 * @param {TileCoord} [tileCoord] Tile coordinate. 46953 * @return {TileCoord} Tile coordinate. 46954 */ 46955function tilecoord_createOrUpdate(z, x, y, tileCoord) { 46956 if (tileCoord !== undefined) { 46957 tileCoord[0] = z; 46958 tileCoord[1] = x; 46959 tileCoord[2] = y; 46960 return tileCoord; 46961 } else { 46962 return [z, x, y]; 46963 } 46964} 46965 46966/** 46967 * @param {number} z Z. 46968 * @param {number} x X. 46969 * @param {number} y Y. 46970 * @return {string} Key. 46971 */ 46972function getKeyZXY(z, x, y) { 46973 return z + '/' + x + '/' + y; 46974} 46975 46976/** 46977 * Get the key for a tile coord. 46978 * @param {TileCoord} tileCoord The tile coord. 46979 * @return {string} Key. 46980 */ 46981function tilecoord_getKey(tileCoord) { 46982 return getKeyZXY(tileCoord[0], tileCoord[1], tileCoord[2]); 46983} 46984 46985/** 46986 * Get the tile cache key for a tile key obtained through `tile.getKey()`. 46987 * @param {string} tileKey The tile key. 46988 * @return {string} The cache key. 46989 */ 46990function getCacheKeyForTileKey(tileKey) { 46991 const [z, x, y] = tileKey 46992 .substring(tileKey.lastIndexOf('/') + 1, tileKey.length) 46993 .split(',') 46994 .map(Number); 46995 return getKeyZXY(z, x, y); 46996} 46997 46998/** 46999 * Get a tile coord given a key. 47000 * @param {string} key The tile coord key. 47001 * @return {TileCoord} The tile coord. 47002 */ 47003function fromKey(key) { 47004 return key.split('/').map(Number); 47005} 47006 47007/** 47008 * @param {TileCoord} tileCoord Tile coord. 47009 * @return {number} Hash. 47010 */ 47011function hash(tileCoord) { 47012 return (tileCoord[1] << tileCoord[0]) + tileCoord[2]; 47013} 47014 47015/** 47016 * @param {TileCoord} tileCoord Tile coordinate. 47017 * @param {!import("./tilegrid/TileGrid.js").default} tileGrid Tile grid. 47018 * @return {boolean} Tile coordinate is within extent and zoom level range. 47019 */ 47020function withinExtentAndZ(tileCoord, tileGrid) { 47021 const z = tileCoord[0]; 47022 const x = tileCoord[1]; 47023 const y = tileCoord[2]; 47024 47025 if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) { 47026 return false;
47027 } 47028 const tileRange = tileGrid.getFullTileRange(z); 47029 if (!tileRange) { 47030 return true; 47031 } else { 47032 return tileRange.containsXY(x, y); 47033 } 47034} 47035 47036;// CONCATENATED MODULE: ./node_modules/ol/TileCache.js 47037/** 47038 * @module ol/TileCache 47039 */ 47040 47041 47042 47043class TileCache extends structs_LRUCache { 47044 clear() { 47045 while (this.getCount() > 0) { 47046 this.pop().release(); 47047 } 47048 super.clear(); 47049 } 47050 47051 /** 47052 * @param {!Object<string, boolean>} usedTiles Used tiles. 47053 */ 47054 expireCache(usedTiles) { 47055 while (this.canExpireCache()) { 47056 const tile = this.peekLast(); 47057 if (tile.getKey() in usedTiles) { 47058 break; 47059 } else { 47060 this.pop().release(); 47061 } 47062 } 47063 } 47064 47065 /** 47066 * Prune all tiles from the cache that don't have the same z as the newest tile. 47067 */ 47068 pruneExceptNewestZ() { 47069 if (this.getCount() === 0) { 47070 return; 47071 } 47072 const key = this.peekFirstKey(); 47073 const tileCoord = fromKey(key); 47074 const z = tileCoord[0]; 47075 this.forEach( 47076 function (tile) { 47077 if (tile.tileCoord[0] !== z) { 47078 this.remove(tilecoord_getKey(tile.tileCoord)); 47079 tile.release(); 47080 } 47081 }.bind(this) 47082 ); 47083 } 47084} 47085 47086/* harmony default export */ const ol_TileCache = (TileCache); 47087 47088;// CONCATENATED MODULE: ./node_modules/ol/source/TileEventType.js 47089/** 47090 * @module ol/source/TileEventType 47091 */ 47092 47093/** 47094 * @enum {string} 47095 */ 47096/* harmony default export */ const TileEventType = ({ 47097 /** 47098 * Triggered when a tile starts loading. 47099 * @event module:ol/source/Tile.TileSourceEvent#tileloadstart 47100 * @api 47101 */ 47102 TILELOADSTART: 'tileloadstart', 47103 47104 /** 47105 * Triggered when a tile finishes loading, either when its data is loaded, 47106 * or when loading was aborted because the tile is no longer needed. 47107 * @event module:ol/source/Tile.TileSourceEvent#tileloadend 47108 * @api 47109 */ 47110 TILELOADEND: 'tileloadend', 47111 47112 /** 47113 * Triggered if tile loading results in an error. Note that this is not the 47114 * right place to re-fetch tiles. See {@link module:ol/ImageTile~ImageTile#load} 47115 * for details. 47116 * @event module:ol/source/Tile.TileSourceEvent#tileloaderror 47117 * @api 47118 */ 47119 TILELOADERROR: 'tileloaderror', 47120}); 47121 47122/** 47123 * @typedef {'tileloadstart'|'tileloadend'|'tileloaderror'} TileSourceEventTypes 47124 */ 47125 47126;// CONCATENATED MODULE: ./node_modules/ol/source/Source.js 47127/** 47128 * @module ol/source/Source 47129 */ 47130 47131 47132 47133 47134/** 47135 * @typedef {'undefined' | 'loading' | 'ready' | 'error'} State 47136 * State of the source, one of 'undefined', 'loading', 'ready' or 'error'. 47137 */ 47138 47139/** 47140 * A function that takes a {@link module:ol/Map~FrameState} and returns a string or 47141 * an array of strings representing source attributions. 47142 * 47143 * @typedef {function(import("../Map.js").FrameState): (string|Array<string>)} Attribution 47144 */ 47145 47146/** 47147 * A type that can be used to provide attribution information for data sources. 47148 * 47149 * It represents either 47150 * * a simple string (e.g. `'© Acme Inc.'`) 47151 * * an array of simple strings (e.g. `['© Acme Inc.', '© Bacme Inc.']`) 47152 * * a function that returns a string or array of strings ({@link module:ol/source/Source~Attribution}) 47153 * 47154 * @typedef {string|Array<string>|Attribution} AttributionLike 47155 */ 47156 47157/** 47158 * @typedef {Object} Options 47159 * @property {AttributionLike} [attributions] Attributions. 47160 * @property {boolean} [attributionsCollapsible=true] Attributions are collapsible. 47161 * @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection. 47162 * @property {import("./Source.js").State} [state='ready'] State. 47163 * @property {boolean} [wrapX=false] WrapX. 47164 * @property {boolean} [interpolate=false] Use interpolated values when resampling. By default, 47165 * the nearest neighbor is used when resampling. 47166 */ 47167 47168/** 47169 * @classdesc 47170 * Abstract base class; normally only used for creating subclasses and not 47171 * instantiated in apps. 47172 * Base class for {@link module:ol/layer/Layer~Layer} sources. 47173 * 47174 * A generic `change` event is triggered when the state of the source changes. 47175 * @abstract 47176 * @api 47177 */ 47178class Source extends ol_Object { 47179 /** 47180 * @param {Options} options Source options. 47181 */ 47182 constructor(options) { 47183 super(); 47184 47185 /** 47186 * @protected 47187 * @type {import("../proj/Projection.js").default|null} 47188 */ 47189 this.projection = proj_get(options.projection); 47190 47191 /** 47192 * @private 47193 * @type {?Attribution} 47194 */ 47195 this.attributions_ = adaptAttributions(options.attributions); 47196 47197 /** 47198 * @private 47199 * @type {boolean} 47200 */ 47201 this.attributionsCollapsible_ = 47202 options.attributionsCollapsible !== undefined 47203 ? options.attributionsCollapsible 47204 : true; 47205 47206 /** 47207 * This source is currently loading data. Sources that defer loading to the 47208 * map's tile queue never set this to `true`. 47209 * @type {boolean} 47210 */ 47211 this.loading = false;
47212 47213 /** 47214 * @private 47215 * @type {import("./Source.js").State} 47216 */ 47217 this.state_ = options.state !== undefined ? options.state : 'ready'; 47218 47219 /** 47220 * @private 47221 * @type {boolean} 47222 */ 47223 this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false; 47224 47225 /** 47226 * @private 47227 * @type {boolean} 47228 */ 47229 this.interpolate_ = !!options.interpolate; 47230 47231 /** 47232 * @protected 47233 * @type {function(import("../View.js").ViewOptions):void} 47234 */ 47235 this.viewResolver = null; 47236 47237 /** 47238 * @protected 47239 * @type {function(Error):void} 47240 */ 47241 this.viewRejector = null; 47242 47243 const self = this; 47244 /** 47245 * @private 47246 * @type {Promise<import("../View.js").ViewOptions>} 47247 */ 47248 this.viewPromise_ = new Promise(function (resolve, reject) { 47249 self.viewResolver = resolve; 47250 self.viewRejector = reject; 47251 }); 47252 } 47253 47254 /** 47255 * Get the attribution function for the source. 47256 * @return {?Attribution} Attribution function. 47257 * @api 47258 */ 47259 getAttributions() { 47260 return this.attributions_; 47261 } 47262 47263 /** 47264 * @return {boolean} Attributions are collapsible. 47265 * @api 47266 */ 47267 getAttributionsCollapsible() { 47268 return this.attributionsCollapsible_; 47269 } 47270 47271 /** 47272 * Get the projection of the source. 47273 * @return {import("../proj/Projection.js").default|null} Projection. 47274 * @api 47275 */ 47276 getProjection() { 47277 return this.projection; 47278 } 47279 47280 /** 47281 * @abstract 47282 * @return {Array<number>|null} Resolutions. 47283 */ 47284 getResolutions() { 47285 return util_abstract(); 47286 } 47287 47288 /** 47289 * @return {Promise<import("../View.js").ViewOptions>} A promise for view-related properties. 47290 */ 47291 getView() { 47292 return this.viewPromise_; 47293 } 47294 47295 /** 47296 * Get the state of the source, see {@link import("./Source.js").State} for possible states. 47297 * @return {import("./Source.js").State} State. 47298 * @api 47299 */ 47300 getState() { 47301 return this.state_; 47302 } 47303 47304 /** 47305 * @return {boolean|undefined} Wrap X. 47306 */ 47307 getWrapX() { 47308 return this.wrapX_; 47309 } 47310 47311 /** 47312 * @return {boolean} Use linear interpolation when resampling. 47313 */ 47314 getInterpolate() { 47315 return this.interpolate_; 47316 } 47317 47318 /** 47319 * Refreshes the source. The source will be cleared, and data from the server will be reloaded. 47320 * @api 47321 */ 47322 refresh() { 47323 this.changed(); 47324 } 47325 47326 /** 47327 * Set the attributions of the source. 47328 * @param {AttributionLike|undefined} attributions Attributions. 47329 * Can be passed as `string`, `Array<string>`, {@link module:ol/source/Source~Attribution}, 47330 * or `undefined`. 47331 * @api 47332 */ 47333 setAttributions(attributions) { 47334 this.attributions_ = adaptAttributions(attributions); 47335 this.changed(); 47336 } 47337 47338 /** 47339 * Set the state of the source. 47340 * @param {import("./Source.js").State} state State. 47341 */ 47342 setState(state) { 47343 this.state_ = state; 47344 this.changed(); 47345 } 47346} 47347 47348/** 47349 * Turns the attributions option into an attributions function. 47350 * @param {AttributionLike|undefined} attributionLike The attribution option. 47351 * @return {Attribution|null} An attribution function (or null). 47352 */ 47353function adaptAttributions(attributionLike) { 47354 if (!attributionLike) { 47355 return null; 47356 } 47357 if (Array.isArray(attributionLike)) { 47358 return function (frameState) { 47359 return attributionLike; 47360 }; 47361 } 47362 47363 if (typeof attributionLike === 'function') { 47364 return attributionLike; 47365 } 47366 47367 return function (frameState) { 47368 return [attributionLike]; 47369 }; 47370} 47371 47372/* harmony default export */ const source_Source = (Source); 47373 47374;// CONCATENATED MODULE: ./node_modules/ol/tilegrid/TileGrid.js 47375/** 47376 * @module ol/tilegrid/TileGrid 47377 */ 47378 47379 47380 47381 47382 47383 47384 47385 47386 47387 47388/** 47389 * @private 47390 * @type {import("../tilecoord.js").TileCoord} 47391 */ 47392const tmpTileCoord = [0, 0, 0]; 47393 47394/** 47395 * Number of decimal digits to consider in integer values when rounding. 47396 * @type {number} 47397 */ 47398const DECIMALS = 5; 47399 47400/** 47401 * @typedef {Object} Options 47402 * @property {import("../extent.js").Extent} [extent] Extent for the tile grid. No tiles outside this 47403 * extent will be requested by {@link module:ol/source/Tile~TileSource} sources. When no `origin` or 47404 * `origins` are configured, the `origin` will be set to the top-left corner of the extent. 47405 * @property {number} [minZoom=0] Minimum zoom. 47406 * @property {import("../coordinate.js").Coordinate} [origin] The tile grid origin, i.e. where the `x` 47407 * and `y` axes meet (`[z, 0, 0]`). Tile coordinates increase left to right and downwards. If not 47408 * specified, `extent` or `origins` must be provided. 47409 * @property {Array<import("../coordinate.js").Coordinate>} [origins] Tile grid origins, i.e. where 47410 * the `x` and `y` axes meet (`[z, 0, 0]`), for each zoom level. If given, the array length 47411 * should match the length of the `resolutions` array, i.e. each resolution can have a different 47412 * origin. Tile coordinates increase left to right and downwards. If not specified, `extent` or 47413 * `origin` must be provided. 47414 * @property {!Array<number>} resolutions Resolutions. The array index of each resolution needs 47415 * to match the zoom level. This means that even if a `minZoom` is configured, the resolutions 47416 * array will have a length of `maxZoom + 1`. 47417 * @property {Array<import("../size.js").Size>} [sizes] Number of tile rows and columns 47418 * of the grid for each zoom level. If specified the values 47419 * define each zoom level's extent together with the `origin` or `origins`. 47420 * A grid `extent` can be configured in addition, and will further limit the extent 47421 * for which tile requests are made by sources. If the bottom-left corner of 47422 * an extent is used as `origin` or `origins`, then the `y` value must be 47423 * negative because OpenLayers tile coordinates use the top left as the origin. 47424 * @property {number|import("../size.js").Size} [tileSize] Tile size. 47425 * Default is `[256, 256]`. 47426 * @property {Array<number|import("../size.js").Size>} [tileSizes] Tile sizes. If given, the array length 47427 * should match the length of the `resolutions` array, i.e. each resolution can have a different 47428 * tile size. 47429 */ 47430 47431/** 47432 * @classdesc 47433 * Base class for setting the grid pattern for sources accessing tiled-image 47434 * servers. 47435 * @api 47436 */ 47437class TileGrid { 47438 /** 47439 * @param {Options} options Tile grid options. 47440 */ 47441 constructor(options) { 47442 /** 47443 * @protected 47444 * @type {number} 47445 */ 47446 this.minZoom = options.minZoom !== undefined ? options.minZoom : 0; 47447 47448 /** 47449 * @private
47450 * @type {!Array<number>} 47451 */ 47452 this.resolutions_ = options.resolutions; 47453 asserts_assert( 47454 isSorted( 47455 this.resolutions_, 47456 function (a, b) { 47457 return b - a; 47458 }, 47459 true 47460 ), 47461 17 47462 ); // `resolutions` must be sorted in descending order 47463 47464 // check if we've got a consistent zoom factor and origin 47465 let zoomFactor; 47466 if (!options.origins) { 47467 for (let i = 0, ii = this.resolutions_.length - 1; i < ii; ++i) { 47468 if (!zoomFactor) { 47469 zoomFactor = this.resolutions_[i] / this.resolutions_[i + 1]; 47470 } else { 47471 if (this.resolutions_[i] / this.resolutions_[i + 1] !== zoomFactor) { 47472 zoomFactor = undefined; 47473 break; 47474 } 47475 } 47476 } 47477 } 47478 47479 /** 47480 * @private 47481 * @type {number|undefined} 47482 */ 47483 this.zoomFactor_ = zoomFactor; 47484 47485 /** 47486 * @protected 47487 * @type {number} 47488 */ 47489 this.maxZoom = this.resolutions_.length - 1; 47490 47491 /** 47492 * @private 47493 * @type {import("../coordinate.js").Coordinate|null} 47494 */ 47495 this.origin_ = options.origin !== undefined ? options.origin : null; 47496 47497 /** 47498 * @private 47499 * @type {Array<import("../coordinate.js").Coordinate>} 47500 */ 47501 this.origins_ = null; 47502 if (options.origins !== undefined) { 47503 this.origins_ = options.origins; 47504 asserts_assert(this.origins_.length == this.resolutions_.length, 20); // Number of `origins` and `resolutions` must be equal 47505 } 47506 47507 const extent = options.extent; 47508 47509 if (extent !== undefined && !this.origin_ && !this.origins_) { 47510 this.origin_ = getTopLeft(extent); 47511 } 47512 47513 asserts_assert( 47514 (!this.origin_ && this.origins_) || (this.origin_ && !this.origins_), 47515 18 47516 ); // Either `origin` or `origins` must be configured, never both 47517 47518 /** 47519 * @private 47520 * @type {Array<number|import("../size.js").Size>} 47521 */ 47522 this.tileSizes_ = null; 47523 if (options.tileSizes !== undefined) { 47524 this.tileSizes_ = options.tileSizes; 47525 asserts_assert(this.tileSizes_.length == this.resolutions_.length, 19); // Number of `tileSizes` and `resolutions` must be equal 47526 } 47527 47528 /** 47529 * @private 47530 * @type {number|import("../size.js").Size} 47531 */ 47532 this.tileSize_ = 47533 options.tileSize !== undefined 47534 ? options.tileSize 47535 : !this.tileSizes_ 47536 ? DEFAULT_TILE_SIZE 47537 : null; 47538 asserts_assert( 47539 (!this.tileSize_ && this.tileSizes_) || 47540 (this.tileSize_ && !this.tileSizes_), 47541 22 47542 ); // Either `tileSize` or `tileSizes` must be configured, never both 47543 47544 /** 47545 * @private 47546 * @type {import("../extent.js").Extent} 47547 */ 47548 this.extent_ = extent !== undefined ? extent : null; 47549 47550 /** 47551 * @private 47552 * @type {Array<import("../TileRange.js").default>} 47553 */ 47554 this.fullTileRanges_ = null; 47555 47556 /** 47557 * @private 47558 * @type {import("../size.js").Size} 47559 */ 47560 this.tmpSize_ = [0, 0]; 47561 47562 /** 47563 * @private 47564 * @type {import("../extent.js").Extent} 47565 */ 47566 this.tmpExtent_ = [0, 0, 0, 0]; 47567 47568 if (options.sizes !== undefined) { 47569 this.fullTileRanges_ = options.sizes.map(function (size, z) { 47570 const tileRange = new ol_TileRange( 47571 Math.min(0, size[0]), 47572 Math.max(size[0] - 1, -1), 47573 Math.min(0, size[1]), 47574 Math.max(size[1] - 1, -1) 47575 ); 47576 if (extent) { 47577 const restrictedTileRange = this.getTileRangeForExtentAndZ(extent, z); 47578 tileRange.minX = Math.max(restrictedTileRange.minX, tileRange.minX); 47579 tileRange.maxX = Math.min(restrictedTileRange.maxX, tileRange.maxX); 47580 tileRange.minY = Math.max(restrictedTileRange.minY, tileRange.minY); 47581 tileRange.maxY = Math.min(restrictedTileRange.maxY, tileRange.maxY); 47582 } 47583 return tileRange; 47584 }, this); 47585 } else if (extent) { 47586 this.calculateTileRanges_(extent); 47587 } 47588 } 47589 47590 /** 47591 * Call a function with each tile coordinate for a given extent and zoom level. 47592 * 47593 * @param {import("../extent.js").Extent} extent Extent. 47594 * @param {number} zoom Integer zoom level. 47595 * @param {function(import("../tilecoord.js").TileCoord): void} callback Function called with each tile coordinate. 47596 * @api 47597 */ 47598 forEachTileCoord(extent, zoom, callback) { 47599 const tileRange = this.getTileRangeForExtentAndZ(extent, zoom); 47600 for (let i = tileRange.minX, ii = tileRange.maxX;
vendor: 16,384 bytes, lines 47600-48098
47600 i <= ii; ++i) { 47601 for (let j = tileRange.minY, jj = tileRange.maxY; j <= jj; ++j) { 47602 callback([zoom, i, j]); 47603 } 47604 } 47605 } 47606 47607 /** 47608 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 47609 * @param {function(number, import("../TileRange.js").default): boolean} callback Callback. 47610 * @param {import("../TileRange.js").default} [tempTileRange] Temporary import("../TileRange.js").default object. 47611 * @param {import("../extent.js").Extent} [tempExtent] Temporary import("../extent.js").Extent object. 47612 * @return {boolean} Callback succeeded. 47613 */ 47614 forEachTileCoordParentTileRange( 47615 tileCoord, 47616 callback, 47617 tempTileRange, 47618 tempExtent 47619 ) { 47620 let tileRange, x, y; 47621 let tileCoordExtent = null; 47622 let z = tileCoord[0] - 1; 47623 if (this.zoomFactor_ === 2) { 47624 x = tileCoord[1]; 47625 y = tileCoord[2]; 47626 } else { 47627 tileCoordExtent = this.getTileCoordExtent(tileCoord, tempExtent); 47628 } 47629 while (z >= this.minZoom) { 47630 if (this.zoomFactor_ === 2) { 47631 x = Math.floor(x / 2); 47632 y = Math.floor(y / 2); 47633 tileRange = TileRange_createOrUpdate(x, x, y, y, tempTileRange); 47634 } else { 47635 tileRange = this.getTileRangeForExtentAndZ( 47636 tileCoordExtent, 47637 z, 47638 tempTileRange 47639 ); 47640 } 47641 if (callback(z, tileRange)) { 47642 return true; 47643 } 47644 --z; 47645 } 47646 return false; 47647 } 47648 47649 /** 47650 * Get the extent for this tile grid, if it was configured. 47651 * @return {import("../extent.js").Extent} Extent. 47652 * @api 47653 */ 47654 getExtent() { 47655 return this.extent_; 47656 } 47657 47658 /** 47659 * Get the maximum zoom level for the grid. 47660 * @return {number} Max zoom. 47661 * @api 47662 */ 47663 getMaxZoom() { 47664 return this.maxZoom; 47665 } 47666 47667 /** 47668 * Get the minimum zoom level for the grid. 47669 * @return {number} Min zoom. 47670 * @api 47671 */ 47672 getMinZoom() { 47673 return this.minZoom; 47674 } 47675 47676 /** 47677 * Get the origin for the grid at the given zoom level. 47678 * @param {number} z Integer zoom level. 47679 * @return {import("../coordinate.js").Coordinate} Origin. 47680 * @api 47681 */ 47682 getOrigin(z) { 47683 if (this.origin_) { 47684 return this.origin_; 47685 } else { 47686 return this.origins_[z]; 47687 } 47688 } 47689 47690 /** 47691 * Get the resolution for the given zoom level. 47692 * @param {number} z Integer zoom level. 47693 * @return {number} Resolution. 47694 * @api 47695 */ 47696 getResolution(z) { 47697 return this.resolutions_[z]; 47698 } 47699 47700 /** 47701 * Get the list of resolutions for the tile grid. 47702 * @return {Array<number>} Resolutions. 47703 * @api 47704 */ 47705 getResolutions() { 47706 return this.resolutions_; 47707 } 47708 47709 /** 47710 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 47711 * @param {import("../TileRange.js").default} [tempTileRange] Temporary import("../TileRange.js").default object. 47712 * @param {import("../extent.js").Extent} [tempExtent] Temporary import("../extent.js").Extent object. 47713 * @return {import("../TileRange.js").default|null} Tile range. 47714 */ 47715 getTileCoordChildTileRange(tileCoord, tempTileRange, tempExtent) { 47716 if (tileCoord[0] < this.maxZoom) { 47717 if (this.zoomFactor_ === 2) { 47718 const minX = tileCoord[1] * 2; 47719 const minY = tileCoord[2] * 2; 47720 return TileRange_createOrUpdate( 47721 minX, 47722 minX + 1, 47723 minY, 47724 minY + 1, 47725 tempTileRange 47726 ); 47727 } 47728 const tileCoordExtent = this.getTileCoordExtent( 47729 tileCoord, 47730 tempExtent || this.tmpExtent_ 47731 ); 47732 return this.getTileRangeForExtentAndZ( 47733 tileCoordExtent, 47734 tileCoord[0] + 1, 47735 tempTileRange 47736 ); 47737 } 47738 return null; 47739 } 47740 47741 /** 47742 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 47743 * @param {number} z Integer zoom level. 47744 * @param {import("../TileRange.js").default} [tempTileRange] Temporary import("../TileRange.js").default object. 47745 * @return {import("../TileRange.js").default|null} Tile range. 47746 */ 47747 getTileRangeForTileCoordAndZ(tileCoord, z, tempTileRange) { 47748 if (z > this.maxZoom || z < this.minZoom) { 47749 return null; 47750 } 47751 47752 const tileCoordZ = tileCoord[0]; 47753 const tileCoordX = tileCoord[1]; 47754 const tileCoordY = tileCoord[2]; 47755 47756 if (z === tileCoordZ) { 47757 return TileRange_createOrUpdate( 47758 tileCoordX, 47759 tileCoordY, 47760 tileCoordX, 47761 tileCoordY, 47762 tempTileRange 47763 ); 47764 } 47765 47766 if (this.zoomFactor_) { 47767 const factor = Math.pow(this.zoomFactor_, z - tileCoordZ); 47768 const minX = Math.floor(tileCoordX * factor); 47769 const minY = Math.floor(tileCoordY * factor); 47770 if (z < tileCoordZ) { 47771 return TileRange_createOrUpdate(minX, minX, minY, minY, tempTileRange); 47772 } 47773 47774 const maxX = Math.floor(factor * (tileCoordX + 1)) - 1; 47775 const maxY = Math.floor(factor * (tileCoordY + 1)) - 1; 47776 return TileRange_createOrUpdate(minX, maxX, minY, maxY, tempTileRange); 47777 } 47778 47779 const tileCoordExtent = this.getTileCoordExtent(tileCoord, this.tmpExtent_); 47780 return this.getTileRangeForExtentAndZ(tileCoordExtent, z, tempTileRange); 47781 } 47782 47783 /** 47784 * Get the extent for a tile range. 47785 * @param {number} z Integer zoom level. 47786 * @param {import("../TileRange.js").default} tileRange Tile range. 47787 * @param {import("../extent.js").Extent} [tempExtent] Temporary import("../extent.js").Extent object. 47788 * @return {import("../extent.js").Extent} Extent. 47789 */ 47790 getTileRangeExtent(z, tileRange, tempExtent) { 47791 const origin = this.getOrigin(z); 47792 const resolution = this.getResolution(z); 47793 const tileSize = toSize(this.getTileSize(z), this.tmpSize_); 47794 const minX = origin[0] + tileRange.minX * tileSize[0] * resolution; 47795 const maxX = origin[0] + (tileRange.maxX + 1) * tileSize[0] * resolution; 47796 const minY = origin[1] + tileRange.minY * tileSize[1] * resolution; 47797 const maxY = origin[1] + (tileRange.maxY + 1) * tileSize[1] * resolution; 47798 return createOrUpdate(minX, minY, maxX, maxY, tempExtent); 47799 } 47800 47801 /** 47802 * Get a tile range for the given extent and integer zoom level. 47803 * @param {import("../extent.js").Extent} extent Extent. 47804 * @param {number} z Integer zoom level. 47805 * @param {import("../TileRange.js").default} [tempTileRange] Temporary tile range object. 47806 * @return {import("../TileRange.js").default} Tile range. 47807 */ 47808 getTileRangeForExtentAndZ(extent, z, tempTileRange) { 47809 const tileCoord = tmpTileCoord; 47810 this.getTileCoordForXYAndZ_(extent[0], extent[3], z, false, tileCoord); 47811 const minX = tileCoord[1]; 47812 const minY = tileCoord[2]; 47813 this.getTileCoordForXYAndZ_(extent[2], extent[1], z, true, tileCoord); 47814 return TileRange_createOrUpdate( 47815 minX, 47816 tileCoord[1], 47817 minY, 47818 tileCoord[2], 47819 tempTileRange 47820 ); 47821 } 47822 47823 /** 47824 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 47825 * @return {import("../coordinate.js").Coordinate} Tile center. 47826 */ 47827 getTileCoordCenter(tileCoord) { 47828 const origin = this.getOrigin(tileCoord[0]); 47829 const resolution = this.getResolution(tileCoord[0]); 47830 const tileSize = toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); 47831 return [ 47832 origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution, 47833 origin[1] - (tileCoord[2] + 0.5) * tileSize[1] * resolution, 47834 ]; 47835 } 47836 47837 /** 47838 * Get the extent of a tile coordinate. 47839 * 47840 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 47841 * @param {import("../extent.js").Extent} [tempExtent] Temporary extent object. 47842 * @return {import("../extent.js").Extent} Extent. 47843 * @api 47844 */ 47845 getTileCoordExtent(tileCoord, tempExtent) { 47846 const origin = this.getOrigin(tileCoord[0]); 47847 const resolution = this.getResolution(tileCoord[0]); 47848 const tileSize = toSize(this.getTileSize(tileCoord[0]), this.tmpSize_); 47849 const minX = origin[0] + tileCoord[1] * tileSize[0] * resolution; 47850 const minY = origin[1] - (tileCoord[2] + 1) * tileSize[1] * resolution; 47851 const maxX = minX + tileSize[0] * resolution; 47852 const maxY = minY + tileSize[1] * resolution; 47853 return createOrUpdate(minX, minY, maxX, maxY, tempExtent); 47854 } 47855 47856 /** 47857 * Get the tile coordinate for the given map coordinate and resolution. This 47858 * method considers that coordinates that intersect tile boundaries should be 47859 * assigned the higher tile coordinate. 47860 * 47861 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 47862 * @param {number} resolution Resolution. 47863 * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Destination import("../tilecoord.js").TileCoord object. 47864 * @return {import("../tilecoord.js").TileCoord} Tile coordinate. 47865 * @api 47866 */ 47867 getTileCoordForCoordAndResolution(coordinate, resolution, opt_tileCoord) { 47868 return this.getTileCoordForXYAndResolution_( 47869 coordinate[0], 47870 coordinate[1], 47871 resolution, 47872 false, 47873 opt_tileCoord 47874 ); 47875 } 47876 47877 /** 47878 * Note that this method should not be called for resolutions that correspond 47879 * to an integer zoom level. Instead call the `getTileCoordForXYAndZ_` method. 47880 * @param {number} x X. 47881 * @param {number} y Y. 47882 * @param {number} resolution Resolution (for a non-integer zoom level). 47883 * @param {boolean} reverseIntersectionPolicy Instead of letting edge 47884 * intersections go to the higher tile coordinate, let edge intersections 47885 * go to the lower tile coordinate. 47886 * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Temporary import("../tilecoord.js").TileCoord object. 47887 * @return {import("../tilecoord.js").TileCoord} Tile coordinate. 47888 * @private 47889 */ 47890 getTileCoordForXYAndResolution_( 47891 x, 47892 y, 47893 resolution, 47894 reverseIntersectionPolicy, 47895 opt_tileCoord 47896 ) { 47897 const z = this.getZForResolution(resolution); 47898 const scale = resolution / this.getResolution(z); 47899 const origin = this.getOrigin(z); 47900 const tileSize = toSize(this.getTileSize(z), this.tmpSize_); 47901 47902 let tileCoordX = (scale * (x - origin[0])) / resolution / tileSize[0]; 47903 let tileCoordY = (scale * (origin[1] - y)) / resolution / tileSize[1]; 47904 47905 if (reverseIntersectionPolicy) { 47906 tileCoordX = ceil(tileCoordX, DECIMALS) - 1; 47907 tileCoordY = ceil(tileCoordY, DECIMALS) - 1; 47908 } else { 47909 tileCoordX = floor(tileCoordX, DECIMALS); 47910 tileCoordY = floor(tileCoordY, DECIMALS); 47911 } 47912 47913 return tilecoord_createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord); 47914 } 47915 47916 /** 47917 * Although there is repetition between this method and `getTileCoordForXYAndResolution_`, 47918 * they should have separate implementations. This method is for integer zoom 47919 * levels. The other method should only be called for resolutions corresponding 47920 * to non-integer zoom levels. 47921 * @param {number} x Map x coordinate. 47922 * @param {number} y Map y coordinate. 47923 * @param {number} z Integer zoom level. 47924 * @param {boolean} reverseIntersectionPolicy Instead of letting edge 47925 * intersections go to the higher tile coordinate, let edge intersections 47926 * go to the lower tile coordinate. 47927 * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Temporary import("../tilecoord.js").TileCoord object. 47928 * @return {import("../tilecoord.js").TileCoord} Tile coordinate. 47929 * @private 47930 */ 47931 getTileCoordForXYAndZ_(x, y, z, reverseIntersectionPolicy, opt_tileCoord) { 47932 const origin = this.getOrigin(z); 47933 const resolution = this.getResolution(z); 47934 const tileSize = toSize(this.getTileSize(z), this.tmpSize_); 47935 47936 let tileCoordX = (x - origin[0]) / resolution / tileSize[0]; 47937 let tileCoordY = (origin[1] - y) / resolution / tileSize[1]; 47938 47939 if (reverseIntersectionPolicy) { 47940 tileCoordX = ceil(tileCoordX, DECIMALS) - 1; 47941 tileCoordY = ceil(tileCoordY, DECIMALS) - 1; 47942 } else { 47943 tileCoordX = floor(tileCoordX, DECIMALS); 47944 tileCoordY = floor(tileCoordY, DECIMALS); 47945 } 47946 47947 return tilecoord_createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord); 47948 } 47949 47950 /** 47951 * Get a tile coordinate given a map coordinate and zoom level. 47952 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 47953 * @param {number} z Zoom level. 47954 * @param {import("../tilecoord.js").TileCoord} [opt_tileCoord] Destination import("../tilecoord.js").TileCoord object. 47955 * @return {import("../tilecoord.js").TileCoord} Tile coordinate. 47956 * @api 47957 */ 47958 getTileCoordForCoordAndZ(coordinate, z, opt_tileCoord) { 47959 return this.getTileCoordForXYAndZ_( 47960 coordinate[0], 47961 coordinate[1], 47962 z, 47963 false, 47964 opt_tileCoord 47965 ); 47966 } 47967 47968 /** 47969 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 47970 * @return {number} Tile resolution. 47971 */ 47972 getTileCoordResolution(tileCoord) { 47973 return this.resolutions_[tileCoord[0]]; 47974 } 47975 47976 /** 47977 * Get the tile size for a zoom level. The type of the return value matches the 47978 * `tileSize` or `tileSizes` that the tile grid was configured with. To always 47979 * get an {@link import("../size.js").Size}, run the result through {@link module:ol/size.toSize}. 47980 * @param {number} z Z. 47981 * @return {number|import("../size.js").Size} Tile size. 47982 * @api 47983 */ 47984 getTileSize(z) { 47985 if (this.tileSize_) { 47986 return this.tileSize_; 47987 } else { 47988 return this.tileSizes_[z]; 47989 } 47990 } 47991 47992 /** 47993 * @param {number} z Zoom level. 47994 * @return {import("../TileRange.js").default} Extent tile range for the specified zoom level. 47995 */ 47996 getFullTileRange(z) { 47997 if (!this.fullTileRanges_) { 47998 return this.extent_ 47999 ? this.getTileRangeForExtentAndZ(this.extent_, z) 48000 : null; 48001 } else { 48002 return this.fullTileRanges_[z]; 48003 } 48004 } 48005 48006 /** 48007 * @param {number} resolution Resolution. 48008 * @param {number|import("../array.js").NearestDirectionFunction} [opt_direction] 48009 * If 0, the nearest resolution will be used. 48010 * If 1, the nearest higher resolution (lower Z) will be used. If -1, the 48011 * nearest lower resolution (higher Z) will be used. Default is 0. 48012 * Use a {@link module:ol/array~NearestDirectionFunction} for more precise control. 48013 * 48014 * For example to change tile Z at the midpoint of zoom levels 48015 * ```js 48016 * function(value, high, low) { 48017 * return value - low * Math.sqrt(high / low); 48018 * } 48019 * ``` 48020 * @return {number} Z. 48021 * @api 48022 */ 48023 getZForResolution(resolution, opt_direction) { 48024 const z = linearFindNearest( 48025 this.resolutions_, 48026 resolution, 48027 opt_direction || 0 48028 ); 48029 return math_clamp(z, this.minZoom, this.maxZoom); 48030 } 48031 48032 /** 48033 * The tile with the provided tile coordinate intersects the given viewport. 48034 * @param {import('../tilecoord.js').TileCoord} tileCoord Tile coordinate. 48035 * @param {Array<number>} viewport Viewport as returned from {@link module:ol/extent.getRotatedViewport}. 48036 * @return {boolean} The tile with the provided tile coordinate intersects the given viewport. 48037 */ 48038 tileCoordIntersectsViewport(tileCoord, viewport) { 48039 return intersectsLinearRing( 48040 viewport, 48041 0, 48042 viewport.length, 48043 2, 48044 this.getTileCoordExtent(tileCoord) 48045 ); 48046 } 48047 48048 /** 48049 * @param {!import("../extent.js").Extent} extent Extent for this tile grid. 48050 * @private 48051 */ 48052 calculateTileRanges_(extent) { 48053 const length = this.resolutions_.length; 48054 const fullTileRanges = new Array(length); 48055 for (let z = this.minZoom; z < length; ++z) { 48056 fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z); 48057 } 48058 this.fullTileRanges_ = fullTileRanges; 48059 } 48060} 48061 48062/* harmony default export */ const tilegrid_TileGrid = (TileGrid); 48063 48064;// CONCATENATED MODULE: ./node_modules/ol/tilegrid.js 48065/** 48066 * @module ol/tilegrid 48067 */ 48068 48069 48070 48071 48072 48073 48074/** 48075 * @param {import("./proj/Projection.js").default} projection Projection. 48076 * @return {!TileGrid} Default tile grid for the 48077 * passed projection. 48078 */ 48079function getForProjection(projection) { 48080 let tileGrid = projection.getDefaultTileGrid(); 48081 if (!tileGrid) { 48082 tileGrid = createForProjection(projection); 48083 projection.setDefaultTileGrid(tileGrid); 48084 } 48085 return tileGrid; 48086} 48087 48088/** 48089 * @param {TileGrid} tileGrid Tile grid. 48090 * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate. 48091 * @param {import("./proj/Projection.js").default} projection Projection. 48092 * @return {import("./tilecoord.js").TileCoord} Tile coordinate. 48093 */ 48094function tilegrid_wrapX(tileGrid, tileCoord, projection) { 48095 const z = tileCoord[0]; 48096 const center = tileGrid.getTileCoordCenter(tileCoord); 48097 const projectionExtent = extentFromProjection(projection); 48098 if (!containsCoor
48098dinate(projectionExtent, center)) { 48099 const worldWidth = extent_getWidth(projectionExtent); 48100 const worldsAway = Math.ceil( 48101 (projectionExtent[0] - center[0]) / worldWidth 48102 ); 48103 center[0] += worldWidth * worldsAway; 48104 return tileGrid.getTileCoordForCoordAndZ(center, z); 48105 } else { 48106 return tileCoord; 48107 } 48108} 48109 48110/** 48111 * @param {import("./extent.js").Extent} extent Extent. 48112 * @param {number} [maxZoom] Maximum zoom level (default is 48113 * DEFAULT_MAX_ZOOM). 48114 * @param {number|import("./size.js").Size} [tileSize] Tile size (default uses 48115 * DEFAULT_TILE_SIZE). 48116 * @param {import("./extent.js").Corner} [corner] Extent corner (default is `'top-left'`). 48117 * @return {!TileGrid} TileGrid instance. 48118 */ 48119function createForExtent(extent, maxZoom, tileSize, corner) { 48120 corner = corner !== undefined ? corner : 'top-left'; 48121 48122 const resolutions = resolutionsFromExtent(extent, maxZoom, tileSize); 48123 48124 return new tilegrid_TileGrid({ 48125 extent: extent, 48126 origin: getCorner(extent, corner), 48127 resolutions: resolutions, 48128 tileSize: tileSize, 48129 }); 48130} 48131 48132/** 48133 * @typedef {Object} XYZOptions 48134 * @property {import("./extent.js").Extent} [extent] Extent for the tile grid. The origin for an XYZ tile grid is the 48135 * top-left corner of the extent. If `maxResolution` is not provided the zero level of the grid is defined by the resolution 48136 * at which one tile fits in the provided extent. If not provided, the extent of the EPSG:3857 projection is used. 48137 * @property {number} [maxResolution] Resolution at level zero. 48138 * @property {number} [maxZoom] Maximum zoom. The default is `42`. This determines the number of levels 48139 * in the grid set. For example, a `maxZoom` of 21 means there are 22 levels in the grid set. 48140 * @property {number} [minZoom=0] Minimum zoom. 48141 * @property {number|import("./size.js").Size} [tileSize=[256, 256]] Tile size in pixels. 48142 */ 48143 48144/** 48145 * Creates a tile grid with a standard XYZ tiling scheme. 48146 * @param {XYZOptions} [options] Tile grid options. 48147 * @return {!TileGrid} Tile grid instance. 48148 * @api 48149 */ 48150function createXYZ(options) { 48151 const xyzOptions = options || {}; 48152 48153 const extent = xyzOptions.extent || proj_get('EPSG:3857').getExtent(); 48154 48155 const gridOptions = { 48156 extent: extent, 48157 minZoom: xyzOptions.minZoom, 48158 tileSize: xyzOptions.tileSize, 48159 resolutions: resolutionsFromExtent( 48160 extent, 48161 xyzOptions.maxZoom, 48162 xyzOptions.tileSize, 48163 xyzOptions.maxResolution 48164 ), 48165 }; 48166 return new tilegrid_TileGrid(gridOptions); 48167} 48168 48169/** 48170 * Create a resolutions array from an extent. A zoom factor of 2 is assumed. 48171 * @param {import("./extent.js").Extent} extent Extent. 48172 * @param {number} [maxZoom] Maximum zoom level (default is 48173 * DEFAULT_MAX_ZOOM). 48174 * @param {number|import("./size.js").Size} [tileSize] Tile size (default uses 48175 * DEFAULT_TILE_SIZE). 48176 * @param {number} [maxResolution] Resolution at level zero. 48177 * @return {!Array<number>} Resolutions array. 48178 */ 48179function resolutionsFromExtent(extent, maxZoom, tileSize, maxResolution) { 48180 maxZoom = maxZoom !== undefined ? maxZoom : DEFAULT_MAX_ZOOM; 48181 tileSize = toSize(tileSize !== undefined ? tileSize : DEFAULT_TILE_SIZE); 48182 48183 const height = extent_getHeight(extent); 48184 const width = extent_getWidth(extent); 48185 48186 maxResolution = 48187 maxResolution > 0 48188 ? maxResolution
48189 : Math.max(width / tileSize[0], height / tileSize[1]); 48190 48191 const length = maxZoom + 1; 48192 const resolutions = new Array(length); 48193 for (let z = 0; z < length; ++z) { 48194 resolutions[z] = maxResolution / Math.pow(2, z); 48195 } 48196 return resolutions; 48197} 48198 48199/** 48200 * @param {import("./proj.js").ProjectionLike} projection Projection. 48201 * @param {number} [maxZoom] Maximum zoom level (default is 48202 * DEFAULT_MAX_ZOOM). 48203 * @param {number|import("./size.js").Size} [tileSize] Tile size (default uses 48204 * DEFAULT_TILE_SIZE). 48205 * @param {import("./extent.js").Corner} [corner] Extent corner (default is `'top-left'`). 48206 * @return {!TileGrid} TileGrid instance. 48207 */ 48208function createForProjection(projection, maxZoom, tileSize, corner) { 48209 const extent = extentFromProjection(projection); 48210 return createForExtent(extent, maxZoom, tileSize, corner); 48211} 48212 48213/** 48214 * Generate a tile grid extent from a projection. If the projection has an 48215 * extent, it is used. If not, a global extent is assumed. 48216 * @param {import("./proj.js").ProjectionLike} projection Projection. 48217 * @return {import("./extent.js").Extent} Extent. 48218 */ 48219function extentFromProjection(projection) { 48220 projection = proj_get(projection); 48221 let extent = projection.getExtent(); 48222 if (!extent) { 48223 const half = 48224 (180 * Units_METERS_PER_UNIT.degrees) / projection.getMetersPerUnit(); 48225 extent = createOrUpdate(-half, -half, half, half); 48226 } 48227 return extent; 48228} 48229 48230;// CONCATENATED MODULE: ./node_modules/ol/source/Tile.js 48231/** 48232 * @module ol/source/Tile 48233 */ 48234 48235 48236 48237 48238 48239 48240 48241 48242 48243 48244 48245/*** 48246 * @template Return 48247 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 48248 * import("../Observable").OnSignature<import("../ObjectEventType").Types, import("../Object").ObjectEvent, Return> & 48249 * import("../Observable").OnSignature<import("./TileEventType").TileSourceEventTypes, TileSourceEvent, Return> & 48250 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types| 48251 * import("./TileEventType").TileSourceEventTypes, Return>} TileSourceOnSignature 48252 */ 48253 48254/** 48255 * @typedef {Object} Options 48256 * @property {import("./Source.js").AttributionLike} [attributions] Attributions. 48257 * @property {boolean} [attributionsCollapsible=true] Attributions are collapsible. 48258 * @property {number} [cacheSize] CacheSize. 48259 * @property {boolean} [opaque=false] Whether the layer is opaque. 48260 * @property {number} [tilePixelRatio] TilePixelRatio. 48261 * @property {import("../proj.js").ProjectionLike} [projection] Projection. 48262 * @property {import("./Source.js").State} [state] State. 48263 * @property {import("../tilegrid/TileGrid.js").default} [tileGrid] TileGrid. 48264 * @property {boolean} [wrapX=false] WrapX. 48265 * @property {number} [transition] Transition. 48266 * @property {string} [key] Key. 48267 * @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection. 48268 * @property {boolean} [interpolate=false] Use interpolated values when resampling. By default, 48269 * the nearest neighbor is used when resampling. 48270 */ 48271 48272/** 48273 * @classdesc 48274 * Abstract base class; normally only used for creating subclasses and not 48275 * instantiated in apps. 48276 * Base class for sources providing images divided into a tile grid. 48277 * @abstract 48278 * @api 48279 */ 48280class TileSource extends source_Source { 48281 /** 48282 * @param {Options} options SourceTile source options. 48283 */ 48284 constructor(options) { 48285 super({ 48286 attributions: options.attributions, 48287 attributionsCollapsible: options.attributionsCollapsible, 48288 projection: options.projection, 48289 state: options.state, 48290 wrapX: options.wrapX, 48291 interpolate: options.interpolate, 48292 }); 48293 48294 /*** 48295 * @type {TileSourceOnSignature<import("../events").EventsKey>} 48296 */ 48297 this.on; 48298 48299 /*** 48300 * @type {TileSourceOnSignature<import("../events").EventsKey>} 48301 */ 48302 this.once; 48303 48304 /*** 48305 * @type {TileSourceOnSignature<void>} 48306 */ 48307 this.un; 48308 48309 /** 48310 * @private 48311 * @type {boolean} 48312 */ 48313 this.opaque_ = options.opaque !== undefined ? options.opaque : false; 48314 48315 /** 48316 * @private 48317 * @type {number} 48318 */ 48319 this.tilePixelRatio_ = 48320 options.tilePixelRatio !== undefined ? options.tilePixelRatio : 1; 48321 48322 /** 48323 * @type {import("../tilegrid/TileGrid.js").default|null} 48324 */ 48325 this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null; 48326 48327 const tileSize = [256, 256]; 48328 if (this.tileGrid) { 48329 toSize(this.tileGrid.getTileSize(this.tileGrid.getMinZoom()), tileSize); 48330 } 48331 48332 /** 48333 * @protected 48334 * @type {import("../TileCache.js").default} 48335 */ 48336 this.tileCache = new ol_TileCache(options.cacheSize || 0); 48337 48338 /** 48339 * @protected 48340 * @type {import("../size.js").Size} 48341 */ 48342 this.tmpSize = [0, 0]; 48343 48344 /** 48345 * @private 48346 * @type {string} 48347 */ 48348 this.key_ = options.key || ''; 48349 48350 /** 48351 * @protected 48352 * @type {import("../Tile.js").Options} 48353 */ 48354 this.tileOptions = { 48355 transition: options.transition, 48356 interpolate: options.interpolate, 48357 }; 48358 48359 /** 48360 * zDirection hint, read by the renderer. Indicates which resolution should be used 48361 * by a renderer if the views resolution does not match any resolution of the tile source. 48362 * If 0, the nearest resolution will be used. If 1, the nearest lower resolution 48363 * will be used. If -1, the nearest higher resolution will be used. 48364 * @type {number|import("../array.js").NearestDirectionFunction} 48365 */ 48366 this.zDirection = options.zDirection ? options.zDirection : 0; 48367 } 48368 48369 /** 48370 * @return {boolean} Can expire cache. 48371 */ 48372 canExpireCache() { 48373 return this.tileCache.canExpireCache(); 48374 } 48375 48376 /** 48377 * @param {import("../proj/Projection.js").default} projection Projection. 48378 * @param {!Object<string, boolean>} usedTiles Used tiles. 48379 */ 48380 expireCache(projection, usedTiles) {
48381 const tileCache = this.getTileCacheForProjection(projection); 48382 if (tileCache) { 48383 tileCache.expireCache(usedTiles); 48384 } 48385 } 48386 48387 /** 48388 * @param {import("../proj/Projection.js").default} projection Projection. 48389 * @param {number} z Zoom level. 48390 * @param {import("../TileRange.js").default} tileRange Tile range. 48391 * @param {function(import("../Tile.js").default):(boolean|void)} callback Called with each 48392 * loaded tile. If the callback returns `false`, the tile will not be 48393 * considered loaded. 48394 * @return {boolean} The tile range is fully covered with loaded tiles. 48395 */ 48396 forEachLoadedTile(projection, z, tileRange, callback) { 48397 const tileCache = this.getTileCacheForProjection(projection); 48398 if (!tileCache) { 48399 return false; 48400 } 48401 48402 let covered = true; 48403 let tile, tileCoordKey, loaded; 48404 for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { 48405 for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { 48406 tileCoordKey = getKeyZXY(z, x, y); 48407 loaded = false; 48408 if (tileCache.containsKey(tileCoordKey)) {
48409 tile = /** @type {!import("../Tile.js").default} */ ( 48410 tileCache.get(tileCoordKey) 48411 ); 48412 loaded = tile.getState() === TileState.LOADED; 48413 if (loaded) { 48414 loaded = callback(tile) !== false; 48415 } 48416 } 48417 if (!loaded) { 48418 covered = false; 48419 } 48420 } 48421 } 48422 return covered; 48423 } 48424 48425 /** 48426 * @param {import("../proj/Projection.js").default} projection Projection. 48427 * @return {number} Gutter. 48428 */ 48429 getGutterForProjection(projection) { 48430 return 0; 48431 } 48432 48433 /** 48434 * Return the key to be used for all tiles in the source. 48435 * @return {string} The key for all tiles. 48436 */ 48437 getKey() { 48438 return this.key_; 48439 } 48440 48441 /** 48442 * Set the value to be used as the key for all tiles in the source. 48443 * @param {string} key The key for tiles. 48444 * @protected 48445 */ 48446 setKey(key) { 48447 if (this.key_ !== key) { 48448 this.key_ = key; 48449 this.changed(); 48450 } 48451 } 48452 48453 /** 48454 * @param {import("../proj/Projection.js").default} projection Projection. 48455 * @return {boolean} Opaque. 48456 */ 48457 getOpaque(projection) { 48458 return this.opaque_; 48459 } 48460 48461 /** 48462 * @return {Array<number>|null} Resolutions. 48463 */ 48464 getResolutions() { 48465 if (!this.tileGrid) { 48466 return null; 48467 } 48468 return this.tileGrid.getResolutions(); 48469 } 48470 48471 /** 48472 * @abstract 48473 * @param {number} z Tile coordinate z. 48474 * @param {number} x Tile coordinate x. 48475 * @param {number} y Tile coordinate y. 48476 * @param {number} pixelRatio Pixel ratio. 48477 * @param {import("../proj/Projection.js").default} projection Projection. 48478 * @return {!import("../Tile.js").default} Tile. 48479 */ 48480 getTile(z, x, y, pixelRatio, projection) { 48481 return util_abstract(); 48482 } 48483 48484 /** 48485 * Return the tile grid of the tile source. 48486 * @return {import("../tilegrid/TileGrid.js").default|null} Tile grid. 48487 * @api 48488 */ 48489 getTileGrid() { 48490 return this.tileGrid; 48491 } 48492 48493 /** 48494 * @param {import("../proj/Projection.js").default} projection Projection. 48495 * @return {!import("../tilegrid/TileGrid.js").default} Tile grid. 48496 */ 48497 getTileGridForProjection(projection) { 48498 if (!this.tileGrid) { 48499 return getForProjection(projection); 48500 } else { 48501 return this.tileGrid; 48502 } 48503 } 48504 48505 /** 48506 * @param {import("../proj/Projection.js").default} projection Projection. 48507 * @return {import("../TileCache.js").default} Tile cache. 48508 * @protected 48509 */ 48510 getTileCacheForProjection(projection) { 48511 const sourceProjection = this.getProjection(); 48512 asserts_assert( 48513 sourceProjection === null || equivalent(sourceProjection, projection), 48514 68 // A VectorTile source can only be rendered if it has a projection compatible with the view projection. 48515 ); 48516 return this.tileCache; 48517 } 48518 48519 /** 48520 * Get the tile pixel ratio for this source. Subclasses may override this 48521 * method, which is meant to return a supported pixel ratio that matches the 48522 * provided `pixelRatio` as close as possible. 48523 * @param {number} pixelRatio Pixel ratio. 48524 * @return {number} Tile pixel ratio. 48525 */ 48526 getTilePixelRatio(pixelRatio) { 48527 return this.tilePixelRatio_; 48528 } 48529 48530 /** 48531 * @param {number} z Z. 48532 * @param {number} pixelRatio Pixel ratio. 48533 * @param {import("../proj/Projection.js").default} projection Projection. 48534 * @return {import("../size.js").Size} Tile size. 48535 */ 48536 getTilePixelSize(z, pixelRatio, projection) { 48537 const tileGrid = this.getTileGridForProjection(projection); 48538 const tilePixelRatio = this.getTilePixelRatio(pixelRatio); 48539 const tileSize = toSize(tileGrid.getTileSize(z), this.tmpSize); 48540 if (tilePixelRatio == 1) { 48541 return tileSize; 48542 } else { 48543 return size_scale(tileSize, tilePixelRatio, this.tmpSize); 48544 } 48545 } 48546 48547 /** 48548 * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate 48549 * is outside the resolution and extent range of the tile grid, `null` will be 48550 * returned. 48551 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 48552 * @param {import("../proj/Projection.js").default} [projection] Projection. 48553 * @return {import("../tilecoord.js").TileCoord} Tile coordinate to be passed to the tileUrlFunction or 48554 * null if no tile URL should be created for the passed `tileCoord`. 48555 */ 48556 getTileCoordForTileUrlFunction(tileCoord, projection) { 48557 projection = projection !== undefined ? projection : this.getProjection(); 48558 const tileGrid = this.getTileGridForProjection(projection); 48559 if (this.getWrapX() && projection.isGlobal()) { 48560 tileCoord = tilegrid_wrapX(tileGrid, tileCoord, projection); 48561 } 48562 return withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null; 48563 } 48564 48565 /** 48566 * Remove all cached tiles from the source. The next render cycle will fetch new tiles. 48567 * @api 48568 */ 48569 clear() { 48570 this.tileCache.clear(); 48571 } 48572 48573 refresh() { 48574 this.clear(); 48575 super.refresh(); 48576 } 48577 48578 /** 48579 * Increases the cache size if needed 48580 * @param {number} tileCount Minimum number of tiles needed. 48581 * @param {import("../proj/Projection.js").default} projection Projection. 48582 */ 48583 updateCacheSize(tileCount, projection) {
48584 const tileCache = this.getTileCacheForProjection(projection); 48585 if (tileCount > tileCache.highWaterMark) { 48586 tileCache.highWaterMark = tileCount; 48587 } 48588 } 48589 48590 /** 48591 * Marks a tile coord as being used, without triggering a load. 48592 * @abstract 48593 * @param {number} z Tile coordinate z. 48594 * @param {number} x Tile coordinate x. 48595 * @param {number} y Tile coordinate y. 48596 * @param {import("../proj/Projection.js").default} projection Projection. 48597 */ 48598 useTile(z, x, y, projection) {} 48599} 48600 48601/** 48602 * @classdesc 48603 * Events emitted by {@link module:ol/source/Tile~TileSource} instances are instances of this 48604 * type. 48605 */ 48606class TileSourceEvent extends Event { 48607 /** 48608 * @param {string} type Type. 48609 * @param {import("../Tile.js").default} tile The tile. 48610 */ 48611 constructor(type, tile) { 48612 super(type); 48613 48614 /** 48615 * The tile related to the event. 48616 * @type {import("../Tile.js").default} 48617 * @api 48618 */ 48619 this.tile = tile; 48620 } 48621} 48622 48623/* harmony default export */ const source_Tile = (TileSource); 48624 48625;// CONCATENATED MODULE: ./node_modules/ol/tileurlfunction.js 48626/** 48627 * @module ol/tileurlfunction 48628 */ 48629 48630 48631 48632 48633/** 48634 * @param {string} template Template. 48635 * @param {import("./tilegrid/TileGrid.js").default} tileGrid Tile grid. 48636 * @return {import("./Tile.js").UrlFunction} Tile URL function. 48637 */ 48638function createFromTemplate(template, tileGrid) { 48639 const zRegEx = /\{z\}/g; 48640 const xRegEx = /\{x\}/g; 48641 const yRegEx = /\{y\}/g; 48642 const dashYRegEx = /\{-y\}/g; 48643 return ( 48644 /** 48645 * @param {import("./tilecoord.js").TileCoord} tileCoord Tile Coordinate. 48646 * @param {number} pixelRatio Pixel ratio. 48647 * @param {import("./proj/Projection.js").default} projection Projection. 48648 * @return {string|undefined} Tile URL. 48649 */ 48650 function (tileCoord, pixelRatio, projection) { 48651 if (!tileCoord) { 48652 return undefined; 48653 } else { 48654 return template 48655 .replace(zRegEx, tileCoord[0].toString()) 48656 .replace(xRegEx, tileCoord[1].toString()) 48657 .replace(yRegEx, tileCoord[2].toString()) 48658 .replace(dashYRegEx, function () { 48659 const z = tileCoord[0]; 48660 const range = tileGrid.getFullTileRange(z); 48661 asserts_assert(range, 55); // The {-y} placeholder requires a tile grid with extent 48662 const y = range.getHeight() - tileCoord[2] - 1; 48663 return y.toString(); 48664 }); 48665 } 48666 } 48667 ); 48668} 48669 48670/** 48671 * @param {Array<string>} templates Templates. 48672 * @param {import("./tilegrid/TileGrid.js").default} tileGrid Tile grid. 48673 * @return {import("./Tile.js").UrlFunction} Tile URL function. 48674 */ 48675function createFromTemplates(templates, tileGrid) { 48676 const len = templates.length; 48677 const tileUrlFunctions = new Array(len); 48678 for (let i = 0; i < len; ++i) { 48679 tileUrlFunctions[i] = createFromTemplate(templates[i], tileGrid); 48680 } 48681 return createFromTileUrlFunctions(tileUrlFunctions); 48682} 48683 48684/** 48685 * @param {Array<import("./Tile.js").UrlFunction>} tileUrlFunctions Tile URL Functions. 48686 * @return {import("./Tile.js").UrlFunction} Tile URL function. 48687 */ 48688function createFromTileUrlFunctions(tileUrlFunctions) { 48689 if (tileUrlFunctions.length === 1) { 48690 return tileUrlFunctions[0]; 48691 } 48692 return ( 48693 /** 48694 * @param {import("./tilecoord.js").TileCoord} tileCoord Tile Coordinate. 48695 * @param {number} pixelRatio Pixel ratio. 48696 * @param {import("./proj/Projection.js").default} projection Projection. 48697 * @return {string|undefined} Tile URL. 48698 */ 48699 function (tileCoord, pixelRatio, projection) { 48700 if (!tileCoord) { 48701 return undefined; 48702 } else { 48703 const h = hash(tileCoord); 48704 const index = math_modulo(h, tileUrlFunctions.length); 48705 return tileUrlFunctions[index](tileCoord, pixelRatio, projection); 48706 } 48707 } 48708 ); 48709} 48710 48711/** 48712 * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate. 48713 * @param {number} pixelRatio Pixel ratio. 48714 * @param {import("./proj/Projection.js").default} projection Projection. 48715 * @return {string|undefined} Tile URL. 48716 */ 48717function nullTileUrlFunction(tileCoord, pixelRatio, projection) { 48718 return undefined; 48719} 48720 48721/** 48722 * @param {string} url URL. 48723 * @return {Array<string>} Array of urls. 48724 */ 48725function expandUrl(url) { 48726 const urls = []; 48727 let match = /\{([a-z])-([a-z])\}/.exec(url); 48728 if (match) { 48729 // char range
vendor: 5,962 bytes, lines 48730-48945
48730 const startCharCode = match[1].charCodeAt(0); 48731 const stopCharCode = match[2].charCodeAt(0); 48732 let charCode; 48733 for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) { 48734 urls.push(url.replace(match[0], String.fromCharCode(charCode))); 48735 } 48736 return urls; 48737 } 48738 match = /\{(\d+)-(\d+)\}/.exec(url); 48739 if (match) { 48740 // number range 48741 const stop = parseInt(match[2], 10); 48742 for (let i = parseInt(match[1], 10); i <= stop; i++) { 48743 urls.push(url.replace(match[0], i.toString())); 48744 } 48745 return urls; 48746 } 48747 urls.push(url); 48748 return urls; 48749} 48750 48751;// CONCATENATED MODULE: ./node_modules/ol/source/UrlTile.js 48752/** 48753 * @module ol/source/UrlTile 48754 */ 48755 48756 48757 48758 48759 48760 48761 48762/** 48763 * @typedef {Object} Options 48764 * @property {import("./Source.js").AttributionLike} [attributions] Attributions. 48765 * @property {boolean} [attributionsCollapsible=true] Attributions are collapsible. 48766 * @property {number} [cacheSize] Cache size. 48767 * @property {boolean} [opaque=false] Whether the layer is opaque. 48768 * @property {import("../proj.js").ProjectionLike} [projection] Projection. 48769 * @property {import("./Source.js").State} [state] State. 48770 * @property {import("../tilegrid/TileGrid.js").default} [tileGrid] TileGrid. 48771 * @property {import("../Tile.js").LoadFunction} tileLoadFunction TileLoadFunction. 48772 * @property {number} [tilePixelRatio] TilePixelRatio. 48773 * @property {import("../Tile.js").UrlFunction} [tileUrlFunction] TileUrlFunction. 48774 * @property {string} [url] Url. 48775 * @property {Array<string>} [urls] Urls. 48776 * @property {boolean} [wrapX=true] WrapX. 48777 * @property {number} [transition] Transition. 48778 * @property {string} [key] Key. 48779 * @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] ZDirection. 48780 * @property {boolean} [interpolate=false] Use interpolated values when resampling. By default, 48781 * the nearest neighbor is used when resampling. 48782 */ 48783 48784/** 48785 * @classdesc 48786 * Base class for sources providing tiles divided into a tile grid over http. 48787 * 48788 * @fires import("./Tile.js").TileSourceEvent 48789 */ 48790class UrlTile extends source_Tile { 48791 /** 48792 * @param {Options} options Image tile options. 48793 */ 48794 constructor(options) { 48795 super({ 48796 attributions: options.attributions, 48797 cacheSize: options.cacheSize, 48798 opaque: options.opaque, 48799 projection: options.projection, 48800 state: options.state, 48801 tileGrid: options.tileGrid, 48802 tilePixelRatio: options.tilePixelRatio, 48803 wrapX: options.wrapX, 48804 transition: options.transition, 48805 interpolate: options.interpolate, 48806 key: options.key, 48807 attributionsCollapsible: options.attributionsCollapsible, 48808 zDirection: options.zDirection, 48809 }); 48810 48811 /** 48812 * @private 48813 * @type {boolean} 48814 */ 48815 this.generateTileUrlFunction_ = 48816 this.tileUrlFunction === UrlTile.prototype.tileUrlFunction; 48817 48818 /** 48819 * @protected 48820 * @type {import("../Tile.js").LoadFunction} 48821 */ 48822 this.tileLoadFunction = options.tileLoadFunction; 48823 48824 if (options.tileUrlFunction) { 48825 this.tileUrlFunction = options.tileUrlFunction; 48826 } 48827 48828 /** 48829 * @protected 48830 * @type {!Array<string>|null} 48831 */ 48832 this.urls = null; 48833 48834 if (options.urls) { 48835 this.setUrls(options.urls); 48836 } else if (options.url) { 48837 this.setUrl(options.url); 48838 } 48839 48840 /** 48841 * @private 48842 * @type {!Object<string, boolean>} 48843 */ 48844 this.tileLoadingKeys_ = {}; 48845 } 48846 48847 /** 48848 * Return the tile load function of the source. 48849 * @return {import("../Tile.js").LoadFunction} TileLoadFunction 48850 * @api 48851 */ 48852 getTileLoadFunction() { 48853 return this.tileLoadFunction; 48854 } 48855 48856 /** 48857 * Return the tile URL function of the source. 48858 * @return {import("../Tile.js").UrlFunction} TileUrlFunction 48859 * @api 48860 */ 48861 getTileUrlFunction() { 48862 return Object.getPrototypeOf(this).tileUrlFunction === this.tileUrlFunction 48863 ? this.tileUrlFunction.bind(this) 48864 : this.tileUrlFunction; 48865 } 48866 48867 /** 48868 * Return the URLs used for this source. 48869 * When a tileUrlFunction is used instead of url or urls, 48870 * null will be returned. 48871 * @return {!Array<string>|null} URLs. 48872 * @api 48873 */ 48874 getUrls() { 48875 return this.urls; 48876 } 48877 48878 /** 48879 * Handle tile change events. 48880 * @param {import("../events/Event.js").default} event Event. 48881 * @protected 48882 */ 48883 handleTileChange(event) { 48884 const tile = /** @type {import("../Tile.js").default} */ (event.target); 48885 const uid = getUid(tile); 48886 const tileState = tile.getState(); 48887 let type; 48888 if (tileState == TileState.LOADING) { 48889 this.tileLoadingKeys_[uid] = true; 48890 type = TileEventType.TILELOADSTART; 48891 } else if (uid in this.tileLoadingKeys_) { 48892 delete this.tileLoadingKeys_[uid]; 48893 type = 48894 tileState == TileState.ERROR 48895 ? TileEventType.TILELOADERROR 48896 : tileState == TileState.LOADED 48897 ? TileEventType.TILELOADEND 48898 : undefined; 48899 } 48900 if (type != undefined) { 48901 this.dispatchEvent(new TileSourceEvent(type, tile)); 48902 } 48903 } 48904 48905 /** 48906 * Set the tile load function of the source. 48907 * @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function. 48908 * @api 48909 */ 48910 setTileLoadFunction(tileLoadFunction) { 48911 this.tileCache.clear(); 48912 this.tileLoadFunction = tileLoadFunction; 48913 this.changed(); 48914 } 48915 48916 /** 48917 * Set the tile URL function of the source. 48918 * @param {import("../Tile.js").UrlFunction} tileUrlFunction Tile URL function. 48919 * @param {string} [key] Optional new tile key for the source. 48920 * @api 48921 */ 48922 setTileUrlFunction(tileUrlFunction, key) { 48923 this.tileUrlFunction = tileUrlFunction; 48924 this.tileCache.pruneExceptNewestZ(); 48925 if (typeof key !== 'undefined') { 48926 this.setKey(key); 48927 } else { 48928 this.changed(); 48929 } 48930 } 48931 48932 /** 48933 * Set the URL to use for requests. 48934 * @param {string} url URL. 48935 * @api 48936 */ 48937 setUrl(url) { 48938 const urls = expandUrl(url); 48939 this.urls = urls; 48940 this.setUrls(urls); 48941 } 48942 48943 /** 48944 * Set the URLs to use for requests. 48945 * @param {Array<string>}
48945 urls URLs. 48946 * @api 48947 */ 48948 setUrls(urls) { 48949 this.urls = urls; 48950 const key = urls.join('\n'); 48951 if (this.generateTileUrlFunction_) { 48952 this.setTileUrlFunction(createFromTemplates(urls, this.tileGrid), key); 48953 } else { 48954 this.setKey(key); 48955 } 48956 } 48957 48958 /** 48959 * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. 48960 * @param {number} pixelRatio Pixel ratio. 48961 * @param {import("../proj/Projection.js").default} projection Projection. 48962 * @return {string|undefined} Tile URL. 48963 */ 48964 tileUrlFunction(tileCoord, pixelRatio, projection) { 48965 return undefined; 48966 } 48967 48968 /** 48969 * Marks a tile coord as being used, without triggering a load. 48970 * @param {number} z Tile coordinate z. 48971 * @param {number} x Tile coordinate x. 48972 * @param {number} y Tile coordinate y. 48973 */ 48974 useTile(z, x, y) { 48975 const tileCoordKey = getKeyZXY(z, x, y); 48976 if (this.tileCache.containsKey(tileCoordKey)) { 48977 this.tileCache.get(tileCoordKey); 48978 } 48979 } 48980} 48981 48982/* harmony default export */ const source_UrlTile = (UrlTile); 48983 48984;// CONCATENATED MODULE: ./node_modules/ol/source/TileImage.js 48985/** 48986 * @module ol/source/TileImage 48987 */ 48988 48989 48990 48991 48992 48993 48994 48995 48996 48997 48998 48999/** 49000 * @typedef {Object} Options 49001 * @property {import("./Source.js").AttributionLike} [attributions] Attributions. 49002 * @property {boolean} [attributionsCollapsible=true] Attributions are collapsible. 49003 * @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport. 49004 * @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that 49005 * you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer. 49006 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail. 49007 * @property {boolean} [interpolate=true] Use interpolated values when resampling. By default, 49008 * linear interpolation is used when resampling. Set to false to use the nearest neighbor instead. 49009 * @property {boolean} [opaque=false] Whether the layer is opaque. 49010 * @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection. 49011 * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels). 49012 * Higher values can increase reprojection performance, but decrease precision. 49013 * @property {import("./Source.js").State} [state] Source state. 49014 * @property {typeof import("../ImageTile.js").default} [tileClass] Class used to instantiate image tiles. 49015 * Default is {@link module:ol/ImageTile~ImageTile}. 49016 * @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid. 49017 * @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is 49018 * ```js 49019 * function(imageTile, src) { 49020 * imageTile.getImage().src = src; 49021 * }; 49022 * ``` 49023 * @property {number} [tilePixelRatio=1] The pixel ratio used by the tile service. For example, if the tile 49024 * service advertizes 256px by 256px tiles but actually sends 512px 49025 * by 512px images (for retina/hidpi devices) then `tilePixelRatio` 49026 * should be set to `2`. 49027 * @property {import("../Tile.js").UrlFunction} [tileUrlFunction] Optional function to get tile URL given a tile coordinate and the projection. 49028 * @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders. 49029 * A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be 49030 * used instead of defining each one separately in the `urls` option. 49031 * @property {Array<string>} [urls] An array of URL templates. 49032 * @property {boolean} [wrapX] Whether to wrap the world horizontally. The default, is to 49033 * request out-of-bounds tiles from the server. When set to `false`, only one 49034 * world will be rendered. When set to `true`, tiles will be requested for one 49035 * world only, but they will be wrapped horizontally to render multiple worlds. 49036 * @property {number} [transition] Duration of the opacity transition for rendering. 49037 * To disable the opacity transition, pass `transition: 0`. 49038 * @property {string} [key] Optional tile key for proper cache fetching 49039 * @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] 49040 * Choose whether to use tiles with a higher or lower zoom level when between integer 49041 * zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}. 49042 */ 49043 49044/** 49045 * @classdesc
49046 * Base class for sources providing images divided into a tile grid. 49047 * 49048 * @fires import("./Tile.js").TileSourceEvent 49049 * @api 49050 */ 49051class TileImage extends source_UrlTile { 49052 /** 49053 * @param {!Options} options Image tile options. 49054 */ 49055 constructor(options) { 49056 super({ 49057 attributions: options.attributions, 49058 cacheSize: options.cacheSize, 49059 opaque: options.opaque, 49060 projection: options.projection, 49061 state: options.state, 49062 tileGrid: options.tileGrid, 49063 tileLoadFunction: options.tileLoadFunction 49064 ? options.tileLoadFunction 49065 : defaultTileLoadFunction, 49066 tilePixelRatio: options.tilePixelRatio, 49067 tileUrlFunction: options.tileUrlFunction, 49068 url: options.url, 49069 urls: options.urls, 49070 wrapX: options.wrapX, 49071 transition: options.transition, 49072 interpolate: 49073 options.interpolate !== undefined ? options.interpolate : true, 49074 key: options.key, 49075 attributionsCollapsible: options.attributionsCollapsible, 49076 zDirection: options.zDirection, 49077 }); 49078 49079 /** 49080 * @protected 49081 * @type {?string} 49082 */ 49083 this.crossOrigin = 49084 options.crossOrigin !== undefined ? options.crossOrigin : null; 49085 49086 /** 49087 * @protected 49088 * @type {typeof ImageTile} 49089 */ 49090 this.tileClass = 49091 options.tileClass !== undefined ? options.tileClass : ol_ImageTile; 49092 49093 /** 49094 * @protected 49095 * @type {!Object<string, TileCache>} 49096 */ 49097 this.tileCacheForProjection = {}; 49098 49099 /** 49100 * @protected 49101 * @type {!Object<string, import("../tilegrid/TileGrid.js").default>} 49102 */ 49103 this.tileGridForProjection = {}; 49104 49105 /** 49106 * @private 49107 * @type {number|undefined} 49108 */ 49109 this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold; 49110 49111 /** 49112 * @private 49113 * @type {boolean} 49114 */ 49115 this.renderReprojectionEdges_ = false;
49116 } 49117 49118 /** 49119 * @return {boolean} Can expire cache. 49120 */ 49121 canExpireCache() { 49122 if (this.tileCache.canExpireCache()) { 49123 return true; 49124 } else { 49125 for (const key in this.tileCacheForProjection) { 49126 if (this.tileCacheForProjection[key].canExpireCache()) { 49127 return true; 49128 } 49129 } 49130 } 49131 return false; 49132 } 49133 49134 /** 49135 * @param {import("../proj/Projection.js").default} projection Projection. 49136 * @param {!Object<string, boolean>} usedTiles Used tiles. 49137 */ 49138 expireCache(projection, usedTiles) { 49139 const usedTileCache = this.getTileCacheForProjection(projection); 49140 49141 this.tileCache.expireCache( 49142 this.tileCache == usedTileCache ? usedTiles : {} 49143 ); 49144 for (const id in this.tileCacheForProjection) { 49145 const tileCache = this.tileCacheForProjection[id]; 49146 tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {}); 49147 } 49148 } 49149 49150 /** 49151 * @param {import("../proj/Projection.js").default} projection Projection. 49152 * @return {number} Gutter. 49153 */ 49154 getGutterForProjection(projection) { 49155 if ( 49156 this.getProjection() && 49157 projection && 49158 !equivalent(this.getProjection(), projection) 49159 ) { 49160 return 0; 49161 } else { 49162 return this.getGutter(); 49163 } 49164 } 49165 49166 /** 49167 * @return {number} Gutter. 49168 */ 49169 getGutter() { 49170 return 0; 49171 } 49172 49173 /** 49174 * Return the key to be used for all tiles in the source. 49175 * @return {string} The key for all tiles. 49176 */ 49177 getKey() { 49178 let key = super.getKey(); 49179 if (!this.getInterpolate()) { 49180 key += ':disable-interpolation'; 49181 } 49182 return key; 49183 } 49184 49185 /** 49186 * @param {import("../proj/Projection.js").default} projection Projection. 49187 * @return {boolean} Opaque. 49188 */ 49189 getOpaque(projection) { 49190 if ( 49191 this.getProjection() && 49192 projection && 49193 !equivalent(this.getProjection(), projection) 49194 ) { 49195 return false; 49196 } else { 49197 return super.getOpaque(projection); 49198 } 49199 } 49200 49201 /** 49202 * @param {import("../proj/Projection.js").default} projection Projection. 49203 * @return {!import("../tilegrid/TileGrid.js").default} Tile grid. 49204 */ 49205 getTileGridForProjection(projection) { 49206 const thisProj = this.getProjection(); 49207 if (this.tileGrid && (!thisProj || equivalent(thisProj, projection))) { 49208 return this.tileGrid; 49209 } else { 49210 const projKey = getUid(projection); 49211 if (!(projKey in this.tileGridForProjection)) { 49212 this.tileGridForProjection[projKey] = 49213 getForProjection(projection); 49214 } 49215 return this.tileGridForProjection[projKey]; 49216 } 49217 } 49218 49219 /** 49220 * @param {import("../proj/Projection.js").default} projection Projection. 49221 * @return {import("../TileCache.js").default} Tile cache. 49222 */ 49223 getTileCacheForProjection(projection) { 49224 const thisProj = this.getProjection(); 49225 if (!thisProj || equivalent(thisProj, projection)) { 49226 return this.tileCache; 49227 } else { 49228 const projKey = getUid(projection); 49229 if (!(projKey in this.tileCacheForProjection)) { 49230 this.tileCacheForProjection[projKey] = new ol_TileCache( 49231 this.tileCache.highWaterMark 49232 ); 49233 } 49234 return this.tileCacheForProjection[projKey]; 49235 } 49236 } 49237 49238 /** 49239 * @param {number} z Tile coordinate z. 49240 * @param {number} x Tile coordinate x. 49241 * @param {number} y Tile coordinate y. 49242 * @param {number} pixelRatio Pixel ratio. 49243 * @param {import("../proj/Projection.js").default} projection Projection. 49244 * @param {string} key The key set on the tile. 49245 * @return {!ImageTile} Tile. 49246 * @private 49247 */ 49248 createTile_(z, x, y, pixelRatio, projection, key) { 49249 const tileCoord = [z, x, y]; 49250 const urlTileCoord = this.getTileCoordForTileUrlFunction( 49251 tileCoord, 49252 projection 49253 ); 49254 const tileUrl = urlTileCoord 49255 ? this.tileUrlFunction(urlTileCoord, pixelRatio, projection) 49256 : undefined; 49257 const tile = new this.tileClass( 49258 tileCoord, 49259 tileUrl !== undefined ? TileState.IDLE : TileState.EMPTY, 49260 tileUrl !== undefined ? tileUrl : '', 49261 this.crossOrigin, 49262 this.tileLoadFunction, 49263 this.tileOptions 49264 ); 49265 tile.key = key; 49266 tile.addEventListener(EventType.CHANGE, this.handleTileChange.bind(this)); 49267 return tile; 49268 } 49269 49270 /** 49271 * @param {number} z Tile coordinate z. 49272 * @param {number} x Tile coordinate x. 49273 * @param {number} y Tile coordinate y. 49274 * @param {number} pixelRatio Pixel ratio. 49275 * @param {import("../proj/Projection.js").default} projection Projection. 49276 * @return {!(ImageTile|ReprojTile)} Tile. 49277 */ 49278 getTile(z, x, y, pixelRatio, projection) { 49279 const sourceProjection = this.getProjection(); 49280 if ( 49281 !sourceProjection || 49282 !projection || 49283 equivalent(sourceProjection, projection) 49284 ) { 49285 return this.getTileInternal( 49286 z, 49287 x, 49288 y, 49289 pixelRatio, 49290 sourceProjection || projection 49291 ); 49292 } else { 49293 const cache = this.getTileCacheForProjection(projection); 49294 const tileCoord = [z, x, y]; 49295 let tile; 49296 const tileCoordKey = tilecoord_getKey(tileCoord); 49297 if (cache.containsKey(tileCoordKey)) { 49298 tile = cache.get(tileCoordKey); 49299 }
49300 const key = this.getKey(); 49301 if (tile && tile.key == key) { 49302 return tile; 49303 } else { 49304 const sourceTileGrid = this.getTileGridForProjection(sourceProjection); 49305 const targetTileGrid = this.getTileGridForProjection(projection); 49306 const wrappedTileCoord = this.getTileCoordForTileUrlFunction( 49307 tileCoord, 49308 projection 49309 ); 49310 const newTile = new reproj_Tile( 49311 sourceProjection, 49312 sourceTileGrid, 49313 projection, 49314 targetTileGrid, 49315 tileCoord, 49316 wrappedTileCoord, 49317 this.getTilePixelRatio(pixelRatio), 49318 this.getGutter(), 49319 function (z, x, y, pixelRatio) { 49320 return this.getTileInternal(z, x, y, pixelRatio, sourceProjection); 49321 }.bind(this), 49322 this.reprojectionErrorThreshold_, 49323 this.renderReprojectionEdges_, 49324 this.getInterpolate() 49325 ); 49326 newTile.key = key; 49327 49328 if (tile) { 49329 newTile.interimTile = tile; 49330 newTile.refreshInterimChain(); 49331 cache.replace(tileCoordKey, newTile); 49332 } else { 49333 cache.set(tileCoordKey, newTile); 49334 } 49335 return newTile; 49336 } 49337 } 49338 } 49339 49340 /** 49341 * @param {number} z Tile coordinate z. 49342 * @param {number} x Tile coordinate x. 49343 * @param {number} y Tile coordinate y. 49344 * @param {number} pixelRatio Pixel ratio. 49345 * @param {!import("../proj/Projection.js").default} projection Projection. 49346 * @return {!(ImageTile|ReprojTile)} Tile. 49347 * @protected 49348 */ 49349 getTileInternal(z, x, y, pixelRatio, projection) { 49350 let tile = null; 49351 const tileCoordKey = getKeyZXY(z, x, y); 49352 const key = this.getKey(); 49353 if (!this.tileCache.containsKey(tileCoordKey)) { 49354 tile = this.createTile_(z, x, y, pixelRatio, projection, key); 49355 this.tileCache.set(tileCoordKey, tile); 49356 } else { 49357 tile = this.tileCache.get(tileCoordKey); 49358 if (tile.key != key) { 49359 // The source's params changed. If the tile has an interim tile and if we 49360 // can use it then we use it. Otherwise we create a new tile. In both 49361 // cases we attempt to assign an interim tile to the new tile. 49362 const interimTile = tile; 49363 tile = this.createTile_(z, x, y, pixelRatio, projection, key); 49364 49365 //make the new tile the head of the list, 49366 if (interimTile.getState() == TileState.IDLE) { 49367 //the old tile hasn't begun loading yet, and is now outdated, so we can simply discard it 49368 tile.interimTile = interimTile.interimTile; 49369 } else { 49370 tile.interimTile = interimTile; 49371 } 49372 tile.refreshInterimChain(); 49373 this.tileCache.replace(tileCoordKey, tile); 49374 } 49375 } 49376 return tile; 49377 } 49378 49379 /** 49380 * Sets whether to render reprojection edges or not (usually for debugging). 49381 * @param {boolean} render Render the edges. 49382 * @api 49383 */ 49384 setRenderReprojectionEdges(render) { 49385 if (this.renderReprojectionEdges_ == render) { 49386 return; 49387 } 49388 this.renderReprojectionEdges_ = render; 49389 for (const id in this.tileCacheForProjection) { 49390 this.tileCacheForProjection[id].clear(); 49391 } 49392 this.changed(); 49393 } 49394 49395 /** 49396 * Sets the tile grid to use when reprojecting the tiles to the given 49397 * projection instead of the default tile grid for the projection. 49398 * 49399 * This can be useful when the default tile grid cannot be created 49400 * (e.g. projection has no extent defined) or 49401 * for optimization reasons (custom tile size, resolutions, ...). 49402 * 49403 * @param {import("../proj.js").ProjectionLike} projection Projection. 49404 * @param {import("../tilegrid/TileGrid.js").default} tilegrid Tile grid to use for the projection. 49405 * @api 49406 */ 49407 setTileGridForProjection(projection, tilegrid) { 49408 const proj = proj_get(projection); 49409 if (proj) { 49410 const projKey = getUid(proj); 49411 if (!(projKey in this.tileGridForProjection)) { 49412 this.tileGridForProjection[projKey] = tilegrid; 49413 } 49414 } 49415 } 49416 49417 clear() { 49418 super.clear(); 49419 for (const id in this.tileCacheForProjection) { 49420 this.tileCacheForProjection[id].clear(); 49421 } 49422 } 49423} 49424 49425/** 49426 * @param {ImageTile} imageTile Image tile. 49427 * @param {string} src Source. 49428 */ 49429function defaultTileLoadFunction(imageTile, src) { 49430 /** @type {HTMLImageElement|HTMLVideoElement} */ (imageTile.getImage()).src = 49431 src; 49432} 49433 49434/* harmony default export */ const source_TileImage = (TileImage); 49435 49436;// CONCATENATED MODULE: ./node_modules/ol/source/XYZ.js 49437/** 49438 * @module ol/source/XYZ 49439 */ 49440 49441 49442 49443 49444/** 49445 * @typedef {Object} Options 49446 * @property {import("./Source.js").AttributionLike} [attributions] Attributions. 49447 * @property {boolean} [attributionsCollapsible=true] Attributions are collapsible. 49448 * @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport. 49449 * @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that 49450 * you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer. 49451 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_
49451image for more detail. 49452 * @property {boolean} [interpolate=true] Use interpolated values when resampling. By default, 49453 * linear interpolation is used when resampling. Set to false to use the nearest neighbor instead. 49454 * @property {boolean} [opaque=false] Whether the layer is opaque. 49455 * @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection. 49456 * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels). 49457 * Higher values can increase reprojection performance, but decrease precision. 49458 * @property {number} [maxZoom=42] Optional max zoom level. Not used if `tileGrid` is provided. 49459 * @property {number} [minZoom=0] Optional min zoom level. Not used if `tileGrid` is provided. 49460 * @property {number} [maxResolution] Optional tile grid resolution at level zero. Not used if `tileGrid` is provided. 49461 * @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid. 49462 * @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is 49463 * ```js 49464 * function(imageTile, src) { 49465 * imageTile.getImage().src = src; 49466 * }; 49467 * ``` 49468 * @property {number} [tilePixelRatio=1] The pixel ratio used by the tile service. 49469 * For example, if the tile service advertizes 256px by 256px tiles but actually sends 512px 49470 * by 512px images (for retina/hidpi devices) then `tilePixelRatio` 49471 * should be set to `2`. 49472 * @property {number|import("../size.js").Size} [tileSize=[256, 256]] The tile size used by the tile service. 49473 * Not used if `tileGrid` is provided. 49474 * @property {number} [gutter=0] The size in pixels of the gutter around image tiles to ignore. 49475 * This allows artifacts of rendering at tile edges to be ignored. 49476 * Supported images should be wider and taller than the tile size by a value of `2 x gutter`. 49477 * @property {import("../Tile.js").UrlFunction} [tileUrlFunction] Optional function to get 49478 * tile URL given a tile coordinate and the projection. 49479 * Required if `url` or `urls` are not provided. 49480 * @property {string} [url] URL template. Must include `{x}`, `{y}` or `{-y}`, 49481 * and `{z}` placeholders. A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, 49482 * may be used instead of defining each one separately in the `urls` option. 49483 * @property {Array<string>} [urls] An array of URL templates. 49484 * @property {boolean} [wrapX=true] Whether to wrap the world horizontally. 49485 * @property {number} [transition=250] Duration of the opacity transition for rendering. 49486 * To disable the opacity transition, pass `transition: 0`. 49487 * @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] 49488 * Choose whether to use tiles with a higher or lower zoom level when between integer 49489 * zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}. 49490 */ 49491 49492/** 49493 * @classdesc 49494 * Layer source for tile data with URLs in a set XYZ format that are 49495 * defined in a URL template. By default, this follows the widely-used 49496 * Google grid where `x` 0 and `y` 0 are in the top left. Grids like 49497 * TMS where `x` 0 and `y` 0 are in the bottom left can be used by 49498 * using the `{-y}` placeholder in the URL template, so long as the 49499 * source does not have a custom tile grid. In this case 49500 * a `tileUrlFunction` can be used, such as: 49501 * ```js 49502 * tileUrlFunction: function(coordinate) { 49503 * return 'http://mapserver.com/' + coordinate[0] + '/' + 49504 * coordinate[1] + '/' + (-coordinate[2] - 1) + '.png'; 49505 * } 49506 * ``` 49507 * @api 49508 */ 49509class XYZ_XYZ extends source_TileImage { 49510 /** 49511 * @param {Options} [options] XYZ options. 49512 */ 49513 constructor(options) { 49514 options = options || {}; 49515 49516 const projection = 49517 options.projection !== undefined ? options.projection : 'EPSG:3857'; 49518 49519 const tileGrid = 49520 options.tileGrid !== undefined 49521 ? options.tileGrid 49522 : createXYZ({ 49523 extent: extentFromProjection(projection), 49524 maxResolution: options.maxResolution, 49525 maxZoom: options.maxZoom, 49526 minZoom: options.minZoom, 49527 tileSize: options.tileSize, 49528 }); 49529 49530 super({ 49531 attributions: options.attributions, 49532 cacheSize: options.cacheSize, 49533 crossOrigin: options.crossOrigin, 49534 interpolate: options.interpolate, 49535 opaque: options.opaque, 49536 projection: projection, 49537 reprojectionErrorThreshold: options.reprojectionErrorThreshold, 49538 tileGrid: tileGrid, 49539 tileLoadFunction: options.tileLoadFunction, 49540 tilePixelRatio: options.tilePixelRatio, 49541 tileUrlFunction: options.tileUrlFunction, 49542 url: options.url, 49543 urls: options.urls, 49544 wrapX: options.wrapX !== undefined ? options.wrapX : true, 49545 transition: options.transition, 49546 attributionsCollapsible: options.attributionsCollapsible, 49547 zDirection: options.zDirection, 49548 }); 49549 49550 /** 49551 * @private 49552 * @type {number} 49553 */ 49554 this.gutter_ = options.gutter !== undefined ? options.gutter : 0; 49555 } 49556 49557 /** 49558 * @return {number} Gutter. 49559 */ 49560 getGutter() { 49561 return this.gutter_; 49562 } 49563} 49564 49565/* harmony default export */ const source_XYZ = (XYZ_XYZ); 49566 49567;// CONCATENATED MODULE: ./node_modules/ol/structs/RBush.js 49568/**
49569 * @module ol/structs/RBush 49570 */ 49571 49572 49573 49574 49575 49576/** 49577 * @typedef {Object} Entry 49578 * @property {number} minX MinX. 49579 * @property {number} minY MinY. 49580 * @property {number} maxX MaxX. 49581 * @property {number} maxY MaxY. 49582 * @property {Object} [value] Value. 49583 */ 49584 49585/** 49586 * @classdesc 49587 * Wrapper around the RBush by Vladimir Agafonkin. 49588 * See https://github.com/mourner/rbush. 49589 * 49590 * @template T 49591 */ 49592class RBush { 49593 /** 49594 * @param {number} [maxEntries] Max entries. 49595 */ 49596 constructor(maxEntries) { 49597 /** 49598 * @private 49599 */ 49600 this.rbush_ = new rbush_min(maxEntries); 49601 49602 /** 49603 * A mapping between the objects added to this rbush wrapper 49604 * and the objects that are actually added to the internal rbush. 49605 * @private 49606 * @type {Object<string, Entry>} 49607 */ 49608 this.items_ = {}; 49609 } 49610 49611 /** 49612 * Insert a value into the RBush. 49613 * @param {import("../extent.js").Extent} extent Extent. 49614 * @param {T} value Value. 49615 */ 49616 insert(extent, value) { 49617 /** @type {Entry} */ 49618 const item = { 49619 minX: extent[0], 49620 minY: extent[1], 49621 maxX: extent[2], 49622 maxY: extent[3], 49623 value: value, 49624 }; 49625 49626 this.rbush_.insert(item); 49627 this.items_[getUid(value)] = item; 49628 } 49629 49630 /** 49631 * Bulk-insert values into the RBush. 49632 * @param {Array<import("../extent.js").Extent>} extents Extents. 49633 * @param {Array<T>} values Values. 49634 */ 49635 load(extents, values) { 49636 const items = new Array(values.length); 49637 for (let i = 0, l = values.length; i < l; i++) { 49638 const extent = extents[i]; 49639 const value = values[i]; 49640 49641 /** @type {Entry} */ 49642 const item = { 49643 minX: extent[0], 49644 minY: extent[1], 49645 maxX: extent[2], 49646 maxY: extent[3], 49647 value: value, 49648 }; 49649 items[i] = item; 49650 this.items_[getUid(value)] = item; 49651 } 49652 this.rbush_.load(items); 49653 } 49654 49655 /** 49656 * Remove a value from the RBush. 49657 * @param {T} value Value. 49658 * @return {boolean} Removed. 49659 */ 49660 remove(value) { 49661 const uid = getUid(value); 49662 49663 // get the object in which the value was wrapped when adding to the 49664 // internal rbush. then use that object to do the removal. 49665 const item = this.items_[uid]; 49666 delete this.items_[uid]; 49667 return this.rbush_.remove(item) !== null; 49668 } 49669 49670 /** 49671 * Update the extent of a value in the RBush. 49672 * @param {import("../extent.js").Extent} extent Extent. 49673 * @param {T} value Value. 49674 */ 49675 update(extent, value) { 49676 const item = this.items_[getUid(value)]; 49677 const bbox = [item.minX, item.minY, item.maxX, item.maxY]; 49678 if (!extent_equals(bbox, extent)) { 49679 this.remove(value); 49680 this.insert(extent, value); 49681 } 49682 } 49683 49684 /** 49685 * Return all values in the RBush. 49686 * @return {Array<T>} All. 49687 */ 49688 getAll() { 49689 const items = this.rbush_.all(); 49690 return items.map(function (item) { 49691 return item.value; 49692 }); 49693 } 49694 49695 /** 49696 * Return all values in the given extent. 49697 * @param {import("../extent.js").Extent} extent Extent. 49698 * @return {Array<T>} All in extent. 49699 */ 49700 getInExtent(extent) { 49701 /** @type {Entry} */ 49702 const bbox = { 49703 minX: extent[0], 49704 minY: extent[1], 49705 maxX: extent[2], 49706 maxY: extent[3], 49707 }; 49708 const items = this.rbush_.search(bbox); 49709 return items.map(function (item) { 49710 return item.value; 49711 }); 49712 } 49713 49714 /** 49715 * Calls a callback function with each value in the tree. 49716 * If the callback returns a truthy value, this value is returned without 49717 * checking the rest of the tree. 49718 * @param {function(T): *} callback Callback. 49719 * @return {*} Callback return value. 49720 */ 49721 forEach(callback) { 49722 return this.forEach_(this.getAll(), callback); 49723 } 49724 49725 /** 49726 * Calls a callback function with each value in the provided extent. 49727 * @param {import("../extent.js").Extent} extent Extent. 49728 * @param {function(T): *} callback Callback. 49729 * @return {*} Callback return value. 49730 */ 49731 forEachInExtent(extent, callback) { 49732 return this.forEach_(this.getInExtent(extent), callback); 49733 } 49734 49735 /** 49736 * @param {Array<T>} values Values. 49737 * @param {function(T): *} callback Callback. 49738 * @private 49739 * @return {*} Callback return value. 49740 */ 49741 forEach_(values, callback) { 49742 let result; 49743 for (let i = 0, l = values.length; i < l; i++) { 49744 result = callback(values[i]); 49745 if (result) { 49746 return result; 49747 } 49748 } 49749 return result; 49750 } 49751 49752 /** 49753 * @return {boolean} Is empty. 49754 */ 49755 isEmpty() { 49756 return obj_isEmpty(this.items_); 49757 } 49758 49759 /** 49760 * Remove all values from the RBush. 49761 */ 49762 clear() { 49763 this.rbush_.clear(); 49764 this.items_ = {}; 49765 } 49766 49767 /** 49768 * @param {import("../extent.js").Extent} [extent] Extent. 49769 * @return {import("../extent.js").Extent} Extent. 49770 */ 49771 getExtent(extent) { 49772 const data = this.rbush_.toJSON(); 49773 return createOrUpdate(data.minX, data.minY, data.maxX, data.maxY, extent); 49774 } 49775 49776 /** 49777 * @param {RBush} rbush R-Tree. 49778 */ 49779 concat(rbush) { 49780 this.rbush_.load(rbush.rbush_.all()); 49781 for (const i in rbush.items_) { 49782 this.items_[i] = rbush.items_[i]; 49783 } 49784 } 49785} 49786 49787/* harmony default export */ const structs_RBush = (RBush); 49788 49789;// CONCATENATED MODULE: ./node_modules/ol/source/VectorEventType.js 49790/** 49791 * @module ol/source/VectorEventType 49792 */ 49793 49794/** 49795 * @enum {string} 49796 */ 49797/* harmony default export */ const VectorEventType = ({ 49798 /** 49799 * Triggered when a feature is added to the source. 49800 * @event module:ol/source/Vector.VectorSourceEvent#addfeature 49801 * @api 49802 */ 49803 ADDFEATURE: 'addfeature', 49804 49805 /** 49806 * Triggered when a feature is updated. 49807 * @event module:ol/source/Vector.VectorSourceEvent#changefeature 49808 * @api 49809 */ 49810 CHANGEFEATURE: 'changefeature', 49811 49812 /** 49813 * Triggered when the clear method is called on the source. 49814 * @event module:ol/source/Vector.VectorSourceEvent#clear 49815 * @api 49816 */ 49817 CLEAR: 'clear', 49818 49819 /** 49820 * Triggered when a feature is removed from the source. 49821 * See {@link module:ol/source/Vector~VectorSource#clear source.clear()} for exceptions. 49822 * @event module:ol/source/Vector.VectorSourceEvent#removefeature 49823 * @api 49824 */ 49825 REMOVEFEATURE: 'removefeature', 49826 49827 /** 49828 * Triggered when features starts loading. 49829 * @event module:ol/source/Vector.VectorSourceEvent#featuresloadstart 49830 * @api 49831 */ 49832 FEATURESLOADSTART: 'featuresloadstart', 49833 49834 /** 49835 * Triggered when features finishes loading. 49836 * @event module:ol/source/Vector.VectorSourceEvent#featuresloadend 49837 * @api 49838 */ 49839 FEATURESLOADEND: 'featuresloadend', 49840 49841 /** 49842 * Triggered if feature loading results in an error. 49843 * @event module:ol/source/Vector.VectorSourceEvent#featuresloaderror 49844 * @api 49845 */ 49846 FEATURESLOADERROR: 'featuresloaderror', 49847}); 49848 49849/** 49850 * @typedef {'addfeature'|'changefeature'|'clear'|'removefeature'|'featuresloadstart'|'featuresloadend'|'featuresloaderror'} VectorSourceEventTypes 49851 */ 49852 49853;// CONCATENATED MODULE: ./node_modules/ol/loadingstrategy.js 49854/** 49855 * @module ol/loadingstrategy 49856 */ 49857 49858 49859 49860/** 49861 * Strategy function for loading all features with a single request. 49862 * @param {import("./extent.js").Extent} extent Extent. 49863 * @param {number} resolution Resolution. 49864 * @return {Array<import("./extent.js").Extent>} Extents. 49865 * @api 49866 */
49867function loadingstrategy_all(extent, resolution) { 49868 return [[-Infinity, -Infinity, Infinity, Infinity]]; 49869} 49870 49871/** 49872 * Strategy function for loading features based on the view's extent and 49873 * resolution. 49874 * @param {import("./extent.js").Extent} extent Extent. 49875 * @param {number} resolution Resolution. 49876 * @return {Array<import("./extent.js").Extent>} Extents. 49877 * @api 49878 */ 49879function bbox(extent, resolution) { 49880 return [extent]; 49881} 49882 49883/** 49884 * Creates a strategy function for loading features based on a tile grid. 49885 * @param {import("./tilegrid/TileGrid.js").default} tileGrid Tile grid. 49886 * @return {function(import("./extent.js").Extent, number, import("./proj.js").Projection): Array<import("./extent.js").Extent>} Loading strategy. 49887 * @api 49888 */ 49889function tile(tileGrid) { 49890 return ( 49891 /** 49892 * @param {import("./extent.js").Extent} extent Extent. 49893 * @param {number} resolution Resolution. 49894 * @param {import("./proj.js").Projection} projection Projection. 49895 * @return {Array<import("./extent.js").Extent>} Extents. 49896 */ 49897 function (extent, resolution, projection) { 49898 const z = tileGrid.getZForResolution( 49899 fromUserResolution(resolution, projection) 49900 ); 49901 const tileRange = tileGrid.getTileRangeForExtentAndZ( 49902 fromUserExtent(extent, projection), 49903 z 49904 ); 49905 /** @type {Array<import("./extent.js").Extent>} */ 49906 const extents = []; 49907 /** @type {import("./tilecoord.js").TileCoord} */ 49908 const tileCoord = [z, 0, 0]; 49909 for ( 49910 tileCoord[1] = tileRange.minX; 49911 tileCoord[1] <= tileRange.maxX; 49912 ++tileCoord[1] 49913 ) { 49914 for ( 49915 tileCoord[2] = tileRange.minY; 49916 tileCoord[2] <= tileRange.maxY; 49917 ++tileCoord[2] 49918 ) { 49919 extents.push( 49920 toUserExtent(tileGrid.getTileCoordExtent(tileCoord), projection) 49921 ); 49922 } 49923 } 49924 return extents; 49925 } 49926 ); 49927} 49928 49929;// CONCATENATED MODULE: ./node_modules/ol/featureloader.js 49930/** 49931 * @module ol/featureloader 49932 */ 49933 49934 49935/** 49936 * 49937 * @type {boolean} 49938 * @private 49939 */ 49940let withCredentials = false; 49941 49942/** 49943 * {@link module:ol/source/Vector~VectorSource} sources use a function of this type to 49944 * load features. 49945 * 49946 * This function takes up to 5 arguments. These are an {@link module:ol/extent~Extent} representing 49947 * the area to be loaded, a `{number}` representing the resolution (map units per pixel), an 49948 * {@link module:ol/proj/Projection~Projection} for the projection, an optional success callback that should get 49949 * the loaded features passed as an argument and an optional failure callback with no arguments. If 49950 * the callbacks are not used, the corresponding vector source will not fire `'featuresloadend'` and 49951 * `'featuresloaderror'` events. `this` within the function is bound to the 49952 * {@link module:ol/source/Vector~VectorSource} it's called from. 49953 * 49954 * The function is responsible for loading the features and adding them to the 49955 * source. 49956 * @typedef {function(this:(import("./source/Vector").default|import("./VectorTile.js").default), 49957 * import("./extent.js").Extent, 49958 * number, 49959 * import("./proj/Projection.js").default, 49960 * function(Array<import("./Feature.js").default>): void=, 49961 * function(): void=): void} FeatureLoader 49962 * @api 49963 */ 49964 49965/** 49966 * {@link module:ol/source/Vector~VectorSource} sources use a function of this type to 49967 * get the url to load features from. 49968 * 49969 * This function takes an {@link module:ol/extent~Extent} representing the area 49970 * to be loaded, a `{number}` representing the resolution (map units per pixel) 49971 * and an {@link module:ol/proj/Projection~Projection} for the projection as 49972 * arguments and returns a `{string}` representing the URL. 49973 * @typedef {function(import("./extent.js").Extent, number, import("./proj/Projection.js").default): string} FeatureUrlFunction 49974 * @api 49975 */ 49976 49977/** 49978 * @param {string|FeatureUrlFunction} url Feature URL service. 49979 * @param {import("./format/Feature.js").default} format Feature format. 49980 * @param {import("./extent.js").Extent} extent Extent. 49981 * @param {number} resolution Resolution. 49982 * @param {import("./proj/Projection.js").default} projection Projection. 49983 * @param {function(Array<import("./Feature.js").default>, import("./proj/Projection.js").default): void} success Success 49984 * Function called with the loaded features and optionally with the data projection. 49985 * @param {function(): void} failure Failure 49986 * Function called when loading failed. 49987 */ 49988function loadFeaturesXhr( 49989 url, 49990 format, 49991 extent, 49992 resolution, 49993 projection, 49994 success, 49995 failure 49996) { 49997 const xhr = new XMLHttpRequest(); 49998 xhr.open( 49999 'GET', 50000 typeof url === 'function' ? url(extent, resolution, projection) : url, 50001 true 50002 ); 50003 if (format.getType() == 'arraybuffer') { 50004 xhr.responseType = 'arraybuffer'; 50005 } 50006 xhr.withCredentials = withCredentials; 50007 /** 50008 * @param {Event} event Event. 50009 * @private 50010 */ 50011 xhr.onload = function (event) { 50012 // status will be 0 for file:// urls 50013 if (!xhr.status || (xhr.status >= 200 && xhr.status < 300)) { 50014 const type = format.getType(); 50015 /** @type {Document|Node|Object|string|undefined} */ 50016 let source; 50017 if (type == 'json' || type == 'text') { 50018 source = xhr.responseText; 50019 } else if (type == 'xml') { 50020 source = xhr.responseXML; 50021 if (!source) { 50022 source = new DOMParser().parseFromString( 50023 xhr.responseText, 50024 'application/xml' 50025 ); 50026 } 50027 } else if (type == 'arraybuffer') { 50028 source = /** @type {ArrayBuffer} */ (xhr.response); 50029 } 50030 if (source) { 50031 success( 50032 /** @type {Array<import("./Feature.js").default>} */ 50033 ( 50034 format.readFeatures(source, { 50035 extent: extent, 50036 featureProjection: projection, 50037 }) 50038 ), 50039 format.readProjection(source) 50040 ); 50041 } else { 50042 failure(); 50043 } 50044 } else { 50045 failure(); 50046 } 50047 }; 50048 /** 50049 * @private 50050 */ 50051 xhr.onerror = failure; 50052 xhr.send(); 50053} 50054 50055/** 50056 * Create an XHR feature loader for a `url` and `format`. The feature loader 50057 * loads features (with XHR), parses the features, and adds them to the 50058 * vector source. 50059 * @param {string|FeatureUrlFunction} url Feature URL service. 50060 * @param {import("./format/Feature.js").default} format Feature format. 50061 * @return {FeatureLoader} The feature loader. 50062 * @api 50063 */ 50064function xhr(url, format) { 50065 /** 50066 * @param {import("./extent.js").Extent} extent Extent. 50067 * @param {number} resolution Resolution. 50068 * @param {import("./proj/Projection.js").default} projection Projection. 50069 * @param {function(Array<import("./Feature.js").default>): void} [success] Success 50070 * Function called when loading succeeded. 50071 * @param {function(): void} [failure] Failure 50072 * Function called when loading failed. 50073 * @this {import("./source/Vector").default} 50074 */ 50075 return function (extent, resolution, projection, success, failure) { 50076 const source = /** @type {import("./source/Vector").default} */ (this); 50077 loadFeaturesXhr( 50078 url, 50079 format, 50080 extent, 50081 resolution, 50082 projection, 50083 /** 50084 * @param {Array<import("./Feature.js").default>} features The loaded features. 50085 * @param {import("./proj/Projection.js").default} dataProjection Data 50086 * projection. 50087 */ 50088 function (features, dataProjection) { 50089 source.addFeatures(features); 50090 if (success !== undefined) { 50091 success(features); 50092 } 50093 }, 50094 /* FIXME handle error */ failure ? failure : VOID 50095 ); 50096 }; 50097} 50098 50099/** 50100 * Setter for the withCredentials configuration for the XHR. 50101 * 50102 * @param {boolean} xhrWithCredentials The value of withCredentials to set. 50103 * Compare https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/ 50104 * @api 50105 */ 50106function setWithCredentials(xhrWithCredentials) { 50107 withCredentials = xhrWithCredentials; 50108} 50109 50110;// CONCATENATED MODULE: ./node_modules/ol/source/Vector.js 50111/** 50112 * @module ol/source/Vector 50113 */ 50114 50115 50116 50117 50118 50119 50120 50121 50122 50123 50124 50125 50126 50127 50128 50129 50130 50131 50132 50133/** 50134 * A function that takes an {@link module:ol/extent~Extent} and a resolution as arguments, and 50135 * returns an array of {@link module:ol/extent~Extent} with the extents to load. Usually this 50136 * is one of the standard {@link module:ol/loadingstrategy} strategies. 50137 * 50138 * @typedef {function(import("../extent.js").Extent, number, import("../proj/Projection.js").default): Array<import("../extent.js").Extent>} LoadingStrategy 50139 * @api 50140 */ 50141 50142/** 50143 * @classdesc 50144 * Events emitted by {@link module:ol/source/Vector~VectorSource} instances are instances of this 50145 * type. 50146 * @template {import("../geom/Geometry.js").default} [Geometry=import("../geom/Geometry.js").default] 50147 */
50148class VectorSourceEvent extends Event { 50149 /** 50150 * @param {string} type Type. 50151 * @param {import("../Feature.js").default<Geometry>} [feature] Feature. 50152 * @param {Array<import("../Feature.js").default<Geometry>>} [features] Features. 50153 */ 50154 constructor(type, feature, features) { 50155 super(type); 50156 50157 /** 50158 * The added or removed feature for the `ADDFEATURE` and `REMOVEFEATURE` events, `undefined` otherwise. 50159 * @type {import("../Feature.js").default<Geometry>|undefined} 50160 * @api 50161 */ 50162 this.feature = feature; 50163 50164 /** 50165 * The loaded features for the `FEATURESLOADED` event, `undefined` otherwise. 50166 * @type {Array<import("../Feature.js").default<Geometry>>|undefined} 50167 * @api 50168 */ 50169 this.features = features; 50170 } 50171} 50172 50173/*** 50174 * @template Return 50175 * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> & 50176 * import("../Observable").OnSignature<import("../ObjectEventType").Types, import("../Object").ObjectEvent, Return> & 50177 * import("../Observable").OnSignature<import("./VectorEventType").VectorSourceEventTypes, VectorSourceEvent, Return> & 50178 * import("../Observable").CombinedOnSignature<import("../Observable").EventTypes|import("../ObjectEventType").Types| 50179 * import("./VectorEventType").VectorSourceEventTypes, Return>} VectorSourceOnSignature 50180 */ 50181 50182/** 50183 * @typedef {Object} Options 50184 * @property {import("./Source.js").AttributionLike} [attributions] Attributions. 50185 * @property {Array<import("../Feature.js").default<Geometry>>|Collection<import("../Feature.js").default<Geometry>>} [features] 50186 * Features. If provided as {@link module:ol/Collection~Collection}, the features in the source 50187 * and the collection will stay in sync. 50188 * @property {import("../format/Feature.js").default} [format] The feature format used by the XHR 50189 * feature loader when `url` is set. Required if `url` is set, otherwise ignored. 50190 * @property {import("../featureloader.js").FeatureLoader} [loader] 50191 * The loader function used to load features, from a remote source for example. 50192 * If this is not set and `url` is set, the source will create and use an XHR 50193 * feature loader. The `'featuresloadend'` and `'featuresloaderror'` events 50194 * will only fire if the `success` and `failure` callbacks are used. 50195 * 50196 * Example: 50197 * 50198 * ```js 50199 * import {Vector} from 'ol/source'; 50200 * import {GeoJSON} from 'ol/format'; 50201 * import {bbox} from 'ol/loadingstrategy'; 50202 * 50203 * const vectorSource = new Vector({ 50204 * format: new GeoJSON(), 50205 * loader: function(extent, resolution, projection, success, failure) { 50206 * const proj = projection.getCode(); 50207 * const url = 'https://ahocevar.com/geoserver/wfs?service=WFS&' + 50208 * 'version=1.1.0&request=GetFeature&typename=osm:water_areas&' + 50209 * 'outputFormat=application/json&srsname=' + proj + '&' + 50210 * 'bbox=' + extent.join(',') + ',' + proj; 50211 * const xhr = new XMLHttpRequest(); 50212 * xhr.open('GET', url); 50213 * const onError = function() { 50214 * vectorSource.removeLoadedExtent(extent); 50215 * failure(); 50216 * } 50217 * xhr.onerror = onError; 50218 * xhr.onload = function() { 50219 * if (xhr.status == 200) { 50220 * const features = vectorSource.getFormat().readFeatures(xhr.responseText); 50221 * vectorSource.addFeatures(features); 50222 * success(features); 50223 * } else { 50224 * onError(); 50225 * } 50226 * } 50227 * xhr.send(); 50228 * }, 50229 * strategy: bbox, 50230 * }); 50231 * ``` 50232 * @property {boolean} [overlaps=true] This source may have overlapping geometries. 50233 * Setting this to `false` (e.g. for sources with polygons that represent administrative 50234 * boundaries or TopoJSON sources) allows the renderer to optimise fill and 50235 * stroke operations. 50236 * @property {LoadingStrategy} [strategy] The loading strategy to use. 50237 * By default an {@link module:ol/loadingstrategy.all} 50238 * strategy is used, a one-off strategy which loads all features at once. 50239 * @property {string|import("../featureloader.js").FeatureUrlFunction} [url] 50240 * Setting this option instructs the source to load features using an XHR loader 50241 * (see {@link module:ol/featureloader.xhr}). Use a `string` and an 50242 * {@link module:ol/loadingstrategy.all} for a one-off download of all features from 50243 * the given URL. Use a {@link module:ol/featureloader~FeatureUrlFunction} to generate the url with 50244 * other loading strategies. 50245 * Requires `format` to be set as well. 50246 * When default XHR feature loader is provided, the features will 50247 * be transformed from the data projection to the view projection 50248 * during parsing. If your remote data source does not advertise its projection 50249 * properly, this transformation will be incorrect. For some formats, the 50250 * default projection (usually EPSG:4326) can be overridden by setting the 50251 * dataProjection constructor option on the format.
50252 * Note that if a source contains non-feature data, such as a GeoJSON geometry 50253 * or a KML NetworkLink, these will be ignored. Use a custom loader to load these. 50254 * @property {boolean} [useSpatialIndex=true] 50255 * By default, an RTree is used as spatial index. When features are removed and 50256 * added frequently, and the total number of features is low, setting this to 50257 * `false` may improve performance. 50258 * 50259 * Note that 50260 * {@link module:ol/source/Vector~VectorSource#getFeaturesInExtent}, 50261 * {@link module:ol/source/Vector~VectorSource#getClosestFeatureToCoordinate} and 50262 * {@link module:ol/source/Vector~VectorSource#getExtent} cannot be used when `useSpatialIndex` is 50263 * set to `false`, and {@link module:ol/source/Vector~VectorSource#forEachFeatureInExtent} will loop 50264 * through all features. 50265 * 50266 * When set to `false`, the features will be maintained in an 50267 * {@link module:ol/Collection~Collection}, which can be retrieved through 50268 * {@link module:ol/source/Vector~VectorSource#getFeaturesCollection}. 50269 * @property {boolean} [wrapX=true] Wrap the world horizontally. For vector editing across the 50270 * -180° and 180° meridians to work properly, this should be set to `false`. The 50271 * resulting geometry coordinates will then exceed the world bounds. 50272 * @template {import("../geom/Geometry.js").default} [Geometry=import("../geom/Geometry.js").default] 50273 */ 50274 50275/** 50276 * @classdesc 50277 * Provides a source of features for vector layers. Vector features provided 50278 * by this source are suitable for editing. See {@link module:ol/source/VectorTile~VectorTile} for 50279 * vector data that is optimized for rendering. 50280 * 50281 * @fires VectorSourceEvent 50282 * @api 50283 * @template {import("../geom/Geometry.js").default} [Geometry=import("../geom/Geometry.js").default] 50284 */ 50285class VectorSource extends source_Source { 50286 /** 50287 * @param {Options<Geometry>} [options] Vector source options. 50288 */ 50289 constructor(options) { 50290 options = options || {}; 50291 50292 super({ 50293 attributions: options.attributions, 50294 interpolate: true, 50295 projection: undefined, 50296 state: 'ready', 50297 wrapX: options.wrapX !== undefined ? options.wrapX : true, 50298 }); 50299 50300 /*** 50301 * @type {VectorSourceOnSignature<import("../events").EventsKey>} 50302 */ 50303 this.on; 50304 50305 /*** 50306 * @type {VectorSourceOnSignature<import("../events").EventsKey>} 50307 */ 50308 this.once; 50309 50310 /*** 50311 * @type {VectorSourceOnSignature<void>} 50312 */ 50313 this.un; 50314 50315 /** 50316 * @private 50317 * @type {import("../featureloader.js").FeatureLoader} 50318 */ 50319 this.loader_ = VOID; 50320 50321 /** 50322 * @private 50323 * @type {import("../format/Feature.js").default|undefined} 50324 */ 50325 this.format_ = options.format; 50326 50327 /** 50328 * @private 50329 * @type {boolean} 50330 */ 50331 this.overlaps_ = options.overlaps === undefined ? true : options.overlaps; 50332 50333 /** 50334 * @private 50335 * @type {string|import("../featureloader.js").FeatureUrlFunction|undefined} 50336 */ 50337 this.url_ = options.url; 50338 50339 if (options.loader !== undefined) { 50340 this.loader_ = options.loader; 50341 } else if (this.url_ !== undefined) { 50342 asserts_assert(this.format_, 7); // `format` must be set when `url` is set 50343 // create a XHR feature loader for "url" and "format" 50344 this.loader_ = xhr( 50345 this.url_, 50346 /** @type {import("../format/Feature.js").default} */ (this.format_) 50347 ); 50348 } 50349 50350 /** 50351 * @private 50352 * @type {LoadingStrategy} 50353 */ 50354 this.strategy_ = 50355 options.strategy !== undefined ? options.strategy : loadingstrategy_all; 50356 50357 const useSpatialIndex = 50358 options.useSpatialIndex !== undefined ? options.useSpatialIndex : true; 50359 50360 /** 50361 * @private 50362 * @type {RBush<import("../Feature.js").default<Geometry>>} 50363 */ 50364 this.featuresRtree_ = useSpatialIndex ? new structs_RBush() : null; 50365 50366 /** 50367 * @private 50368 * @type {RBush<{extent: import("../extent.js").Extent}>} 50369 */ 50370 this.loadedExtentsRtree_ = new structs_RBush(); 50371 50372 /** 50373 * @type {number} 50374 * @private 50375 */ 50376 this.loadingExtentsCount_ = 0; 50377 50378 /** 50379 * @private 50380 * @type {!Object<string, import("../Feature.js").default<Geometry>>} 50381 */ 50382 this.nullGeometryFeatures_ = {}; 50383 50384 /** 50385 * A lookup of features by id (the return from feature.getId()). 50386 * @private
50387 * @type {!Object<string, import("../Feature.js").default<Geometry>>} 50388 */ 50389 this.idIndex_ = {}; 50390 50391 /** 50392 * A lookup of features by uid (using getUid(feature)). 50393 * @private 50394 * @type {!Object<string, import("../Feature.js").default<Geometry>>} 50395 */ 50396 this.uidIndex_ = {}; 50397 50398 /** 50399 * @private 50400 * @type {Object<string, Array<import("../events.js").EventsKey>>} 50401 */ 50402 this.featureChangeKeys_ = {}; 50403 50404 /** 50405 * @private 50406 * @type {Collection<import("../Feature.js").default<Geometry>>|null} 50407 */ 50408 this.featuresCollection_ = null; 50409 50410 /** @type {Collection<import("../Feature.js").default<Geometry>>} */ 50411 let collection; 50412 /** @type {Array<import("../Feature.js").default<Geometry>>} */ 50413 let features; 50414 if (Array.isArray(options.features)) { 50415 features = options.features; 50416 } else if (options.features) { 50417 collection = options.features; 50418 features = collection.getArray(); 50419 } 50420 if (!useSpatialIndex && collection === undefined) { 50421 collection = new ol_Collection(features); 50422 } 50423 if (features !== undefined) { 50424 this.addFeaturesInternal(features); 50425 } 50426 if (collection !== undefined) { 50427 this.bindFeaturesCollection_(collection); 50428 } 50429 } 50430 50431 /** 50432 * Add a single feature to the source. If you want to add a batch of features 50433 * at once, call {@link module:ol/source/Vector~VectorSource#addFeatures #addFeatures()} 50434 * instead. A feature will not be added to the source if feature with 50435 * the same id is already there. The reason for this behavior is to avoid 50436 * feature duplication when using bbox or tile loading strategies. 50437 * Note: this also applies if an {@link module:ol/Collection~Collection} is used for features, 50438 * meaning that if a feature with a duplicate id is added in the collection, it will 50439 * be removed from it right away. 50440 * @param {import("../Feature.js").default<Geometry>} feature Feature to add. 50441 * @api 50442 */ 50443 addFeature(feature) { 50444 this.addFeatureInternal(feature); 50445 this.changed(); 50446 } 50447 50448 /** 50449 * Add a feature without firing a `change` event. 50450 * @param {import("../Feature.js").default<Geometry>} feature Feature. 50451 * @protected 50452 */ 50453 addFeatureInternal(feature) { 50454 const featureKey = getUid(feature); 50455 50456 if (!this.addToIndex_(featureKey, feature)) { 50457 if (this.featuresCollection_) { 50458 this.featuresCollection_.remove(feature); 50459 } 50460 return; 50461 } 50462 50463 this.setupChangeEvents_(featureKey, feature); 50464 50465 const geometry = feature.getGeometry(); 50466 if (geometry) { 50467 const extent = geometry.getExtent(); 50468 if (this.featuresRtree_) { 50469 this.featuresRtree_.insert(extent, feature); 50470 } 50471 } else { 50472 this.nullGeometryFeatures_[featureKey] = feature; 50473 } 50474 50475 this.dispatchEvent( 50476 new VectorSourceEvent(VectorEventType.ADDFEATURE, feature) 50477 ); 50478 } 50479 50480 /** 50481 * @param {string} featureKey Unique identifier for the feature. 50482 * @param {import("../Feature.js").default<Geometry>} feature The feature. 50483 * @private 50484 */ 50485 setupChangeEvents_(featureKey, feature) { 50486 this.featureChangeKeys_[featureKey] = [ 50487 listen(feature, EventType.CHANGE, this.handleFeatureChange_, this), 50488 listen( 50489 feature, 50490 ObjectEventType.PROPERTYCHANGE, 50491 this.handleFeatureChange_, 50492 this 50493 ), 50494 ]; 50495 } 50496 50497 /** 50498 * @param {string} featureKey Unique identifier for the feature. 50499 * @param {import("../Feature.js").default<Geometry>} feature The feature. 50500 * @return {boolean} The feature is "valid", in the sense that it is also a 50501 * candidate for insertion into the Rtree. 50502 * @private 50503 */ 50504 addToIndex_(featureKey, feature) { 50505 let valid = true; 50506 const id = feature.getId(); 50507 if (id !== undefined) { 50508 if (!(id.toString() in this.idIndex_)) { 50509 this.idIndex_[id.toString()] = feature; 50510 } else { 50511 valid = false; 50512 } 50513 } 50514 if (valid) { 50515 asserts_assert(!(featureKey in this.uidIndex_), 30); // The passed `feature` was already added to the source 50516 this.uidIndex_[featureKey] = feature; 50517 } 50518 return valid; 50519 } 50520 50521 /** 50522 * Add a batch of features to the source. 50523 * @param {Array<import("../Feature.js").default<Geometry>>} features Features to add. 50524 * @api 50525 */ 50526 addFeatures(features) { 50527 this.addFeaturesInternal(features); 50528 this.changed(); 50529 } 50530 50531 /** 50532 * Add features without firing a `change` event. 50533 * @param {Array<import("../Feature.js").default<Geometry>>} features Features. 50534 * @protected 50535 */ 50536 addFeaturesInternal(features) { 50537 const extents = []; 50538 const newFeatures = []; 50539 const geometryFeatures = []; 50540 50541 for (let i = 0, length = features.length; i < length; i++) { 50542 const feature = features[i]; 50543 const featureKey = getUid(feature); 50544 if (this.addToIndex_(featureKey, feature)) { 50545 newFeatures.push(feature); 50546 } 50547 } 50548 50549 for (let i = 0, length = newFeatures.length; i < length; i++) { 50550 const feature = newFeatures[i]; 50551 const featureKey = getUid(feature); 50552 this.setupChangeEvents_(featureKey, feature); 50553 50554 const geometry = feature.getGeometry(); 50555 if (geometry) { 50556 const extent = geometry.getExtent(); 50557 extents.push(extent); 50558 geometryFeatures.push(feature); 50559 } else { 50560 this.nullGeometryFeatures_[featureKey] = feature; 50561 } 50562 } 50563 if (this.featuresRtree_) { 50564 this.featuresRtree_.load(extents, geometryFeatures); 50565 } 50566 50567 if (this.hasListener(VectorEventType.ADDFEATURE)) { 50568 for (let i = 0, length = newFeatures.length; i < length; i++) { 50569 this.dispatchEvent( 50570 new VectorSourceEvent(VectorEventType.ADDFEATURE, newFeatures[i]) 50571 ); 50572 } 50573 } 50574 } 50575 50576 /** 50577 * @param {!Collection<import("../Feature.js").default<Geometry>>} collection Collection. 50578 * @private 50579 */ 50580 bindFeaturesCollection_(collection) { 50581 let modifyingCollection = false;
50582 this.addEventListener( 50583 VectorEventType.ADDFEATURE, 50584 /** 50585 * @param {VectorSourceEvent<Geometry>} evt The vector source event 50586 */ 50587 function (evt) { 50588 if (!modifyingCollection) { 50589 modifyingCollection = true; 50590 collection.push(evt.feature); 50591 modifyingCollection = false; 50592 } 50593 } 50594 ); 50595 this.addEventListener( 50596 VectorEventType.REMOVEFEATURE, 50597 /** 50598 * @param {VectorSourceEvent<Geometry>} evt The vector source event 50599 */ 50600 function (evt) { 50601 if (!modifyingCollection) { 50602 modifyingCollection = true; 50603 collection.remove(evt.feature); 50604 modifyingCollection = false; 50605 } 50606 } 50607 ); 50608 collection.addEventListener( 50609 CollectionEventType.ADD, 50610 /** 50611 * @param {import("../Collection.js").CollectionEvent<import("../Feature.js").default<Geometry>>} evt The collection event 50612 */ 50613 function (evt) { 50614 if (!modifyingCollection) { 50615 modifyingCollection = true; 50616 this.addFeature(evt.element); 50617 modifyingCollection = false; 50618 } 50619 }.bind(this) 50620 ); 50621 collection.addEventListener( 50622 CollectionEventType.REMOVE, 50623 /** 50624 * @param {import("../Collection.js").CollectionEvent<import("../Feature.js").default<Geometry>>} evt The collection event 50625 */ 50626 function (evt) { 50627 if (!modifyingCollection) { 50628 modifyingCollection = true; 50629 this.removeFeature(evt.element); 50630 modifyingCollection = false; 50631 } 50632 }.bind(this) 50633 ); 50634 this.featuresCollection_ = collection; 50635 } 50636 50637 /** 50638 * Remove all features from the source. 50639 * @param {boolean} [fast] Skip dispatching of {@link module:ol/source/Vector.VectorSourceEvent#event:removefeature} events. 50640 * @api 50641 */ 50642 clear(fast) { 50643 if (fast) { 50644 for (const featureId in this.featureChangeKeys_) { 50645 const keys = this.featureChangeKeys_[featureId]; 50646 keys.forEach(unlistenByKey); 50647 } 50648 if (!this.featuresCollection_) { 50649 this.featureChangeKeys_ = {}; 50650 this.idIndex_ = {}; 50651 this.uidIndex_ = {}; 50652 } 50653 } else { 50654 if (this.featuresRtree_) { 50655 const removeAndIgnoreReturn = function (feature) { 50656 this.removeFeatureInternal(feature); 50657 }.bind(this); 50658 this.featuresRtree_.forEach(removeAndIgnoreReturn); 50659 for (const id in this.nullGeometryFeatures_) { 50660 this.removeFeatureInternal(this.nullGeometryFeatures_[id]); 50661 } 50662 } 50663 } 50664 if (this.featuresCollection_) { 50665 this.featuresCollection_.clear(); 50666 } 50667 50668 if (this.featuresRtree_) { 50669 this.featuresRtree_.clear(); 50670 } 50671 this.nullGeometryFeatures_ = {}; 50672 50673 const clearEvent = new VectorSourceEvent(VectorEventType.CLEAR); 50674 this.dispatchEvent(clearEvent); 50675 this.changed(); 50676 } 50677 50678 /** 50679 * Iterate through all features on the source, calling the provided callback 50680 * with each one. If the callback returns any "truthy" value, iteration will 50681 * stop and the function will return the same value. 50682 * Note: this function only iterate through the feature that have a defined geometry. 50683 * 50684 * @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature 50685 * on the source. Return a truthy value to stop iteration. 50686 * @return {T|undefined} The return value from the last call to the callback. 50687 * @template T 50688 * @api 50689 */ 50690 forEachFeature(callback) { 50691 if (this.featuresRtree_) { 50692 return this.featuresRtree_.forEach(callback); 50693 } else if (this.featuresCollection_) { 50694 this.featuresCollection_.forEach(callback); 50695 } 50696 } 50697 50698 /** 50699 * Iterate through all features whose geometries contain the provided 50700 * coordinate, calling the callback with each feature. If the callback returns 50701 * a "truthy" value, iteration will stop and the function will return the same 50702 * value. 50703 * 50704 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 50705 * @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature 50706 * whose goemetry contains the provided coordinate. 50707 * @return {T|undefined} The return value from the last call to the callback. 50708 * @template T 50709 */ 50710 forEachFeatureAtCoordinateDirect(coordinate, callback) { 50711 const extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]]; 50712 return this.forEachFeatureInExtent(extent, function (feature) { 50713 const geometry = feature.getGeometry(); 50714 if (geometry.intersectsCoordinate(coordinate)) { 50715 return callback(feature); 50716 } else { 50717 return undefined; 50718 } 50719 }); 50720 } 50721 50722 /** 50723 * Iterate through all features whose bounding box intersects the provided 50724 * extent (note that the feature's geometry may not intersect the extent), 50725 * calling the callback with each feature. If the callback returns a "truthy" 50726 * value, iteration will stop and the function will return the same value. 50727 * 50728 * If you are interested in features whose geometry intersects an extent, call 50729 * the {@link module:ol/source/Vector~VectorSource#forEachFeatureIntersectingExtent #forEachFeatureIntersectingExtent()} method instead. 50730 * 50731 * When `useSpatialIndex` is set to false, this method will loop through all 50732 * features, equivalent to {@link module:ol/source/Vector~VectorSource#forEachFeature #forEachFeature()}. 50733 * 50734 * @param {import("../extent.js").Extent} extent Extent. 50735 * @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature 50736 * whose bounding box intersects the provided extent. 50737 * @return {T|undefined} The return value from the last call to the callback. 50738 * @template T 50739 * @api 50740 */ 50741 forEachFeatureInExtent(extent, callback) { 50742 if (this.featuresRtree_) { 50743 return this.featuresRtree_.forEachInExtent(extent, callback); 50744 } else if (this.featuresCollection_) { 50745 this.featuresCollection_.forEach(callback); 50746 } 50747 } 50748 50749 /** 50750 * Iterate through all features whose geometry intersects the provided extent, 50751 * calling the callback with each feature. If the callback returns a "truthy" 50752 * value, iteration will stop and the function will return the same value. 50753 * 50754 * If you only want to test for bounding box intersection, call the 50755 * {@link module:ol/source/Vector~VectorSource#forEachFeatureInExtent #forEachFeatureInExtent()} method instead. 50756 * 50757 * @param {import("../extent.js").Extent} extent Extent. 50758 * @param {function(import("../Feature.js").default<Geometry>): T} callback Called with each feature 50759 * whose geometry intersects the provided extent. 50760 * @return {T|undefined} The return value from the last call to the callback. 50761 * @template T 50762 * @api 50763 */ 50764 forEachFeatureIntersectingExtent(extent, callback) { 50765 return this.forEachFeatureInExtent( 50766 extent, 50767 /** 50768 * @param {import("../Feature.js").default<Geometry>} feature Feature. 50769 * @return {T|undefined} The return value from the last call to the callback. 50770 */ 50771 function (feature) { 50772 const geometry = feature.getGeometry(); 50773 if (geometry.intersectsExtent(extent)) { 50774 const result = callback(feature); 50775 if (result) { 50776 return result; 50777 } 50778 } 50779 } 50780 ); 50781 } 50782 50783 /** 50784 * Get the features collection associated with this source. Will be `null` 50785 * unless the source was configured with `useSpatialIndex` set to `false`, or 50786 * with an {@link module:ol/Collection~Collection} as `features`. 50787 * @return {Collection<import("../Feature.js").default<Geometry>>|null} The collection of features. 50788 * @api 50789 */ 50790 getFeaturesCollection() { 50791 return this.featuresCollection_; 50792 } 50793 50794 /** 50795 * Get a snapshot of the features currently on the source in random order. The returned array 50796 * is a copy, the features are references to the features in the source. 50797 * @return {Array<import("../Feature.js").default<Geometry>>} Features. 50798 * @api 50799 */ 50800 getFeatures() { 50801 let features; 50802 if (this.featuresCollection_) { 50803 features = this.featuresCollection_.getArray().slice(0); 50804 } else if (this.featuresRtree_) { 50805 features = this.featuresRtree_.getAll(); 50806 if (!obj_isEmpty(this.nullGeometryFeatures_)) { 50807 array_extend(features, Object.values(this.nullGeometryFeatures_)); 50808 } 50809 } 50810 return /** @type {Array<import("../Feature.js").default<Geometry>>} */ ( 50811 features 50812 ); 50813 } 50814 50815 /** 50816 * Get all features whose geometry intersects the provided coordinate. 50817 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 50818 * @return {Array<import("../Feature.js").default<Geometry>>} Features. 50819 * @api 50820 */ 50821 getFeaturesAtCoordinate(coordinate) { 50822 const features = []; 50823 this.forEachFeatureAtCoordinateDirect(coordinate, function (feature) { 50824 features.push(feature); 50825 }); 50826 return features; 50827 } 50828 50829 /** 50830 * Get all features whose bounding box intersects the provided extent. Note that this returns an array of 50831 * all features intersecting the given extent in random order (so it may include 50832 * features whose geometries do not intersect the extent). 50833 * 50834 * When `useSpatialIndex` is set to false, this method will return all 50835 * features. 50836 * 50837 * @param {import("../extent.js").Extent} extent Extent. 50838 * @param {import("../proj/Projection.js").default} [projection] Include features
50839 * where `extent` exceeds the x-axis bounds of `projection` and wraps around the world. 50840 * @return {Array<import("../Feature.js").default<Geometry>>} Features. 50841 * @api 50842 */ 50843 getFeaturesInExtent(extent, projection) { 50844 if (this.featuresRtree_) { 50845 const multiWorld = projection && projection.canWrapX() && this.getWrapX(); 50846 50847 if (!multiWorld) { 50848 return this.featuresRtree_.getInExtent(extent); 50849 } 50850 50851 const extents = wrapAndSliceX(extent, projection); 50852 50853 return [].concat( 50854 ...extents.map((anExtent) => this.featuresRtree_.getInExtent(anExtent)) 50855 ); 50856 } else if (this.featuresCollection_) { 50857 return this.featuresCollection_.getArray().slice(0); 50858 } else { 50859 return []; 50860 } 50861 } 50862 50863 /** 50864 * Get the closest feature to the provided coordinate. 50865 * 50866 * This method is not available when the source is configured with 50867 * `useSpatialIndex` set to `false`. 50868 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 50869 * @param {function(import("../Feature.js").default<Geometry>):boolean} [filter] Feature filter function. 50870 * The filter function will receive one argument, the {@link module:ol/Feature~Feature feature} 50871 * and it should return a boolean value. By default, no filtering is made. 50872 * @return {import("../Feature.js").default<Geometry>} Closest feature. 50873 * @api 50874 */ 50875 getClosestFeatureToCoordinate(coordinate, filter) { 50876 // Find the closest feature using branch and bound. We start searching an 50877 // infinite extent, and find the distance from the first feature found. This 50878 // becomes the closest feature. We then compute a smaller extent which any 50879 // closer feature must intersect. We continue searching with this smaller 50880 // extent, trying to find a closer feature. Every time we find a closer 50881 // feature, we update the extent being searched so that any even closer 50882 // feature must intersect it. We continue until we run out of features. 50883 const x = coordinate[0]; 50884 const y = coordinate[1]; 50885 let closestFeature = null; 50886 const closestPoint = [NaN, NaN]; 50887 let minSquaredDistance = Infinity; 50888 const extent = [-Infinity, -Infinity, Infinity, Infinity]; 50889 filter = filter ? filter : TRUE; 50890 this.featuresRtree_.forEachInExtent( 50891 extent, 50892 /** 50893 * @param {import("../Feature.js").default<Geometry>} feature Feature. 50894 */ 50895 function (feature) { 50896 if (filter(feature)) { 50897 const geometry = feature.getGeometry(); 50898 const previousMinSquaredDistance = minSquaredDistance; 50899 minSquaredDistance = geometry.closestPointXY( 50900 x, 50901 y, 50902 closestPoint, 50903 minSquaredDistance 50904 ); 50905 if (minSquaredDistance < previousMinSquaredDistance) { 50906 closestFeature = feature; 50907 // This is sneaky. Reduce the extent that it is currently being 50908 // searched while the R-Tree traversal using this same extent object 50909 // is still in progress. This is safe because the new extent is 50910 // strictly contained by the old extent. 50911 const minDistance = Math.sqrt(minSquaredDistance); 50912 extent[0] = x - minDistance; 50913 extent[1] = y - minDistance; 50914 extent[2] = x + minDistance; 50915 extent[3] = y + minDistance; 50916 } 50917 } 50918 } 50919 ); 50920 return closestFeature; 50921 } 50922 50923 /** 50924 * Get the extent of the features currently in the source. 50925 * 50926 * This method is not available when the source is configured with 50927 * `useSpatialIndex` set to `false`. 50928 * @param {import("../extent.js").Extent} [extent] Destination extent. If provided, no new extent 50929 * will be created. Instead, that extent's coordinates will be overwritten. 50930 * @return {import("../extent.js").Extent} Extent. 50931 * @api 50932 */ 50933 getExtent(extent) { 50934 return this.featuresRtree_.getExtent(extent); 50935 } 50936 50937 /** 50938 * Get a feature by its identifier (the value returned by feature.getId()). 50939 * Note that the index treats string and numeric identifiers as the same. So 50940 * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`. 50941 * 50942 * @param {string|number} id Feature identifier. 50943 * @return {import("../Feature.js").default<Geometry>|null} The feature (or `null` if not found). 50944 * @api 50945 */ 50946 getFeatureById(id) {
50947 const feature = this.idIndex_[id.toString()]; 50948 return feature !== undefined ? feature : null; 50949 } 50950 50951 /** 50952 * Get a feature by its internal unique identifier (using `getUid`). 50953 * 50954 * @param {string} uid Feature identifier. 50955 * @return {import("../Feature.js").default<Geometry>|null} The feature (or `null` if not found). 50956 */ 50957 getFeatureByUid(uid) { 50958 const feature = this.uidIndex_[uid]; 50959 return feature !== undefined ? feature : null; 50960 } 50961 50962 /** 50963 * Get the format associated with this source. 50964 * 50965 * @return {import("../format/Feature.js").default|undefined} The feature format. 50966 * @api 50967 */ 50968 getFormat() { 50969 return this.format_; 50970 } 50971 50972 /** 50973 * @return {boolean} The source can have overlapping geometries. 50974 */ 50975 getOverlaps() { 50976 return this.overlaps_; 50977 } 50978 50979 /** 50980 * Get the url associated with this source. 50981 * 50982 * @return {string|import("../featureloader.js").FeatureUrlFunction|undefined} The url. 50983 * @api 50984 */ 50985 getUrl() { 50986 return this.url_; 50987 } 50988 50989 /** 50990 * @param {Event} event Event. 50991 * @private 50992 */ 50993 handleFeatureChange_(event) { 50994 const feature = /** @type {import("../Feature.js").default<Geometry>} */ ( 50995 event.target 50996 ); 50997 const featureKey = getUid(feature); 50998 const geometry = feature.getGeometry(); 50999 if (!geometry) { 51000 if (!(featureKey in this.nullGeometryFeatures_)) { 51001 if (this.featuresRtree_) { 51002 this.featuresRtree_.remove(feature); 51003 } 51004 this.nullGeometryFeatures_[featureKey] = feature; 51005 } 51006 } else { 51007 const extent = geometry.getExtent(); 51008 if (featureKey in this.nullGeometryFeatures_) { 51009 delete this.nullGeometryFeatures_[featureKey]; 51010 if (this.featuresRtree_) { 51011 this.featuresRtree_.insert(extent, feature); 51012 } 51013 } else { 51014 if (this.featuresRtree_) { 51015 this.featuresRtree_.update(extent, feature); 51016 } 51017 } 51018 } 51019 const id = feature.getId(); 51020 if (id !== undefined) { 51021 const sid = id.toString(); 51022 if (this.idIndex_[sid] !== feature) { 51023 this.removeFromIdIndex_(feature); 51024 this.idIndex_[sid] = feature; 51025 } 51026 } else { 51027 this.removeFromIdIndex_(feature); 51028 this.uidIndex_[featureKey] = feature; 51029 } 51030 this.changed(); 51031 this.dispatchEvent( 51032 new VectorSourceEvent(VectorEventType.CHANGEFEATURE, feature) 51033 ); 51034 } 51035 51036 /** 51037 * Returns true if the feature is contained within the source. 51038 * @param {import("../Feature.js").default<Geometry>} feature Feature. 51039 * @return {boolean} Has feature. 51040 * @api 51041 */ 51042 hasFeature(feature) { 51043 const id = feature.getId(); 51044 if (id !== undefined) { 51045 return id in this.idIndex_; 51046 } else { 51047 return getUid(feature) in this.uidIndex_; 51048 } 51049 } 51050 51051 /** 51052 * @return {boolean} Is empty. 51053 */ 51054 isEmpty() { 51055 if (this.featuresRtree_) { 51056 return ( 51057 this.featuresRtree_.isEmpty() && obj_isEmpty(this.nullGeometryFeatures_) 51058 ); 51059 } 51060 if (this.featuresCollection_) { 51061 return this.featuresCollection_.getLength() === 0; 51062 } 51063 return true; 51064 } 51065 51066 /** 51067 * @param {import("../extent.js").Extent} extent Extent. 51068 * @param {number} resolution Resolution. 51069 * @param {import("../proj/Projection.js").default} projection Projection. 51070 */ 51071 loadFeatures(extent, resolution, projection) { 51072 const loadedExtentsRtree = this.loadedExtentsRtree_; 51073 const extentsToLoad = this.strategy_(extent, resolution, projection); 51074 for (let i = 0, ii = extentsToLoad.length; i < ii; ++i) { 51075 const extentToLoad = extentsToLoad[i]; 51076 const alreadyLoaded = loadedExtentsRtree.forEachInExtent( 51077 extentToLoad, 51078 /** 51079 * @param {{extent: import("../extent.js").Extent}} object Object. 51080 * @return {boolean} Contains. 51081 */ 51082 function (object) { 51083 return containsExtent(object.extent, extentToLoad); 51084 } 51085 ); 51086 if (!alreadyLoaded) { 51087 ++this.loadingExtentsCount_; 51088 this.dispatchEvent( 51089 new VectorSourceEvent(VectorEventType.FEATURESLOADSTART) 51090 ); 51091 this.loader_.call( 51092 this, 51093 extentToLoad, 51094 resolution, 51095 projection, 51096 function (features) { 51097 --this.loadingExtentsCount_; 51098 this.dispatchEvent( 51099 new VectorSourceEvent( 51100 VectorEventType.FEATURESLOADEND, 51101 undefined, 51102 features 51103 ) 51104 ); 51105 }.bind(this), 51106 function () { 51107 --this.loadingExtentsCount_; 51108 this.dispatchEvent( 51109 new VectorSourceEvent(VectorEventType.FEATURESLOADERROR) 51110 ); 51111 }.bind(this) 51112 ); 51113 loadedExtentsRtree.insert(extentToLoad, {extent: extentToLoad.slice()}); 51114 } 51115 } 51116 this.loading = 51117 this.loader_.length < 4 ? false : this.loadingExtentsCount_ > 0; 51118 } 51119 51120 refresh() { 51121 this.clear(true); 51122 this.loadedExtentsRtree_.clear(); 51123 super.refresh(); 51124 } 51125 51126 /** 51127 * Remove an extent from the list of loaded extents. 51128 * @param {import("../extent.js").Extent} extent Extent. 51129 * @api 51130 */ 51131 removeLoadedExtent(extent) { 51132 const loadedExtentsRtree = this.loadedExtentsRtree_; 51133 let obj; 51134 loadedExtentsRtree.forEachInExtent(extent, function (object) { 51135 if (extent_equals(object.extent, extent)) { 51136 obj = object; 51137 return true; 51138 } 51139 }); 51140 if (obj) { 51141 loadedExtentsRtree.remove(obj); 51142 } 51143 } 51144 51145 /** 51146 * Remove a single feature from the source. If you want to remove all features 51147 * at once, use the {@link module:ol/source/Vector~VectorSource#clear #clear()} method 51148 * instead. 51149 * @param {import("../Feature.js").default<Geometry>} feature Feature to remove. 51150 * @api 51151 */
51152 removeFeature(feature) { 51153 if (!feature) { 51154 return; 51155 } 51156 const featureKey = getUid(feature); 51157 if (featureKey in this.nullGeometryFeatures_) { 51158 delete this.nullGeometryFeatures_[featureKey]; 51159 } else { 51160 if (this.featuresRtree_) { 51161 this.featuresRtree_.remove(feature); 51162 } 51163 } 51164 const result = this.removeFeatureInternal(feature); 51165 if (result) { 51166 this.changed(); 51167 } 51168 } 51169 51170 /** 51171 * Remove feature without firing a `change` event. 51172 * @param {import("../Feature.js").default<Geometry>} feature Feature. 51173 * @return {import("../Feature.js").default<Geometry>|undefined} The removed feature 51174 * (or undefined if the feature was not found). 51175 * @protected 51176 */ 51177 removeFeatureInternal(feature) { 51178 const featureKey = getUid(feature); 51179 const featureChangeKeys = this.featureChangeKeys_[featureKey]; 51180 if (!featureChangeKeys) { 51181 return; 51182 } 51183 featureChangeKeys.forEach(unlistenByKey); 51184 delete this.featureChangeKeys_[featureKey]; 51185 const id = feature.getId(); 51186 if (id !== undefined) { 51187 delete this.idIndex_[id.toString()]; 51188 } 51189 delete this.uidIndex_[featureKey]; 51190 this.dispatchEvent( 51191 new VectorSourceEvent(VectorEventType.REMOVEFEATURE, feature) 51192 ); 51193 return feature; 51194 } 51195 51196 /** 51197 * Remove a feature from the id index. Called internally when the feature id 51198 * may have changed. 51199 * @param {import("../Feature.js").default<Geometry>} feature The feature. 51200 * @return {boolean} Removed the feature from the index. 51201 * @private 51202 */ 51203 removeFromIdIndex_(feature) { 51204 let removed = false; 51205 for (const id in this.idIndex_) { 51206 if (this.idIndex_[id] === feature) { 51207 delete this.idIndex_[id]; 51208 removed = true; 51209 break; 51210 } 51211 } 51212 return removed; 51213 } 51214 51215 /** 51216 * Set the new loader of the source. The next render cycle will use the 51217 * new loader. 51218 * @param {import("../featureloader.js").FeatureLoader} loader The loader to set. 51219 * @api 51220 */ 51221 setLoader(loader) { 51222 this.loader_ = loader; 51223 } 51224 51225 /** 51226 * Points the source to a new url. The next render cycle will use the new url. 51227 * @param {string|import("../featureloader.js").FeatureUrlFunction} url Url. 51228 * @api 51229 */ 51230 setUrl(url) { 51231 asserts_assert(this.format_, 7); // `format` must be set when `url` is set 51232 this.url_ = url; 51233 this.setLoader(xhr(url, this.format_)); 51234 } 51235} 51236 51237/* harmony default export */ const source_Vector = (VectorSource); 51238 51239;// CONCATENATED MODULE: ./node_modules/ol/source/OSM.js 51240/** 51241 * @module ol/source/OSM 51242 */ 51243 51244 51245 51246/** 51247 * The attribution containing a link to the OpenStreetMap Copyright and License 51248 * page. 51249 * @const 51250 * @type {string} 51251 * @api 51252 */ 51253const ATTRIBUTION = 51254 '© ' + 51255 '<a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> ' + 51256 'contributors.'; 51257 51258/** 51259 * @typedef {Object} Options 51260 * @property {import("./Source.js").AttributionLike} [attributions] Attributions. 51261 * @property {number} [cacheSize] Initial tile cache size. Will auto-grow to hold at least the number of tiles in the viewport. 51262 * @property {null|string} [crossOrigin='anonymous'] The `crossOrigin` attribute for loaded images. Note that 51263 * you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer. 51264 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail. 51265 * @property {boolean} [interpolate=true] Use interpolated values when resampling. By default, 51266 * linear interpolation is used when resampling. Set to false to use the nearest neighbor instead. 51267 * @property {number} [maxZoom=19] Max zoom. 51268 * @property {boolean} [opaque=true] Whether the layer is opaque. 51269 * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels). 51270 * Higher values can increase reprojection performance, but decrease precision. 51271 * @property {import("../Tile.js").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is 51272 * ```js 51273 * function(imageTile, src) { 51274 * imageTile.getImage().src = src; 51275 * }; 51276 * ``` 51277 * @property {number} [transition=250] Duration of the opacity transition for rendering. 51278 * To disable the opacity transition, pass `transition: 0`. 51279 * @property {string} [url='https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'] URL template. 51280 * Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders. 51281 * @property {boolean} [wrapX=true] Whether to wrap the world horizontally. 51282 * @property {number|import("../array.js").NearestDirectionFunction} [zDirection=0] 51283 * Choose whether to use tiles with a higher or lower zoom level when between integer 51284 * zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}. 51285 */ 51286 51287/** 51288 * @classdesc 51289 * Layer source for the OpenStreetMap tile server. 51290 * @api 51291 */ 51292class OSM extends source_XYZ { 51293 /** 51294 * @param {Options} [options] Open Street Map options. 51295 */ 51296 constructor(options) { 51297 options = options || {}; 51298 51299 let attributions; 51300 if (options.attributions !== undefined) { 51301 attributions = options.attributions; 51302 } else { 51303 attributions = [ATTRIBUTION]; 51304 } 51305 51306 const crossOrigin = 51307 options.crossOrigin !== undefined ? options.crossOrigin : 'anonymous'; 51308 51309 const url = 51310 options.url !== undefined 51311 ? options.url 51312 : 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'; 51313 51314 super({ 51315 attributions: attributions, 51316 attributionsCollapsible: false, 51317 cacheSize: options.cacheSize, 51318 crossOrigin: crossOrigin, 51319 interpolate: options.interpolate, 51320 maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19, 51321 opaque: options.opaque !== undefined ? options.opaque : true, 51322 reprojectionErrorThreshold: options.reprojectionErrorThreshold, 51323 tileLoadFunction: options.tileLoadFunction, 51324 transition: options.transition, 51325 url: url, 51326 wrapX: options.wrapX, 51327 zDirection: options.zDirection, 51328 }); 51329 } 51330} 51331 51332/* harmony default export */ const source_OSM = (OSM); 51333 51334;// CONCATENATED MODULE: ./node_modules/ol/Overlay.js 51335/** 51336 * @module ol/Overlay 51337 */ 51338 51339 51340 51341 51342 51343 51344 51345/** 51346 * @typedef {'bottom-left' | 'bottom-center' | 'bottom-right' | 'center-left' | 'center-center' | 'center-right' | 'top-left' | 'top-center' | 'top-right'} Positioning 51347 * The overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`, 51348 * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`, 51349 * `'top-center'`, or `'top-right'`. 51350 */ 51351 51352/** 51353 * @typedef {Object} Options 51354 * @property {number|string} [id] Set the overlay id. The overlay id can be used 51355 * with the {@link module:ol/Map~Map#getOverlayById} method. 51356 * @property {HTMLElement} [element] The overlay element. 51357 * @property {Array<number>} [offset=[0, 0]] Offsets in pixels used when positioning 51358 * the overlay. The first element in the 51359 * array is the horizontal offset. A positive value shifts the overlay right. 51360 * The second element in the array is the vertical offset. A positive value 51361 * shifts the overlay down. 51362 * @property {import("./coordinate.js").Coordinate} [position] The overlay position 51363 * in map projection. 51364 * @property {Positioning} [positioning='top-left'] Defines how 51365 * the overlay is actually positioned with respect to its `position` property. 51366 * Possible values are `'bottom-left'`, `'bottom-center'`, `'bottom-right'`, 51367 * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`, 51368 * `'top-center'`, and `'top-right'`. 51369 * @property {boolean} [stopEvent=true] Whether event propagation to the map 51370 * viewport should be stopped. If `true` the overlay is placed in the same 51371 * container as that of the controls (CSS class name 51372 * `ol-overlaycontainer-stopevent`); if `false` it is placed in the container 51373 * with CSS class name specified by the `className` property. 51374 * @property {boolean} [insertFirst=true] Whether the overlay is inserted first 51375 * in the overlay container, or appended. If the overlay is placed in the same 51376 * container as that of the controls (see the `stopEvent` option) you will 51377 * probably set `insertFirst` to `true` so the overlay is displayed below the 51378 * controls. 51379 * @property {PanIntoViewOptions|boolean} [autoPan=false] Pan the map when calling 51380 * `setPosition`, so that the overlay is entirely visible in the current viewport. 51381 * @property {string} [className='ol-overlay-container ol-selectable'] CSS class 51382 * name. 51383 */ 51384 51385/** 51386 * @typedef {Object} PanOptions 51387 * @property {number} [duration=1000] The duration of the animation in 51388 * milliseconds. 51389 * @property {function(number):number} [easing] The easing function to use. Can 51390 * be one from {@link module:ol/easing} or a custom function. 51391 * Default is {@link module:ol/easing.inAndOut}. 51392 */ 51393 51394/** 51395 * @typedef {Object} PanIntoViewOptions 51396 * @property {PanOptions} [animation={}] The animation parameters for the pan 51397 * @property {number} [margin=20] The margin (in pixels) between the 51398 * overlay and the borders of the map when panning into view. 51399 */ 51400 51401/** 51402 * @enum {string} 51403 * @protected 51404 */ 51405const Overlay_Property = { 51406 ELEMENT: 'element', 51407 MAP: 'map', 51408 OFFSET: 'offset',
vendor: 11,579 bytes, lines 51409-51851
51409 POSITION: 'position', 51410 POSITIONING: 'positioning', 51411}; 51412 51413/** 51414 * @typedef {import("./ObjectEventType").Types|'change:element'|'change:map'|'change:offset'|'change:position'| 51415 * 'change:positioning'} OverlayObjectEventTypes 51416 */ 51417 51418/*** 51419 * @template Return 51420 * @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> & 51421 * import("./Observable").OnSignature<OverlayObjectEventTypes, import("./Object").ObjectEvent, Return> & 51422 * import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|OverlayObjectEventTypes, Return>} OverlayOnSignature 51423 */ 51424 51425/** 51426 * @classdesc 51427 * An element to be displayed over the map and attached to a single map 51428 * location. Like {@link module:ol/control/Control~Control}, Overlays are 51429 * visible widgets. Unlike Controls, they are not in a fixed position on the 51430 * screen, but are tied to a geographical coordinate, so panning the map will 51431 * move an Overlay but not a Control. 51432 * 51433 * Example: 51434 * 51435 * import Overlay from 'ol/Overlay'; 51436 * 51437 * // ... 51438 * const popup = new Overlay({ 51439 * element: document.getElementById('popup'), 51440 * }); 51441 * popup.setPosition(coordinate); 51442 * map.addOverlay(popup); 51443 * 51444 * @api 51445 */ 51446class Overlay extends ol_Object { 51447 /** 51448 * @param {Options} options Overlay options. 51449 */ 51450 constructor(options) { 51451 super(); 51452 51453 /*** 51454 * @type {OverlayOnSignature<import("./events").EventsKey>} 51455 */ 51456 this.on; 51457 51458 /*** 51459 * @type {OverlayOnSignature<import("./events").EventsKey>} 51460 */ 51461 this.once; 51462 51463 /*** 51464 * @type {OverlayOnSignature<void>} 51465 */ 51466 this.un; 51467 51468 /** 51469 * @protected 51470 * @type {Options} 51471 */ 51472 this.options = options; 51473 51474 /** 51475 * @protected 51476 * @type {number|string|undefined} 51477 */ 51478 this.id = options.id; 51479 51480 /** 51481 * @protected 51482 * @type {boolean} 51483 */ 51484 this.insertFirst = 51485 options.insertFirst !== undefined ? options.insertFirst : true; 51486 51487 /** 51488 * @protected 51489 * @type {boolean} 51490 */ 51491 this.stopEvent = options.stopEvent !== undefined ? options.stopEvent : true; 51492 51493 /** 51494 * @protected 51495 * @type {HTMLElement} 51496 */ 51497 this.element = document.createElement('div'); 51498 this.element.className = 51499 options.className !== undefined 51500 ? options.className 51501 : 'ol-overlay-container ' + CLASS_SELECTABLE; 51502 this.element.style.position = 'absolute'; 51503 this.element.style.pointerEvents = 'auto'; 51504 51505 /** 51506 * @protected 51507 * @type {PanIntoViewOptions|undefined} 51508 */ 51509 this.autoPan = options.autoPan === true ? {} : options.autoPan || undefined; 51510 51511 /** 51512 * @protected 51513 * @type {{transform_: string, 51514 * visible: boolean}} 51515 */ 51516 this.rendered = { 51517 transform_: '', 51518 visible: true, 51519 }; 51520 51521 /** 51522 * @protected 51523 * @type {?import("./events.js").EventsKey} 51524 */ 51525 this.mapPostrenderListenerKey = null; 51526 51527 this.addChangeListener(Overlay_Property.ELEMENT, this.handleElementChanged); 51528 this.addChangeListener(Overlay_Property.MAP, this.handleMapChanged); 51529 this.addChangeListener(Overlay_Property.OFFSET, this.handleOffsetChanged); 51530 this.addChangeListener(Overlay_Property.POSITION, this.handlePositionChanged); 51531 this.addChangeListener(Overlay_Property.POSITIONING, this.handlePositioningChanged); 51532 51533 if (options.element !== undefined) { 51534 this.setElement(options.element); 51535 } 51536 51537 this.setOffset(options.offset !== undefined ? options.offset : [0, 0]); 51538 51539 this.setPositioning(options.positioning || 'top-left'); 51540 51541 if (options.position !== undefined) { 51542 this.setPosition(options.position); 51543 } 51544 } 51545 51546 /** 51547 * Get the DOM element of this overlay. 51548 * @return {HTMLElement|undefined} The Element containing the overlay. 51549 * @observable 51550 * @api 51551 */ 51552 getElement() { 51553 return /** @type {HTMLElement|undefined} */ (this.get(Overlay_Property.ELEMENT)); 51554 } 51555 51556 /** 51557 * Get the overlay identifier which is set on constructor. 51558 * @return {number|string|undefined} Id. 51559 * @api 51560 */ 51561 getId() { 51562 return this.id; 51563 } 51564 51565 /** 51566 * Get the map associated with this overlay. 51567 * @return {import("./Map.js").default|null} The map that the 51568 * overlay is part of. 51569 * @observable 51570 * @api 51571 */ 51572 getMap() { 51573 return /** @type {import("./Map.js").default|null} */ ( 51574 this.get(Overlay_Property.MAP) || null 51575 ); 51576 } 51577 51578 /** 51579 * Get the offset of this overlay. 51580 * @return {Array<number>} The offset. 51581 * @observable 51582 * @api 51583 */ 51584 getOffset() { 51585 return /** @type {Array<number>} */ (this.get(Overlay_Property.OFFSET)); 51586 } 51587 51588 /** 51589 * Get the current position of this overlay. 51590 * @return {import("./coordinate.js").Coordinate|undefined} The spatial point that the overlay is 51591 * anchored at. 51592 * @observable 51593 * @api 51594 */ 51595 getPosition() { 51596 return /** @type {import("./coordinate.js").Coordinate|undefined} */ ( 51597 this.get(Overlay_Property.POSITION) 51598 ); 51599 } 51600 51601 /** 51602 * Get the current positioning of this overlay. 51603 * @return {Positioning} How the overlay is positioned 51604 * relative to its point on the map. 51605 * @observable 51606 * @api 51607 */ 51608 getPositioning() { 51609 return /** @type {Positioning} */ (this.get(Overlay_Property.POSITIONING)); 51610 } 51611 51612 /** 51613 * @protected 51614 */ 51615 handleElementChanged() { 51616 removeChildren(this.element); 51617 const element = this.getElement(); 51618 if (element) { 51619 this.element.appendChild(element); 51620 } 51621 } 51622 51623 /** 51624 * @protected 51625 */ 51626 handleMapChanged() { 51627 if (this.mapPostrenderListenerKey) { 51628 removeNode(this.element); 51629 unlistenByKey(this.mapPostrenderListenerKey); 51630 this.mapPostrenderListenerKey = null; 51631 } 51632 const map = this.getMap(); 51633 if (map) { 51634 this.mapPostrenderListenerKey = listen( 51635 map, 51636 MapEventType.POSTRENDER, 51637 this.render, 51638 this 51639 ); 51640 this.updatePixelPosition(); 51641 const container = this.stopEvent 51642 ? map.getOverlayContainerStopEvent() 51643 : map.getOverlayContainer(); 51644 if (this.insertFirst) { 51645 container.insertBefore(this.element, container.childNodes[0] || null); 51646 } else { 51647 container.appendChild(this.element); 51648 } 51649 this.performAutoPan(); 51650 } 51651 } 51652 51653 /** 51654 * @protected 51655 */ 51656 render() { 51657 this.updatePixelPosition(); 51658 } 51659 51660 /** 51661 * @protected 51662 */ 51663 handleOffsetChanged() { 51664 this.updatePixelPosition(); 51665 } 51666 51667 /** 51668 * @protected 51669 */ 51670 handlePositionChanged() { 51671 this.updatePixelPosition(); 51672 this.performAutoPan(); 51673 } 51674 51675 /** 51676 * @protected 51677 */ 51678 handlePositioningChanged() { 51679 this.updatePixelPosition(); 51680 } 51681 51682 /** 51683 * Set the DOM element to be associated with this overlay. 51684 * @param {HTMLElement|undefined} element The Element containing the overlay. 51685 * @observable 51686 * @api 51687 */ 51688 setElement(element) { 51689 this.set(Overlay_Property.ELEMENT, element); 51690 } 51691 51692 /** 51693 * Set the map to be associated with this overlay. 51694 * @param {import("./Map.js").default|null} map The map that the 51695 * overlay is part of. Pass `null` to just remove the overlay from the current map. 51696 * @observable 51697 * @api 51698 */ 51699 setMap(map) { 51700 this.set(Overlay_Property.MAP, map); 51701 } 51702 51703 /** 51704 * Set the offset for this overlay. 51705 * @param {Array<number>} offset Offset. 51706 * @observable 51707 * @api 51708 */ 51709 setOffset(offset) { 51710 this.set(Overlay_Property.OFFSET, offset); 51711 } 51712 51713 /** 51714 * Set the position for this overlay. If the position is `undefined` the 51715 * overlay is hidden. 51716 * @param {import("./coordinate.js").Coordinate|undefined} position The spatial point that the overlay 51717 * is anchored at. 51718 * @observable 51719 * @api 51720 */ 51721 setPosition(position) { 51722 this.set(Overlay_Property.POSITION, position); 51723 } 51724 51725 /** 51726 * Pan the map so that the overlay is entirely visible in the current viewport 51727 * (if necessary) using the configured autoPan parameters 51728 * @protected 51729 */ 51730 performAutoPan() { 51731 if (this.autoPan) { 51732 this.panIntoView(this.autoPan); 51733 } 51734 } 51735 51736 /** 51737 * Pan the map so that the overlay is entirely visible in the current viewport 51738 * (if necessary). 51739 * @param {PanIntoViewOptions} [panIntoViewOptions] Options for the pan action 51740 * @api 51741 */ 51742 panIntoView(panIntoViewOptions) { 51743 const map = this.getMap(); 51744 51745 if (!map || !map.getTargetElement() || !this.get(Overlay_Property.POSITION)) { 51746 return; 51747 } 51748 51749 const mapRect = this.getRect(map.getTargetElement(), map.getSize()); 51750 const element = this.getElement(); 51751 const overlayRect = this.getRect(element, [ 51752 dom_outerWidth(element), 51753 dom_outerHeight(element), 51754 ]); 51755 51756 panIntoViewOptions = panIntoViewOptions || {}; 51757 51758 const myMargin = 51759 panIntoViewOptions.margin === undefined ? 20 : panIntoViewOptions.margin; 51760 if (!containsExtent(mapRect, overlayRect)) { 51761 // the overlay is not completely inside the viewport, so pan the map 51762 const offsetLeft = overlayRect[0] - mapRect[0]; 51763 const offsetRight = mapRect[2] - overlayRect[2]; 51764 const offsetTop = overlayRect[1] - mapRect[1]; 51765 const offsetBottom = mapRect[3] - overlayRect[3]; 51766 51767 const delta = [0, 0]; 51768 if (offsetLeft < 0) { 51769 // move map to the left 51770 delta[0] = offsetLeft - myMargin; 51771 } else if (offsetRight < 0) { 51772 // move map to the right 51773 delta[0] = Math.abs(offsetRight) + myMargin; 51774 } 51775 if (offsetTop < 0) { 51776 // move map up 51777 delta[1] = offsetTop - myMargin; 51778 } else if (offsetBottom < 0) { 51779 // move map down 51780 delta[1] = Math.abs(offsetBottom) + myMargin; 51781 } 51782 51783 if (delta[0] !== 0 || delta[1] !== 0) { 51784 const center = /** @type {import("./coordinate.js").Coordinate} */ ( 51785 map.getView().getCenterInternal() 51786 ); 51787 const centerPx = map.getPixelFromCoordinateInternal(center); 51788 if (!centerPx) { 51789 return; 51790 } 51791 const newCenterPx = [centerPx[0] + delta[0], centerPx[1] + delta[1]]; 51792 51793 const panOptions = panIntoViewOptions.animation || {}; 51794 map.getView().animateInternal({ 51795 center: map.getCoordinateFromPixelInternal(newCenterPx), 51796 duration: panOptions.duration, 51797 easing: panOptions.easing, 51798 }); 51799 } 51800 } 51801 } 51802 51803 /** 51804 * Get the extent of an element relative to the document 51805 * @param {HTMLElement} element The element. 51806 * @param {import("./size.js").Size} size The size of the element. 51807 * @return {import("./extent.js").Extent} The extent. 51808 * @protected 51809 */ 51810 getRect(element, size) { 51811 const box = element.getBoundingClientRect(); 51812 const offsetX = box.left + window.pageXOffset; 51813 const offsetY = box.top + window.pageYOffset; 51814 return [offsetX, offsetY, offsetX + size[0], offsetY + size[1]]; 51815 } 51816 51817 /** 51818 * Set the positioning for this overlay. 51819 * @param {Positioning} positioning how the overlay is 51820 * positioned relative to its point on the map. 51821 * @observable 51822 * @api 51823 */ 51824 setPositioning(positioning) { 51825 this.set(Overlay_Property.POSITIONING, positioning); 51826 } 51827 51828 /** 51829 * Modify the visibility of the element. 51830 * @param {boolean} visible Element visibility. 51831 * @protected 51832 */ 51833 setVisible(visible) { 51834 if (this.rendered.visible !== visible) { 51835 this.element.style.display = visible ? '' : 'none'; 51836 this.rendered.visible = visible; 51837 } 51838 } 51839 51840 /** 51841 * Update pixel position. 51842 * @protected 51843 */ 51844 updatePixelPosition() { 51845 const map = this.getMap(); 51846 const position = this.getPosition(); 51847 if (!map || !map.isRendered() || !position) { 51848 this.setVisible(false); 51849 return; 51850 } 51851
51852 const pixel = map.getPixelFromCoordinate(position); 51853 const mapSize = map.getSize(); 51854 this.updateRenderedPosition(pixel, mapSize); 51855 } 51856 51857 /** 51858 * @param {import("./pixel.js").Pixel} pixel The pixel location. 51859 * @param {import("./size.js").Size|undefined} mapSize The map size. 51860 * @protected 51861 */ 51862 updateRenderedPosition(pixel, mapSize) { 51863 const style = this.element.style; 51864 const offset = this.getOffset(); 51865 51866 const positioning = this.getPositioning(); 51867 51868 this.setVisible(true); 51869 51870 const x = Math.round(pixel[0] + offset[0]) + 'px'; 51871 const y = Math.round(pixel[1] + offset[1]) + 'px'; 51872 let posX = '0%'; 51873 let posY = '0%'; 51874 if ( 51875 positioning == 'bottom-right' || 51876 positioning == 'center-right' || 51877 positioning == 'top-right' 51878 ) { 51879 posX = '-100%'; 51880 } else if ( 51881 positioning == 'bottom-center' || 51882 positioning == 'center-center' || 51883 positioning == 'top-center' 51884 ) { 51885 posX = '-50%'; 51886 } 51887 if ( 51888 positioning == 'bottom-left' || 51889 positioning == 'bottom-center' || 51890 positioning == 'bottom-right' 51891 ) { 51892 posY = '-100%'; 51893 } else if ( 51894 positioning == 'center-left' || 51895 positioning == 'center-center' || 51896 positioning == 'center-right' 51897 ) { 51898 posY = '-50%'; 51899 } 51900 const transform = `translate(${posX}, ${posY}) translate(${x}, ${y})`; 51901 if (this.rendered.transform_ != transform) { 51902 this.rendered.transform_ = transform; 51903 style.transform = transform; 51904 } 51905 } 51906 51907 /** 51908 * returns the options this Overlay has been created with 51909 * @return {Options} overlay options 51910 */ 51911 getOptions() { 51912 return this.options; 51913 } 51914} 51915 51916/* harmony default export */ const ol_Overlay = (Overlay); 51917 51918;// CONCATENATED MODULE: ./node_modules/ol/DataTile.js 51919/** 51920 * @module ol/DataTile 51921 */ 51922 51923 51924 51925/** 51926 * Data that can be used with a DataTile. For increased browser compatibility, use 51927 * Uint8Array instead of Uint8ClampedArray where possible. 51928 * @typedef {Uint8Array|Uint8ClampedArray|Float32Array|DataView} Data 51929 */ 51930 51931/** 51932 * @typedef {Object} Options 51933 * @property {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate. 51934 * @property {function(): Promise<Data>} loader Data loader. 51935 * @property {number} [transition=250] A duration for tile opacity 51936 * transitions in milliseconds. A duration of 0 disables the opacity transition. 51937 * @property {boolean} [interpolate=false] Use interpolated values when resampling. By default, 51938 * the nearest neighbor is used when resampling. 51939 * @property {import('./size.js').Size} [size=[256, 256]] Tile size. 51940 * @api 51941 */ 51942 51943class DataTile extends ol_Tile { 51944 /** 51945 * @param {Options} options Tile options. 51946 */ 51947 constructor(options) { 51948 const state = TileState.IDLE; 51949 51950 super(options.tileCoord, state, { 51951 transition: options.transition, 51952 interpolate: options.interpolate, 51953 }); 51954 51955 /** 51956 * @type {function(): Promise<Data>} 51957 * @private 51958 */ 51959 this.loader_ = options.loader; 51960 51961 /** 51962 * @type {Data} 51963 * @private 51964 */ 51965 this.data_ = null; 51966 51967 /** 51968 * @type {Error} 51969 * @private 51970 */ 51971 this.error_ = null; 51972 51973 /** 51974 * @type {import('./size.js').Size} 51975 * @private 51976 */ 51977 this.size_ = options.size || [256, 256]; 51978 } 51979 51980 /** 51981 * Get the tile size. 51982 * @return {import('./size.js').Size} Tile size. 51983 */ 51984 getSize() { 51985 return this.size_; 51986 } 51987 51988 /** 51989 * Get the data for the tile. 51990 * @return {Data} Tile data. 51991 * @api 51992 */ 51993 getData() { 51994 return this.data_; 51995 } 51996 51997 /** 51998 * Get any loading error. 51999 * @return {Error} Loading error. 52000 * @api 52001 */ 52002 getError() { 52003 return this.error_; 52004 } 52005 52006 /** 52007 * Load not yet loaded URI. 52008 * @api 52009 */ 52010 load() { 52011 if (this.state !== TileState.IDLE && this.state !== TileState.ERROR) { 52012 return; 52013 } 52014 this.state = TileState.LOADING; 52015 this.changed(); 52016 52017 const self = this; 52018 this.loader_() 52019 .then(function (data) { 52020 self.data_ = data; 52021 self.state = TileState.LOADED; 52022 self.changed(); 52023 }) 52024 .catch(function (error) { 52025 self.error_ = error; 52026 self.state = TileState.ERROR; 52027 self.changed(); 52028 }); 52029 } 52030} 52031 52032/* harmony default export */ const ol_DataTile = (DataTile); 52033 52034;
52034// CONCATENATED MODULE: ./node_modules/ol/webgl.js 52035/** 52036 * @module ol/webgl 52037 */ 52038 52039 52040 52041/** 52042 * Constants taken from goog.webgl 52043 */ 52044 52045/** 52046 * Used by {@link module:ol/webgl/Helper~WebGLHelper} for buffers containing vertices data, such as 52047 * position, color, texture coordinate, etc. These vertices are then referenced by an index buffer 52048 * to be drawn on screen (see {@link module:ol/webgl.ELEMENT_ARRAY_BUFFER}). 52049 * @const 52050 * @type {number} 52051 * @api 52052 */ 52053const ARRAY_BUFFER = 0x8892; 52054 52055/** 52056 * Used by {@link module:ol/webgl/Helper~WebGLHelper} for buffers containing indices data. 52057 * Index buffers are essentially lists of references to vertices defined in a vertex buffer 52058 * (see {@link module:ol/webgl.ARRAY_BUFFER}), and define the primitives (triangles) to be drawn. 52059 * @const 52060 * @type {number} 52061 * @api 52062 */ 52063const ELEMENT_ARRAY_BUFFER = 0x8893; 52064 52065/** 52066 * Used by {link module:ol/webgl/Buffer~WebGLArrayBuffer}. 52067 * @const 52068 * @type {number} 52069 * @api 52070 */ 52071const STREAM_DRAW = 0x88e0; 52072 52073/** 52074 * Used by {link module:ol/webgl/Buffer~WebGLArrayBuffer}. 52075 * @const 52076 * @type {number} 52077 * @api 52078 */ 52079const STATIC_DRAW = 0x88e4; 52080 52081/** 52082 * Used by {link module:ol/webgl/Buffer~WebGLArrayBuffer}. 52083 * @const 52084 * @type {number} 52085 * @api 52086 */ 52087const DYNAMIC_DRAW = 0x88e8; 52088 52089/** 52090 * @const 52091 * @type {number} 52092 */ 52093const UNSIGNED_BYTE = 0x1401; 52094 52095/** 52096 * @const 52097 * @type {number} 52098 */ 52099const UNSIGNED_SHORT = 0x1403; 52100 52101/** 52102 * @const 52103 * @type {number} 52104 */ 52105const UNSIGNED_INT = 0x1405; 52106 52107/** 52108 * @const 52109 * @type {number} 52110 */ 52111const FLOAT = 0x1406; 52112 52113/** end of goog.webgl constants 52114 */ 52115 52116/** 52117 * @const 52118 * @type {Array<string>} 52119 */ 52120const CONTEXT_IDS = ['experimental-webgl', 'webgl', 'webkit-3d', 'moz-webgl']; 52121 52122/** 52123 * @param {HTMLCanvasElement} canvas Canvas. 52124 * @param {Object} [attributes] Attributes. 52125 * @return {WebGLRenderingContext} WebGL rendering context. 52126 */ 52127function getContext(canvas, attributes) { 52128 attributes = Object.assign( 52129 { 52130 preserveDrawingBuffer: true, 52131 antialias: SAFARI_BUG_237906 ? false : true, // https://bugs.webkit.org/show_bug.cgi?id=237906 52132 }, 52133 attributes 52134 ); 52135 const ii = CONTEXT_IDS.length; 52136 for (let i = 0; i < ii; ++i) { 52137 try { 52138 const context = canvas.getContext(CONTEXT_IDS[i], attributes); 52139 if (context) {
52140 return /** @type {!WebGLRenderingContext} */ (context); 52141 } 52142 } catch (e) { 52143 // pass 52144 } 52145 } 52146 return null; 52147} 52148 52149/** 52150 * @type {Array<string>} 52151 */ 52152let supportedExtensions; 52153 52154/** 52155 * @return {Array<string>} List of supported WebGL extensions. 52156 */ 52157function getSupportedExtensions() { 52158 if (!supportedExtensions) { 52159 const canvas = document.createElement('canvas'); 52160 const gl = getContext(canvas); 52161 if (gl) { 52162 supportedExtensions = gl.getSupportedExtensions(); 52163 } 52164 } 52165 return supportedExtensions; 52166} 52167 52168;// CONCATENATED MODULE: ./node_modules/ol/webgl/Buffer.js 52169/** 52170 * @module ol/webgl/Buffer 52171 */ 52172 52173 52174 52175/** 52176 * Used to describe the intended usage for the data: `STATIC_DRAW`, `STREAM_DRAW` 52177 * or `DYNAMIC_DRAW`. 52178 * @enum {number} 52179 */ 52180const BufferUsage = { 52181 STATIC_DRAW: STATIC_DRAW, 52182 STREAM_DRAW: STREAM_DRAW, 52183 DYNAMIC_DRAW: DYNAMIC_DRAW, 52184}; 52185 52186/** 52187 * @classdesc 52188 * Object used to store an array of data as well as usage information for that data. 52189 * Stores typed arrays internally, either Float32Array or Uint16/32Array depending on 52190 * the buffer type (ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER) and available extensions. 52191 * 52192 * To populate the array, you can either use: 52193 * * A size using `#ofSize(buffer)` 52194 * * An `ArrayBuffer` object using `#fromArrayBuffer(buffer)` 52195 * * A plain array using `#fromArray(array)` 52196 * 52197 * Note: 52198 * See the documentation of [WebGLRenderingContext.bufferData](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bufferData) 52199 * for more info on buffer usage. 52200 * @api 52201 */ 52202class WebGLArrayBuffer { 52203 /** 52204 * @param {number} type Buffer type, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER. 52205 * @param {number} [usage] Intended usage, either `STATIC_DRAW`, `STREAM_DRAW` or `DYNAMIC_DRAW`. 52206 * Default is `DYNAMIC_DRAW`. 52207 */ 52208 constructor(type, usage) { 52209 /** 52210 * @private 52211 * @type {Float32Array|Uint32Array} 52212 */ 52213 this.array = null; 52214 52215 /** 52216 * @private 52217 * @type {number} 52218 */ 52219 this.type = type; 52220 52221 asserts_assert(type === ARRAY_BUFFER || type === ELEMENT_ARRAY_BUFFER, 62); 52222 52223 /** 52224 * @private 52225 * @type {number} 52226 */ 52227 this.usage = usage !== undefined ? usage : BufferUsage.STATIC_DRAW; 52228 } 52229 52230 /** 52231 * Populates the buffer with an array of the given size (all values will be zeroes). 52232 * @param {number} size Array size 52233 */ 52234 ofSize(size) { 52235 this.array = new (getArrayClassForType(this.type))(size); 52236 } 52237 52238 /** 52239 * Populates the buffer with an array of the given size. 52240 * @param {Array<number>} array Numerical array 52241 */ 52242 fromArray(array) { 52243 this.array = getArrayClassForType(this.type).from(array); 52244 } 52245 52246 /** 52247 * Populates the buffer with a raw binary array buffer. 52248 * @param {ArrayBuffer} buffer Raw binary buffer to populate the array with. Note that this buffer must have been 52249 * initialized for the same typed array class. 52250 */ 52251 fromArrayBuffer(buffer) { 52252 this.array = new (getArrayClassForType(this.type))(buffer); 52253 } 52254 52255 /** 52256 * @return {number} Buffer type. 52257 */ 52258 getType() { 52259 return this.type; 52260 } 52261 52262 /** 52263 * Will return null if the buffer was not initialized 52264 * @return {Float32Array|Uint32Array} Array. 52265 */ 52266 getArray() { 52267 return this.array; 52268 } 52269 52270 /** 52271 * @return {number} Usage. 52272 */ 52273 getUsage() { 52274 return this.usage; 52275 } 52276 52277 /** 52278 * Will return 0 if the buffer is not initialized 52279 * @return {number} Array size 52280 */ 52281 getSize() { 52282 return this.array ? this.array.length : 0; 52283 } 52284} 52285 52286/** 52287 * Returns a typed array constructor based on the given buffer type 52288 * @param {number} type Buffer type, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER. 52289 * @return {Float32ArrayConstructor|Uint32ArrayConstructor} The typed array class to use for this buffer. 52290 */ 52291function getArrayClassForType(type) { 52292 switch (type) { 52293 case ARRAY_BUFFER: 52294 return Float32Array; 52295 case ELEMENT_ARRAY_BUFFER: 52296 return Uint32Array; 52297 default: 52298 return Float32Array; 52299 } 52300} 52301 52302/* harmony default export */ const Buffer = (WebGLArrayBuffer); 52303 52304;// CONCATENATED MODULE: ./node_modules/ol/webgl/TileTexture.js 52305/** 52306 * @module ol/webgl/TileTexture 52307 */ 52308 52309 52310 52311 52312 52313 52314 52315 52316 52317 52318 52319/** 52320 * @param {WebGLRenderingContext} gl The WebGL context. 52321 * @param {WebGLTexture} texture The texture. 52322 * @param {boolean} interpolate Interpolate when resampling. 52323 */ 52324function bindAndConfigure(gl, texture, interpolate) { 52325 const resampleFilter = interpolate ? gl.LINEAR : gl.NEAREST; 52326 gl.bindTexture(gl.TEXTURE_2D, texture); 52327 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 52328 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 52329 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, resampleFilter); 52330 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, resampleFilter); 52331} 52332 52333/** 52334 * @param {WebGLRenderingContext} gl The WebGL context. 52335 * @param {WebGLTexture} texture The texture. 52336 * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image The image. 52337 * @param {boolean} interpolate Interpolate when resampling. 52338 */ 52339function uploadImageTexture(gl, texture, image, interpolate) { 52340 bindAndConfigure(gl, texture, interpolate); 52341 52342 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 52343} 52344 52345/** 52346 * @param {import("./Helper.js").default} helper The WebGL helper. 52347 * @param {WebGLTexture} texture The texture. 52348 * @param {import("../DataTile.js").Data} data The pixel data. 52349 * @param {import("../size.js").Size} size The pixel size. 52350 * @param {number} bandCount The band count. 52351 * @param {boolean} interpolate Interpolate when resampling. 52352 */ 52353function uploadDataTexture( 52354 helper, 52355 texture, 52356 data, 52357 size, 52358 bandCount, 52359 interpolate 52360) { 52361 const gl = helper.getGL(); 52362 let textureType; 52363 let canInterpolate; 52364 if (data instanceof Float32Array) { 52365 textureType = gl.FLOAT; 52366 helper.getExtension('OES_texture_float'); 52367 const extension = helper.getExtension('OES_texture_float_linear'); 52368 canInterpolate = extension !== null; 52369 } else { 52370 textureType = gl.UNSIGNED_BYTE; 52371 canInterpolate = true; 52372 } 52373 bindAndConfigure(gl, texture, interpolate && canInterpolate); 52374 52375 const bytesPerRow = data.byteLength / size[1]; 52376 let unpackAlignment = 1; 52377 if (bytesPerRow % 8 === 0) { 52378 unpackAlignment = 8; 52379 } else if (bytesPerRow % 4 === 0) { 52380 unpackAlignment = 4; 52381 } else if (bytesPerRow % 2 === 0) { 52382 unpackAlignment = 2; 52383 } 52384 52385 let format; 52386 switch (bandCount) { 52387 case 1: { 52388 format = gl.LUMINANCE; 52389 break; 52390 } 52391 case 2: { 52392 format = gl.LUMINANCE_ALPHA; 52393 break; 52394 } 52395 case 3: { 52396 format = gl.RGB; 52397 break; 52398 } 52399 case 4: { 52400 format = gl.RGBA; 52401 break; 52402 } 52403 default: { 52404 throw new Error(`Unsupported number of bands: ${bandCount}`); 52405 } 52406 } 52407 52408 const oldUnpackAlignment = gl.getParameter(gl.UNPACK_ALIGNMENT); 52409 gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); 52410 gl.texImage2D( 52411 gl.TEXTURE_2D, 52412 0, 52413 format, 52414 size[0], 52415 size[1], 52416 0, 52417 format, 52418 textureType, 52419 data 52420 ); 52421 gl.pixelStorei(gl.UNPACK_ALIGNMENT, oldUnpackAlignment); 52422} 52423 52424/** 52425 * @type {CanvasRenderingContext2D} 52426 */ 52427let TileTexture_pixelContext = null; 52428 52429function TileTexture_createPixelContext() { 52430 const canvas = document.createElement('canvas'); 52431 canvas.width = 1; 52432 canvas.height = 1; 52433 TileTexture_pixelContext = canvas.getContext('2d'); 52434} 52435 52436/** 52437 * @typedef {import("../DataTile.js").default|ImageTile|ReprojTile} TileType 52438 */ 52439 52440/** 52441 * @typedef {Object} Options 52442 * @property {TileType} tile The tile. 52443 * @property {import("../tilegrid/TileGrid.js").default} grid Tile grid. 52444 * @property {import("../webgl/Helper.js").default} helper WebGL helper. 52445 * @property {number} [gutter=0] The size in pixels of the gutter around image tiles to ignore. 52446 */ 52447 52448class TileTexture extends events_Target { 52449 /** 52450 * @param {Options} options The tile texture options. 52451 */ 52452 constructor(options) { 52453 super(); 52454 52455 /** 52456 * @type {TileType} 52457 */ 52458 this.tile; 52459 52460 /** 52461 * @type {Array<WebGLTexture>} 52462 */ 52463 this.textures = []; 52464 this.handleTileChange_ = this.handleTileChange_.bind(this); 52465 52466 /** 52467 * @type {import("../size.js").Size} 52468 * @private 52469 */ 52470 this.renderSize_ = toSize( 52471 options.grid.getTileSize(options.tile.tileCoord[0]) 52472 ); 52473 52474 /** 52475 * @type {number} 52476 * @private 52477 */ 52478 this.gutter_ = options.gutter || 0; 52479 52480 /** 52481 * @type {number} 52482 */ 52483 this.bandCount = NaN; 52484 52485 /** 52486 * @type {import("../webgl/Helper.js").default} 52487 * @private 52488 */ 52489 this.helper_ = options.helper; 52490 52491 const coords = new Buffer(ARRAY_BUFFER, STATIC_DRAW); 52492 coords.fromArray([ 52493 0, // P0 52494 1, 52495 1, // P1 52496 1, 52497 1, // P2 52498 0, 52499 0, // P3 52500 0, 52501 ]); 52502 this.helper_.flushBufferData(coords); 52503 52504 /** 52505 * @type {WebGLArrayBuffer} 52506 */ 52507 this.coords = coords; 52508 52509 this.setTile(options.tile); 52510 } 52511 52512 /** 52513 * @param {TileType} tile Tile. 52514 */ 52515 setTile(tile) { 52516 if (tile !== this.tile) { 52517 if (this.tile) { 52518 this.tile.removeEventListener(EventType.CHANGE, this.handleTileChange_); 52519 } 52520 this.tile = tile; 52521 this.textures.length = 0; 52522 this.loaded = tile.getState() === TileState.LOADED; 52523 if (this.loaded) { 52524 this.uploadTile_(); 52525 } else { 52526 if (tile instanceof ol_ImageTile) { 52527 const image = tile.getImage(); 52528 if (image instanceof Image && !image.crossOrigin) { 52529 image.crossOrigin = 'anonymous'; 52530 } 52531 } 52532 tile.addEventListener(EventType.CHANGE, this.handleTileChange_); 52533 } 52534 } 52535 } 52536 52537 uploadTile_() { 52538 const helper = this.helper_; 52539 const gl = helper.getGL(); 52540 const tile = this.tile; 52541 52542 if (tile instanceof ol_ImageTile || tile instanceof reproj_Tile) { 52543 const texture = gl.createTexture(); 52544 this.textures.push(texture); 52545 this.bandCount = 4; 52546 uploadImageTexture(gl, texture, tile.getImage(), tile.interpolate); 52547 return; 52548 } 52549 52550 const sourceTileSize = tile.getSize(); 52551 const pixelSize = [ 52552 sourceTileSize[0] + 2 * this.gutter_, 52553 sourceTileSize[1] + 2 * this.gutter_, 52554 ]; 52555 const data = tile.getData(); 52556 const isFloat = data instanceof Float32Array; 52557 const pixelCount = pixelSize[0] * pixelSize[1]; 52558 const DataType = isFloat ? Float32Array : Uint8Array; 52559 const bytesPerElement = DataType.BYTES_PER_ELEMENT; 52560 const bytesPerRow = data.byteLength / pixelSize[1]; 52561 52562 this.bandCount = Math.floor(bytesPerRow / bytesPerElement / pixelSize[0]);
52563 const textureCount = Math.ceil(this.bandCount / 4); 52564 52565 if (textureCount === 1) { 52566 const texture = gl.createTexture(); 52567 this.textures.push(texture); 52568 uploadDataTexture( 52569 helper, 52570 texture, 52571 data, 52572 pixelSize, 52573 this.bandCount, 52574 tile.interpolate 52575 ); 52576 return; 52577 } 52578 52579 const textureDataArrays = new Array(textureCount); 52580 for (let textureIndex = 0; textureIndex < textureCount; ++textureIndex) { 52581 const texture = gl.createTexture(); 52582 this.textures.push(texture); 52583 52584 const bandCount = 52585 textureIndex < textureCount - 1 ? 4 : ((this.bandCount - 1) % 4) + 1; 52586 textureDataArrays[textureIndex] = new DataType(pixelCount * bandCount); 52587 } 52588 52589 let dataIndex = 0; 52590 let rowOffset = 0; 52591 const colCount = pixelSize[0] * this.bandCount; 52592 for (let rowIndex = 0; rowIndex < pixelSize[1]; ++rowIndex) { 52593 for (let colIndex = 0; colIndex < colCount; ++colIndex) { 52594 const dataValue = data[rowOffset + colIndex]; 52595 52596 const pixelIndex = Math.floor(dataIndex / this.bandCount); 52597 const bandIndex = colIndex % this.bandCount; 52598 const textureIndex = Math.floor(bandIndex / 4); 52599 const textureData = textureDataArrays[textureIndex]; 52600 const bandCount = textureData.length / pixelCount; 52601 const textureBandIndex = bandIndex % 4; 52602 textureData[pixelIndex * bandCount + textureBandIndex] = dataValue; 52603 52604 ++dataIndex; 52605 } 52606 rowOffset += bytesPerRow / bytesPerElement; 52607 } 52608 52609 for (let textureIndex = 0; textureIndex < textureCount; ++textureIndex) { 52610 const texture = this.textures[textureIndex]; 52611 const textureData = textureDataArrays[textureIndex]; 52612 const bandCount = textureData.length / pixelCount; 52613 uploadDataTexture( 52614 helper, 52615 texture, 52616 textureData, 52617 pixelSize, 52618 bandCount, 52619 tile.interpolate 52620 ); 52621 } 52622 } 52623 52624 handleTileChange_() { 52625 if (this.tile.getState() === TileState.LOADED) { 52626 this.loaded = true; 52627 this.uploadTile_(); 52628 this.dispatchEvent(EventType.CHANGE); 52629 } 52630 } 52631 52632 disposeInternal() { 52633 const gl = this.helper_.getGL(); 52634 this.helper_.deleteBuffer(this.coords); 52635 for (let i = 0; i < this.textures.length; ++i) { 52636 gl.deleteTexture(this.textures[i]); 52637 } 52638 this.tile.removeEventListener(EventType.CHANGE, this.handleTileChange_); 52639 } 52640 52641 /** 52642 * Get data for a pixel. If the tile is not loaded, null is returned. 52643 * @param {number} renderCol The column index (in rendered tile space). 52644 * @param {number} renderRow The row index (in rendered tile space). 52645 * @return {import("../DataTile.js").Data|null} The data. 52646 */ 52647 getPixelData(renderCol, renderRow) { 52648 if (!this.loaded) { 52649 return null; 52650 } 52651 const renderWidth = this.renderSize_[0]; 52652 const renderHeight = this.renderSize_[1]; 52653 const gutter = this.gutter_; 52654 52655 if (this.tile instanceof ol_DataTile) { 52656 const sourceSize = this.tile.getSize(); 52657 52658 const sourceWidthWithoutGutter = sourceSize[0]; 52659 const sourceHeightWithoutGutter = sourceSize[1]; 52660 const sourceWidth = sourceWidthWithoutGutter + 2 * gutter; 52661 const sourceHeight = sourceHeightWithoutGutter + 2 * gutter; 52662 52663 const sourceCol = 52664 gutter + 52665 Math.floor(sourceWidthWithoutGutter * (renderCol / renderWidth)); 52666 52667 const sourceRow = 52668 gutter + 52669 Math.floor(sourceHeightWithoutGutter * (renderRow / renderHeight)); 52670 52671 const data = this.tile.getData(); 52672 if (data instanceof DataView) { 52673 const bytesPerPixel = data.byteLength / (sourceWidth * sourceHeight); 52674 const offset = bytesPerPixel * (sourceRow * sourceWidth + sourceCol); 52675 const buffer = data.buffer.slice(offset, offset + bytesPerPixel); 52676 return new DataView(buffer); 52677 } 52678 52679 const offset = this.bandCount * (sourceRow * sourceWidth + sourceCol); 52680 return data.slice(offset, offset + this.bandCount); 52681 } 52682 52683 if (!TileTexture_pixelContext) { 52684 TileTexture_createPixelContext(); 52685 } 52686 TileTexture_pixelContext.clearRect(0, 0, 1, 1); 52687 52688 const image = this.tile.getImage(); 52689 const sourceWidth = image.width; 52690 const sourceHeight = image.height; 52691
52692 const sourceWidthWithoutGutter = sourceWidth - 2 * gutter; 52693 const sourceHeightWithoutGutter = sourceHeight - 2 * gutter; 52694 52695 const sourceCol = 52696 gutter + Math.floor(sourceWidthWithoutGutter * (renderCol / renderWidth)); 52697 52698 const sourceRow = 52699 gutter + 52700 Math.floor(sourceHeightWithoutGutter * (renderRow / renderHeight)); 52701 52702 let data; 52703 try { 52704 TileTexture_pixelContext.drawImage(image, sourceCol, sourceRow, 1, 1, 0, 0, 1, 1); 52705 data = TileTexture_pixelContext.getImageData(0, 0, 1, 1).data; 52706 } catch (err) { 52707 TileTexture_pixelContext = null; 52708 return null; 52709 } 52710 return data; 52711 } 52712} 52713 52714/* harmony default export */ const webgl_TileTexture = (TileTexture); 52715 52716;// CONCATENATED MODULE: ./node_modules/ol/webgl/ContextEventType.js 52717/** 52718 * @module ol/webgl/ContextEventType 52719 */ 52720 52721/** 52722 * @enum {string} 52723 */ 52724/* harmony default export */ const ContextEventType = ({ 52725 LOST: 'webglcontextlost', 52726 RESTORED: 'webglcontextrestored', 52727}); 52728 52729;// CONCATENATED MODULE: ./node_modules/ol/webgl/PostProcessingPass.js 52730/** 52731 * @module ol/webgl/PostProcessingPass 52732 */ 52733 52734 52735 52736const DEFAULT_VERTEX_SHADER = ` 52737 precision mediump float; 52738 52739 attribute vec2 a_position; 52740 varying vec2 v_texCoord; 52741 varying vec2 v_screenCoord; 52742 52743 uniform vec2 u_screenSize; 52744 52745 void main() { 52746 v_texCoord = a_position * 0.5 + 0.5; 52747 v_screenCoord = v_texCoord * u_screenSize; 52748 gl_Position = vec4(a_position, 0.0, 1.0); 52749 } 52750`; 52751 52752const DEFAULT_FRAGMENT_SHADER = ` 52753 precision mediump float; 52754 52755 uniform sampler2D u_image; 52756 uniform float u_opacity; 52757 52758 varying vec2 v_texCoord; 52759 52760 void main() { 52761 gl_FragColor = texture2D(u_image, v_texCoord) * u_opacity; 52762 } 52763`; 52764 52765/** 52766 * @typedef {Object} Options 52767 * @property {WebGLRenderingContext} webGlContext WebGL context; mandatory. 52768 * @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than 52769 * the main canvas that will then be sampled up (useful for saving resource on blur steps). 52770 * @property {string} [vertexShader] Vertex shader source 52771 * @property {string} [fragmentShader] Fragment shader source 52772 * @property {Object<string,import("./Helper").UniformValue>} [uniforms] Uniform definitions for the post process step 52773 */ 52774 52775/** 52776 * @typedef {Object} UniformInternalDescription 52777 * @property {import("./Helper").UniformValue} value Value 52778 * @property {number} location Location 52779 * @property {WebGLTexture} [texture] Texture 52780 * @private 52781 */ 52782 52783/** 52784 * @classdesc 52785 * This class is used to define Post Processing passes with custom shaders and uniforms. 52786 * This is used internally by {@link module:ol/webgl/Helper~WebGLHelper}. 52787 * 52788 * Please note that the final output on the DOM canvas is expected to have premultiplied alpha, which means that 52789 * a pixel which is 100% red with an opacity of 50% must have a color of (r=0.5, g=0, b=0, a=0.5). 52790 * Failing to provide pixel colors with premultiplied alpha will result in render anomalies. 52791 * 52792 * The default post-processing pass does *not* multiply color values with alpha value, it expects color values to be 52793 * premultiplied. 52794 * 52795 * Default shaders are shown hereafter: 52796 * 52797 * * Vertex shader: 52798 * 52799 * ``` 52800 * precision mediump float; 52801 * 52802 * attribute vec2 a_position; 52803 * varying vec2 v_texCoord; 52804 * varying vec2 v_screenCoord; 52805 * 52806 * uniform vec2 u_screenSize; 52807 * 52808 * void main() { 52809 * v_texCoord = a_position * 0.5 + 0.5; 52810 * v_screenCoord = v_texCoord * u_screenSize; 52811 * gl_Position = vec4(a_position, 0.0, 1.0); 52812 * } 52813 * ``` 52814 * 52815 * * Fragment shader: 52816 * 52817 * ``` 52818 * precision mediump float; 52819 * 52820 * uniform sampler2D u_image; 52821 * uniform float u_opacity; 52822 * 52823 * varying vec2 v_texCoord; 52824 * 52825 * void main() { 52826 * gl_FragColor = texture2D(u_image, v_texCoord) * u_opacity; 52827 * } 52828 * ``` 52829 * 52830 * @api 52831 */ 52832class WebGLPostProcessingPass { 52833 /** 52834 * @param {Options} options Options. 52835 */ 52836 constructor(options) { 52837 this.gl_ = options.webGlContext; 52838 const gl = this.gl_; 52839 52840 this.scaleRatio_ = options.scaleRatio || 1; 52841 52842 this.renderTargetTexture_ = gl.createTexture(); 52843 this.renderTargetTextureSize_ = null; 52844 52845 this.frameBuffer_ = gl.createFramebuffer(); 52846 52847 // compile the program for the frame buffer 52848 // TODO: make compilation errors show up 52849 const vertexShader = gl.createShader(gl.VERTEX_SHADER); 52850 gl.shaderSource( 52851 vertexShader, 52852 options.vertexShader || DEFAULT_VERTEX_SHADER 52853 ); 52854 gl.compileShader(vertexShader); 52855 const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); 52856 gl.shaderSource( 52857 fragmentShader, 52858 options.fragmentShader || DEFAULT_FRAGMENT_SHADER 52859 ); 52860 gl.compileShader(fragmentShader); 52861 this.renderTargetProgram_ = gl.createProgram(); 52862 gl.attachShader(this.renderTargetProgram_, vertexShader); 52863 gl.attachShader(this.renderTargetProgram_, fragmentShader); 52864 gl.linkProgram(this.renderTargetProgram_); 52865 52866 // bind the vertices buffer for the frame buffer 52867 this.renderTargetVerticesBuffer_ = gl.createBuffer(); 52868 const verticesArray = [-1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1]; 52869 gl.bindBuffer(gl.ARRAY_BUFFER, this.renderTargetVerticesBuffer_); 52870 gl.bufferData( 52871 gl.ARRAY_BUFFER, 52872 new Float32Array(verticesArray), 52873 gl.STATIC_DRAW 52874 ); 52875 52876 this.renderTargetAttribLocation_ = gl.getAttribLocation( 52877 this.renderTargetProgram_, 52878 'a_position' 52879 ); 52880 this.renderTargetUniformLocation_ = gl.getUniformLocation( 52881 this.renderTargetProgram_, 52882 'u_screenSize' 52883 ); 52884 this.renderTargetOpacityLocation_ = gl.getUniformLocation( 52885 this.renderTargetProgram_, 52886 'u_opacity' 52887 ); 52888 this.renderTargetTextureLocation_ = gl.getUniformLocation( 52889 this.renderTargetProgram_, 52890 'u_image' 52891 ); 52892 52893 /** 52894 * Holds info about custom uniforms used in the post processing pass 52895 * @type {Array<UniformInternalDescription>} 52896 * @private 52897 */ 52898 this.uniforms_ = []; 52899 options.uniforms &&
52900 Object.keys(options.uniforms).forEach( 52901 function (name) { 52902 this.uniforms_.push({ 52903 value: options.uniforms[name], 52904 location: gl.getUniformLocation(this.renderTargetProgram_, name), 52905 }); 52906 }.bind(this) 52907 ); 52908 } 52909 52910 /** 52911 * Get the WebGL rendering context 52912 * @return {WebGLRenderingContext} The rendering context. 52913 * @api 52914 */ 52915 getGL() { 52916 return this.gl_; 52917 } 52918 52919 /** 52920 * Initialize the render target texture of the post process, make sure it is at the 52921 * right size and bind it as a render target for the next draw calls. 52922 * The last step to be initialized will be the one where the primitives are rendered. 52923 * @param {import("../Map.js").FrameState} frameState current frame state 52924 * @api 52925 */ 52926 init(frameState) { 52927 const gl = this.getGL(); 52928 const textureSize = [ 52929 gl.drawingBufferWidth * this.scaleRatio_, 52930 gl.drawingBufferHeight * this.scaleRatio_, 52931 ]; 52932 52933 // rendering goes to my buffer 52934 gl.bindFramebuffer(gl.FRAMEBUFFER, this.getFrameBuffer()); 52935 gl.viewport(0, 0, textureSize[0], textureSize[1]); 52936 52937 // if size has changed: adjust canvas & render target texture 52938 if ( 52939 !this.renderTargetTextureSize_ || 52940 this.renderTargetTextureSize_[0] !== textureSize[0] || 52941 this.renderTargetTextureSize_[1] !== textureSize[1] 52942 ) { 52943 this.renderTargetTextureSize_ = textureSize; 52944 52945 // create a new texture 52946 const level = 0; 52947 const internalFormat = gl.RGBA; 52948 const border = 0; 52949 const format = gl.RGBA; 52950 const type = gl.UNSIGNED_BYTE; 52951 const data = null; 52952 gl.bindTexture(gl.TEXTURE_2D, this.renderTargetTexture_); 52953 gl.texImage2D( 52954 gl.TEXTURE_2D, 52955 level, 52956 internalFormat, 52957 textureSize[0], 52958 textureSize[1], 52959 border, 52960 format, 52961 type, 52962 data 52963 ); 52964 52965 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 52966 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 52967 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 52968 52969 // bind the texture to the framebuffer 52970 gl.framebufferTexture2D( 52971 gl.FRAMEBUFFER, 52972 gl.COLOR_ATTACHMENT0, 52973 gl.TEXTURE_2D, 52974 this.renderTargetTexture_, 52975 0 52976 ); 52977 } 52978 } 52979 52980 /** 52981 * Render to the next postprocessing pass (or to the canvas if final pass). 52982 * @param {import("../Map.js").FrameState} frameState current frame state 52983 * @param {WebGLPostProcessingPass} [nextPass] Next pass, optional 52984 * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing. 52985 * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing. 52986 * @api 52987 */ 52988 apply(frameState, nextPass, preCompose, postCompose) { 52989 const gl = this.getGL(); 52990 const size = frameState.size; 52991 52992 gl.bindFramebuffer( 52993 gl.FRAMEBUFFER, 52994 nextPass ? nextPass.getFrameBuffer() : null 52995 ); 52996 gl.activeTexture(gl.TEXTURE0); 52997 gl.bindTexture(gl.TEXTURE_2D, this.renderTargetTexture_); 52998 52999 if (!nextPass) { 53000 // clear the canvas if we are the first to render to it 53001 // and preserveDrawingBuffer is true 53002 const canvasId = getUid(gl.canvas); 53003 if (!frameState.renderTargets[canvasId]) { 53004 const attributes = gl.getContextAttributes(); 53005 if (attributes && attributes.preserveDrawingBuffer) { 53006 gl.clearColor(0.0, 0.0, 0.0, 0.0); 53007 gl.clear(gl.COLOR_BUFFER_BIT); 53008 } 53009 53010 frameState.renderTargets[canvasId] = true; 53011 } 53012 } 53013 53014 gl.enable(gl.BLEND); 53015 gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 53016 gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 53017 53018 gl.bindBuffer(gl.ARRAY_BUFFER, this.renderTargetVerticesBuffer_); 53019 53020 gl.useProgram(this.renderTargetProgram_); 53021 gl.enableVertexAttribArray(this.renderTargetAttribLocation_); 53022 gl.vertexAttribPointer( 53023 this.renderTargetAttribLocation_, 53024 2, 53025 gl.FLOAT, 53026 false, 53027 0, 53028 0 53029 ); 53030 gl.uniform2f(this.renderTargetUniformLocation_, size[0], size[1]); 53031 gl.uniform1i(this.renderTargetTextureLocation_, 0); 53032 53033 const opacity = frameState.layerStatesArray[frameState.layerIndex].opacity; 53034 gl.uniform1f(this.renderTargetOpacityLocation_, opacity); 53035 53036 this.applyUniforms(frameState); 53037 53038 if (preCompose) { 53039 preCompose(gl, frameState); 53040 } 53041 gl.drawArrays(gl.TRIANGLES, 0, 6); 53042 if (postCompose) { 53043 postCompose(gl, frameState); 53044 } 53045 } 53046 53047 /** 53048 * @return {WebGLFramebuffer} Frame buffer 53049 * @api 53050 */ 53051 getFrameBuffer() { 53052 return this.frameBuffer_; 53053 } 53054 53055 /** 53056 * Sets the custom uniforms based on what was given in the constructor. 53057 * @param {import("../Map.js").FrameState} frameState Frame state. 53058 * @private 53059 */ 53060 applyUniforms(frameState) { 53061 const gl = this.getGL(); 53062 53063 let value; 53064 let textureSlot = 1; 53065 this.uniforms_.forEach(function (uniform) { 53066 value = 53067 typeof uniform.value === 'function' 53068 ? uniform.value(frameState) 53069 : uniform.value; 53070 53071 // apply value based on type 53072 if (value instanceof HTMLCanvasElement || value instanceof ImageData) { 53073 // create a texture & put data 53074 if (!uniform.texture) { 53075 uniform.texture = gl.createTexture(); 53076 } 53077 gl.activeTexture(gl[`TEXTURE${textureSlot}`]); 53078 gl.bindTexture(gl.TEXTURE_2D, uniform.texture); 53079 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 53080 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 53081 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 53082 53083 if (value instanceof ImageData) { 53084 gl.texImage2D( 53085 gl.TEXTURE_2D, 53086 0, 53087 gl.RGBA, 53088 gl.RGBA, 53089 value.width, 53090 value.height, 53091 0, 53092 gl.UNSIGNED_BYTE, 53093 new Uint8Array(value.data) 53094 ); 53095 } else { 53096 gl.texImage2D( 53097 gl.TEXTURE_2D, 53098 0, 53099 gl.RGBA, 53100 gl.RGBA, 53101 gl.UNSIGNED_BYTE, 53102 value 53103 ); 53104 } 53105 53106 // fill texture slots 53107 gl.uniform1i(uniform.location, textureSlot++); 53108 } else if (Array.isArray(value)) { 53109 switch (value.length) { 53110 case 2: 53111 gl.uniform2f(uniform.location, value[0], value[1]); 53112 return; 53113 case 3: 53114 gl.uniform3f(uniform.location, value[0], value[1], value[2]); 53115 return; 53116 case 4: 53117 gl.uniform4f( 53118 uniform.location, 53119 value[0], 53120 value[1], 53121 value[2], 53122 value[3] 53123 ); 53124 return; 53125 default: 53126 return; 53127 } 53128 } else if (typeof value === 'number') { 53129 gl.uniform1f(uniform.location, value); 53130 } 53131 }); 53132 } 53133} 53134 53135/* harmony default export */ const PostProcessingPass = (WebGLPostProcessingPass); 53136 53137;// CONCATENATED MODULE: ./node_modules/ol/vec/mat4.js 53138/** 53139 * @module ol/vec/mat4 53140 */ 53141 53142/** 53143 * @return {Array<number>} "4x4 matrix representing a 3D identity transform." 53144 */ 53145function mat4_create() { 53146 return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; 53147} 53148 53149/** 53150 * @param {Array<number>} mat4 Flattened 4x4 matrix receiving the result. 53151 * @param {import("../transform.js").Transform} transform Transformation matrix. 53152 * @return {Array<number>} "2D transformation matrix as flattened 4x4 matrix." 53153 */ 53154function fromTransform(mat4, transform) { 53155 mat4[0] = transform[0]; 53156 mat4[1] = transform[1]; 53157 mat4[4] = transform[2]; 53158 mat4[5] = transform[3]; 53159 mat4[12] = transform[4]; 53160 mat4[13] = transform[5]; 53161 return mat4; 53162} 53163 53164;// CONCATENATED MODULE: ./node_modules/ol/webgl/Helper.js 53165/** 53166 * @module ol/webgl/Helper 53167 */ 53168 53169 53170 53171 53172 53173 53174 53175 53176 53177/** 53178 * @typedef {Object} BufferCacheEntry 53179 * @property {import("./Buffer.js").default} buffer Buffer. 53180 * @property {WebGLBuffer} webGlBuffer WebGlBuffer. 53181 */ 53182 53183/**
53184 * Shader types, either `FRAGMENT_SHADER` or `VERTEX_SHADER`. 53185 * @enum {number} 53186 */ 53187const ShaderType = { 53188 FRAGMENT_SHADER: 0x8b30, 53189 VERTEX_SHADER: 0x8b31, 53190}; 53191 53192/** 53193 * Names of uniforms made available to all shaders. 53194 * Please note: changing these *will* break custom shaders! 53195 * @enum {string} 53196 */ 53197const DefaultUniform = { 53198 PROJECTION_MATRIX: 'u_projectionMatrix', 53199 OFFSET_SCALE_MATRIX: 'u_offsetScaleMatrix', 53200 OFFSET_ROTATION_MATRIX: 'u_offsetRotateMatrix', 53201 TIME: 'u_time', 53202 ZOOM: 'u_zoom', 53203 RESOLUTION: 'u_resolution', 53204 SIZE_PX: 'u_sizePx', 53205 PIXEL_RATIO: 'u_pixelRatio', 53206}; 53207 53208/** 53209 * Attribute types, either `UNSIGNED_BYTE`, `UNSIGNED_SHORT`, `UNSIGNED_INT` or `FLOAT` 53210 * Note: an attribute stored in a `Float32Array` should be of type `FLOAT`. 53211 * @enum {number} 53212 */ 53213const AttributeType = { 53214 UNSIGNED_BYTE: UNSIGNED_BYTE, 53215 UNSIGNED_SHORT: UNSIGNED_SHORT, 53216 UNSIGNED_INT: UNSIGNED_INT, 53217 FLOAT: FLOAT, 53218}; 53219 53220/** 53221 * Description of an attribute in a buffer 53222 * @typedef {Object} AttributeDescription 53223 * @property {string} name Attribute name to use in shaders 53224 * @property {number} size Number of components per attributes 53225 * @property {AttributeType} [type] Attribute type, i.e. number of bytes used to store the value. This is 53226 * determined by the class of typed array which the buffer uses (eg. `Float32Array` for a `FLOAT` attribute). 53227 * Default is `FLOAT`. 53228 */ 53229 53230/** 53231 * @typedef {number|Array<number>|HTMLCanvasElement|HTMLImageElement|ImageData|import("../transform").Transform} UniformLiteralValue 53232 */ 53233 53234/** 53235 * Uniform value can be a number, array of numbers (2 to 4), canvas element or a callback returning 53236 * one of the previous types. 53237 * @typedef {UniformLiteralValue|function(import("../Map.js").FrameState):UniformLiteralValue} UniformValue 53238 */ 53239 53240/** 53241 * @typedef {Object} PostProcessesOptions 53242 * @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than 53243 * the main canvas which will then be sampled up (useful for saving resource on blur steps). 53244 * @property {string} [vertexShader] Vertex shader source 53245 * @property {string} [fragmentShader] Fragment shader source 53246 * @property {Object<string,UniformValue>} [uniforms] Uniform definitions for the post process step 53247 */ 53248 53249/** 53250 * @typedef {Object} Options 53251 * @property {Object<string,UniformValue>} [uniforms] Uniform definitions; property names must match the uniform 53252 * names in the provided or default shaders. 53253 * @property {Array<PostProcessesOptions>} [postProcesses] Post-processes definitions 53254 * @property {string} [canvasCacheKey] The cache key for the canvas. 53255 */ 53256 53257/** 53258 * @typedef {Object} UniformInternalDescription 53259 * @property {string} name Name 53260 * @property {UniformValue} [value] Value 53261 * @property {WebGLTexture} [texture] Texture 53262 * @private 53263 */ 53264 53265/** 53266 * @typedef {Object} CanvasCacheItem 53267 * @property {HTMLCanvasElement} canvas Canvas element. 53268 * @property {number} users The count of users of this canvas. 53269 */ 53270 53271/** 53272 * @type {Object<string,CanvasCacheItem>} 53273 */ 53274const canvasCache = {}; 53275 53276/** 53277 * @param {string} key The cache key for the canvas. 53278 * @return {string} The shared cache key. 53279 */ 53280function getSharedCanvasCacheKey(key) { 53281 return 'shared/' + key; 53282} 53283 53284let uniqueCanvasCacheKeyCount = 0; 53285 53286/** 53287 * @return {string} The unique cache key. 53288 */ 53289function getUniqueCanvasCacheKey() { 53290 const key = 'unique/' + uniqueCanvasCacheKeyCount; 53291 uniqueCanvasCacheKeyCount += 1; 53292 return key; 53293} 53294 53295/** 53296 * @param {string} key The cache key for the canvas. 53297 * @return {HTMLCanvasElement} The canvas. 53298 */ 53299function getCanvas(key) { 53300 let cacheItem = canvasCache[key]; 53301 if (!cacheItem) { 53302 const canvas = document.createElement('canvas'); 53303 canvas.style.position = 'absolute'; 53304 canvas.style.left = '0'; 53305 cacheItem = {users: 0, canvas}; 53306 canvasCache[key] = cacheItem; 53307 } 53308 53309 cacheItem.users += 1; 53310 return cacheItem.canvas; 53311} 53312 53313/** 53314 * @param {string} key The cache key for the canvas. 53315 */ 53316function Helper_releaseCanvas(key) { 53317 const cacheItem = canvasCache[key]; 53318 if (!cacheItem) { 53319 return; 53320 } 53321 53322 cacheItem.users -= 1; 53323 if (cacheItem.users > 0) { 53324 return; 53325 } 53326
53327 const canvas = cacheItem.canvas; 53328 const gl = getContext(canvas); 53329 const extension = gl.getExtension('WEBGL_lose_context'); 53330 if (extension) { 53331 extension.loseContext(); 53332 } 53333 53334 delete canvasCache[key]; 53335} 53336 53337/** 53338 * @classdesc 53339 * This class is intended to provide low-level functions related to WebGL rendering, so that accessing 53340 * directly the WebGL API should not be required anymore. 53341 * 53342 * Several operations are handled by the `WebGLHelper` class: 53343 * 53344 * ### Define custom shaders and uniforms 53345 * 53346 * *Shaders* are low-level programs executed on the GPU and written in GLSL. There are two types of shaders: 53347 * 53348 * Vertex shaders are used to manipulate the position and attribute of *vertices* of rendered primitives (ie. corners of a square). 53349 * Outputs are: 53350 * 53351 * * `gl_Position`: position of the vertex in screen space 53352 * 53353 * * Varyings usually prefixed with `v_` are passed on to the fragment shader 53354 * 53355 * Fragment shaders are used to control the actual color of the pixels drawn on screen. Their only output is `gl_FragColor`. 53356 * 53357 * Both shaders can take *uniforms* or *attributes* as input. Attributes are explained later. Uniforms are common, read-only values that 53358 * can be changed at every frame and can be of type float, arrays of float or images. 53359 * 53360 * Shaders must be compiled and assembled into a program like so: 53361 * ```js 53362 * // here we simply create two shaders and assemble them in a program which is then used 53363 * // for subsequent rendering calls; note how a frameState is required to set up a program, 53364 * // as several default uniforms are computed from it (projection matrix, zoom level, etc.) 53365 * const vertexShader = new WebGLVertex(VERTEX_SHADER); 53366 * const fragmentShader = new WebGLFragment(FRAGMENT_SHADER); 53367 * const program = this.context.getProgram(fragmentShader, vertexShader); 53368 * helper.useProgram(this.program, frameState); 53369 * ``` 53370 * 53371 * Uniforms are defined using the `uniforms` option and can either be explicit values or callbacks taking the frame state as argument. 53372 * You can also change their value along the way like so: 53373 * ```js 53374 * helper.setUniformFloatValue('u_value', valueAsNumber); 53375 * ``` 53376 * 53377 * ### Defining post processing passes 53378 * 53379 * *Post processing* describes the act of rendering primitives to a texture, and then rendering this texture to the final canvas 53380 * while applying special effects in screen space. 53381 * Typical uses are: blurring, color manipulation, depth of field, filtering... 53382 * 53383 * The `WebGLHelper` class offers the possibility to define post processes at creation time using the `postProcesses` option. 53384 * A post process step accepts the following options: 53385 * 53386 * * `fragmentShader` and `vertexShader`: text literals in GLSL language that will be compiled and used in the post processing step. 53387 * * `uniforms`: uniforms can be defined for the post processing steps just like for the main render. 53388 * * `scaleRatio`: allows using an intermediate texture smaller or higher than the final canvas in the post processing step. 53389 * This is typically used in blur steps to reduce the performance overhead by using an already downsampled texture as input. 53390 * 53391 * The {@link module:ol/webgl/PostProcessingPass~WebGLPostProcessingPass} class is used internally, refer to its documentation for more info. 53392 * 53393 * ### Binding WebGL buffers and flushing data into them 53394 * 53395 * Data that must be passed to the GPU has to be transferred using {@link module:ol/webgl/Buffer~WebGLArrayBuffer} objects. 53396 * A buffer has to be created only once, but must be bound every time the buffer content will be used for rendering. 53397 * This is done using {@link bindBuffer}. 53398 * When the buffer's array content has changed, the new data has to be flushed to the GPU memory; this is done using 53399 * {@link flushBufferData}. Note: this operation is expensive and should be done as infrequently as possible. 53400 * 53401 * When binding an array buffer, a `target` parameter must be given: it should be either {@link module:ol/webgl.ARRAY_BUFFER} 53402 * (if the buffer contains vertices data) or {@link module:ol/webgl.ELEMENT_ARRAY_BUFFER} (if the buffer contains indices data). 53403 * 53404 * Examples below: 53405 * ```js 53406 * // at initialization phase 53407 * const verticesBuffer = new WebGLArrayBuffer([], DYNAMIC_DRAW); 53408 * const indicesBuffer = new WebGLArrayBuffer([], DYNAMIC_DRAW); 53409 * 53410 * // when array values have changed 53411 * helper.flushBufferData(ARRAY_BUFFER, this.verticesBuffer); 53412 * helper.flushBufferData(ELEMENT_ARRAY_BUFFER, this.indicesBuffer); 53413 * 53414 * // at rendering phase 53415 * helper.bindBuffer(ARRAY_BUFFER, this.verticesBuffer); 53416 * helper.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer); 53417 * ``` 53418 * 53419 * ### Specifying attributes 53420 * 53421 * The GPU only receives the data as arrays of numbers. These numbers must be handled differently depending on what it describes (position, texture coordinate...). 53422 * Attributes are used to specify these uses. Specify the attribute names with 53423 * {@link module:ol/webgl/Helper~WebGLHelper#enableAttributes} (see code snippet below). 53424 * 53425 * Please note that you will have to specify the type and offset of the attributes in the data array. You can refer to the documentation of [WebGLRenderingContext.vertexAttribPointer](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer) for more explanation. 53426 * ```js 53427 * // here we indicate that the data array has the following structure: 53428 * // [posX, posY, offsetX, offsetY, texCoordU, texCoordV, posX, posY, ...] 53429 * helper.enableAttributes([ 53430 * { 53431 * name: 'a_position', 53432 * size: 2 53433 * }, 53434 * { 53435 * name: 'a_offset', 53436 * size: 2 53437 * }, 53438 * { 53439 * name: 'a_texCoord', 53440 * size: 2 53441 * } 53442 * ]) 53443 * ``` 53444 * 53445 * ### Rendering primitives 53446 * 53447 * Once all the steps above have been achieved, rendering primitives to the screen is done using {@link prepareDraw}, {@link drawElements} and {@link finalizeDraw}. 53448 * ```js 53449 * // frame preparation step 53450 * helper.prepareDraw(frameState); 53451 * 53452 * // call this for every data array that has to be rendered on screen 53453 * helper.drawElements(0, this.indicesBuffer.getArray().length); 53454 * 53455 * // finalize the rendering by applying post processes 53456 * helper.finalizeDraw(frameState); 53457 * ``` 53458 * 53459 * For an example usage of this class, refer to {@link module:ol/renderer/webgl/PointsLayer~WebGLPointsLayerRenderer}. 53460 */ 53461class WebGLHelper extends ol_Disposable { 53462 /** 53463 * @param {Options} [options] Options. 53464 */ 53465 constructor(options) { 53466 super(); 53467 options = options || {}; 53468 53469 /** @private */ 53470 this.boundHandleWebGLContextLost_ = this.handleWebGLContextLost.bind(this); 53471 53472 /** @private */ 53473 this.boundHandleWebGLContextRestored_ = 53474 this.handleWebGLContextRestored.bind(this); 53475 53476 /** 53477 * @private 53478 * @type {string} 53479 */ 53480 this.canvasCacheKey_ = options.canvasCacheKey 53481 ? getSharedCanvasCacheKey(options.canvasCacheKey) 53482 : getUniqueCanvasCacheKey(); 53483 53484 /** 53485 * @private 53486 * @type {HTMLCanvasElement} 53487 */ 53488 this.canvas_ = getCanvas(this.canvasCacheKey_); 53489 53490 /** 53491 * @private 53492 * @type {WebGLRenderingContext} 53493 */ 53494 this.gl_ = getContext(this.canvas_); 53495 53496 /** 53497 * @private
53498 * @type {!Object<string, BufferCacheEntry>} 53499 */ 53500 this.bufferCache_ = {}; 53501 53502 /** 53503 * @private 53504 * @type {Object<string, Object>} 53505 */ 53506 this.extensionCache_ = {}; 53507 53508 /** 53509 * @private 53510 * @type {WebGLProgram} 53511 */ 53512 this.currentProgram_ = null; 53513 53514 this.canvas_.addEventListener( 53515 ContextEventType.LOST, 53516 this.boundHandleWebGLContextLost_ 53517 ); 53518 this.canvas_.addEventListener( 53519 ContextEventType.RESTORED, 53520 this.boundHandleWebGLContextRestored_ 53521 ); 53522 53523 /** 53524 * @private 53525 * @type {import("../transform.js").Transform} 53526 */ 53527 this.offsetRotateMatrix_ = create(); 53528 53529 /** 53530 * @private 53531 * @type {import("../transform.js").Transform} 53532 */ 53533 this.offsetScaleMatrix_ = create(); 53534 53535 /** 53536 * @private 53537 * @type {Array<number>} 53538 */ 53539 this.tmpMat4_ = mat4_create(); 53540 53541 /** 53542 * @private 53543 * @type {Object<string, WebGLUniformLocation>} 53544 */ 53545 this.uniformLocations_ = {}; 53546 53547 /** 53548 * @private 53549 * @type {Object<string, number>} 53550 */ 53551 this.attribLocations_ = {}; 53552 53553 /** 53554 * Holds info about custom uniforms used in the post processing pass. 53555 * If the uniform is a texture, the WebGL Texture object will be stored here. 53556 * @type {Array<UniformInternalDescription>} 53557 * @private 53558 */ 53559 this.uniforms_ = []; 53560 if (options.uniforms) { 53561 this.setUniforms(options.uniforms); 53562 } 53563 53564 const gl = this.getGL(); 53565 53566 /** 53567 * An array of PostProcessingPass objects is kept in this variable, built from the steps provided in the 53568 * options. If no post process was given, a default one is used (so as not to have to make an exception to 53569 * the frame buffer logic). 53570 * @type {Array<WebGLPostProcessingPass>} 53571 * @private 53572 */ 53573 this.postProcessPasses_ = options.postProcesses 53574 ? options.postProcesses.map(function (options) { 53575 return new PostProcessingPass({ 53576 webGlContext: gl, 53577 scaleRatio: options.scaleRatio, 53578 vertexShader: options.vertexShader, 53579 fragmentShader: options.fragmentShader, 53580 uniforms: options.uniforms, 53581 }); 53582 }) 53583 : [new PostProcessingPass({webGlContext: gl})]; 53584 53585 /** 53586 * @type {string|null} 53587 * @private 53588 */ 53589 this.shaderCompileErrors_ = null; 53590 53591 /** 53592 * @type {number} 53593 * @private 53594 */ 53595 this.startTime_ = Date.now(); 53596 } 53597 53598 /** 53599 * @param {Object<string, UniformValue>} uniforms Uniform definitions. 53600 */ 53601 setUniforms(uniforms) { 53602 this.uniforms_ = []; 53603 for (const name in uniforms) { 53604 this.uniforms_.push({ 53605 name: name, 53606 value: uniforms[name], 53607 }); 53608 } 53609 this.uniformLocations_ = {}; 53610 } 53611 53612 /** 53613 * @param {string} canvasCacheKey The canvas cache key. 53614 * @return {boolean} The provided key matches the one this helper was constructed with. 53615 */ 53616 canvasCacheKeyMatches(canvasCacheKey) { 53617 return this.canvasCacheKey_ === getSharedCanvasCacheKey(canvasCacheKey); 53618 } 53619 53620 /** 53621 * Get a WebGL extension. If the extension is not supported, null is returned. 53622 * Extensions are cached after they are enabled for the first time. 53623 * @param {string} name The extension name. 53624 * @return {Object|null} The extension or null if not supported. 53625 */ 53626 getExtension(name) { 53627 if (name in this.extensionCache_) { 53628 return this.extensionCache_[name]; 53629 } 53630 const extension = this.gl_.getExtension(name); 53631 this.extensionCache_[name] = extension; 53632 return extension; 53633 } 53634 53635 /** 53636 * Just bind the buffer if it's in the cache. Otherwise create 53637 * the WebGL buffer, bind it, populate it, and add an entry to 53638 * the cache. 53639 * @param {import("./Buffer").default} buffer Buffer. 53640 */ 53641 bindBuffer(buffer) { 53642 const gl = this.getGL(); 53643 const bufferKey = getUid(buffer); 53644 let bufferCache = this.bufferCache_[bufferKey]; 53645 if (!bufferCache) { 53646 const webGlBuffer = gl.createBuffer(); 53647 bufferCache = { 53648 buffer: buffer, 53649 webGlBuffer: webGlBuffer, 53650 }; 53651 this.bufferCache_[bufferKey] = bufferCache; 53652 } 53653 gl.bindBuffer(buffer.getType(), bufferCache.webGlBuffer); 53654 } 53655 53656 /** 53657 * Update the data contained in the buffer array; this is required for the 53658 * new data to be rendered 53659 * @param {import("./Buffer").default} buffer Buffer. 53660 */ 53661 flushBufferData(buffer) { 53662 const gl = this.getGL(); 53663 this.bindBuffer(buffer); 53664 gl.bufferData(buffer.getType(), buffer.getArray(), buffer.getUsage()); 53665 } 53666 53667 /** 53668 * @param {import("./Buffer.js").default} buf Buffer. 53669 */ 53670 deleteBuffer(buf) { 53671 const gl = this.getGL(); 53672 const bufferKey = getUid(buf); 53673 const bufferCacheEntry = this.bufferCache_[bufferKey]; 53674 if (bufferCacheEntry && !gl.isContextLost()) { 53675 gl.deleteBuffer(bufferCacheEntry.webGlBuffer); 53676 } 53677 delete this.bufferCache_[bufferKey]; 53678 } 53679 53680 /** 53681 * Clean up. 53682 */ 53683 disposeInternal() { 53684 this.canvas_.removeEventListener( 53685 ContextEventType.LOST, 53686 this.boundHandleWebGLContextLost_ 53687 ); 53688 this.canvas_.removeEventListener( 53689 ContextEventType.RESTORED, 53690 this.boundHandleWebGLContextRestored_ 53691 ); 53692 53693 Helper_releaseCanvas(this.canvasCacheKey_); 53694 53695 delete this.gl_; 53696 delete this.canvas_; 53697 } 53698 53699 /** 53700 * Clear the buffer & set the viewport to draw. 53701 * Post process passes will be initialized here, the first one being bound as a render target for 53702 * subsequent draw calls. 53703 * @param {import("../Map.js").FrameState} frameState current frame state 53704 * @param {boolean} [disableAlphaBlend] If true, no alpha blending will happen. 53705 */ 53706 prepareDraw(frameState, disableAlphaBlend) { 53707 const gl = this.getGL(); 53708 const canvas = this.getCanvas(); 53709 const size = frameState.size; 53710 const pixelRatio = frameState.pixelRatio; 53711 53712 canvas.width = size[0] * pixelRatio; 53713 canvas.height = size[1] * pixelRatio; 53714 canvas.style.width = size[0] + 'px'; 53715 canvas.style.height = size[1] + 'px'; 53716 53717 // loop backwards in post processes list 53718 for (let i = this.postProcessPasses_.length - 1; i >= 0; i--) { 53719 this.postProcessPasses_[i].init(frameState); 53720 } 53721 53722 gl.bindTexture(gl.TEXTURE_2D, null); 53723 53724 gl.clearColor(0.0, 0.0, 0.0, 0.0); 53725 gl.clear(gl.COLOR_BUFFER_BIT); 53726 53727 gl.enable(gl.BLEND); 53728 gl.blendFunc(gl.ONE, disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA); 53729 } 53730 53731 /** 53732 * Clear the render target & bind it for future draw operations. 53733 * This is similar to `prepareDraw`, only post processes will not be applied. 53734 * Note: the whole viewport will be drawn to the render target, regardless of its size. 53735 * @param {import("../Map.js").FrameState} frameState current frame state 53736 * @param {import("./RenderTarget.js").default} renderTarget Render target to draw to 53737 * @param {boolean} [disableAlphaBlend] If true, no alpha blending will happen. 53738 */ 53739 prepareDrawToRenderTarget(frameState, renderTarget, disableAlphaBlend) { 53740 const gl = this.getGL(); 53741 const size = renderTarget.getSize(); 53742 53743 gl.bindFramebuffer(gl.FRAMEBUFFER, renderTarget.getFramebuffer()); 53744 gl.viewport(0, 0, size[0], size[1]); 53745 gl.bindTexture(gl.TEXTURE_2D, renderTarget.getTexture()); 53746 gl.clearColor(0.0, 0.0, 0.0, 0.0); 53747 gl.clear(gl.COLOR_BUFFER_BIT); 53748 gl.enable(gl.BLEND); 53749 gl.blendFunc(gl.ONE, disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA); 53750 } 53751 53752 /** 53753 * Execute a draw call based on the currently bound program, texture, buffers, attributes. 53754 * @param {number} start Start index. 53755 * @param {number} end End index. 53756 */ 53757 drawElements(start, end) { 53758 const gl = this.getGL(); 53759 this.getExtension('OES_element_index_uint'); 53760 53761 const elementType = gl.UNSIGNED_INT; 53762 const elementSize = 4; 53763 53764 const numItems = end - start; 53765 const offsetInBytes = start * elementSize; 53766 gl.drawElements(gl.TRIANGLES, numItems, elementType, offsetInBytes); 53767 } 53768 53769 /** 53770 * Apply the successive post process passes which will eventually render to the actual canvas. 53771 * @param {import("../Map.js").FrameState} frameState current frame state 53772 * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing. 53773 * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing. 53774 */ 53775 finalizeDraw(frameState, preCompose, postCompose) { 53776 // apply post processes using the next one as target 53777 for (let i = 0, ii = this.postProcessPasses_.length; i < ii; i++) { 53778 if (i === ii - 1) { 53779 this.postProcessPasses_[i].apply( 53780 frameState, 53781 null, 53782 preCompose, 53783 postCompose 53784 ); 53785 } else { 53786 this.postProcessPasses_[i].apply( 53787 frameState, 53788 this.postProcessPasses_[i + 1] 53789 ); 53790 } 53791 } 53792 } 53793 53794 /** 53795 * @return {HTMLCanvasElement} Canvas. 53796 */ 53797 getCanvas() { 53798 return this.canvas_; 53799 } 53800 53801 /** 53802 * Get the WebGL rendering context 53803 * @return {WebGLRenderingContext} The rendering context. 53804 */ 53805 getGL() { 53806 return this.gl_; 53807 } 53808 53809 /** 53810 * Sets the default matrix uniforms for a given frame state. This is called
53810internally in `prepareDraw`. 53811 * @param {import("../Map.js").FrameState} frameState Frame state. 53812 */ 53813 applyFrameState(frameState) { 53814 const size = frameState.size; 53815 const rotation = frameState.viewState.rotation; 53816 const pixelRatio = frameState.pixelRatio; 53817 53818 const offsetScaleMatrix = transform_reset(this.offsetScaleMatrix_); 53819 transform_scale(offsetScaleMatrix, 2 / size[0], 2 / size[1]); 53820 53821 const offsetRotateMatrix = transform_reset(this.offsetRotateMatrix_); 53822 if (rotation !== 0) { 53823 transform_rotate(offsetRotateMatrix, -rotation); 53824 } 53825 53826 this.setUniformMatrixValue( 53827 DefaultUniform.OFFSET_SCALE_MATRIX, 53828 fromTransform(this.tmpMat4_, offsetScaleMatrix) 53829 ); 53830 this.setUniformMatrixValue( 53831 DefaultUniform.OFFSET_ROTATION_MATRIX, 53832 fromTransform(this.tmpMat4_, offsetRotateMatrix) 53833 ); 53834 53835 this.setUniformFloatValue( 53836 DefaultUniform.TIME, 53837 (Date.now() - this.startTime_) * 0.001 53838 ); 53839 this.setUniformFloatValue(DefaultUniform.ZOOM, frameState.viewState.zoom); 53840 this.setUniformFloatValue( 53841 DefaultUniform.RESOLUTION, 53842 frameState.viewState.resolution 53843 ); 53844 this.setUniformFloatValue(DefaultUniform.PIXEL_RATIO, pixelRatio); 53845 this.setUniformFloatVec2(DefaultUniform.SIZE_PX, [size[0], size[1]]); 53846 } 53847 53848 /** 53849 * Sets the custom uniforms based on what was given in the constructor. This is called internally in `prepareDraw`. 53850 * @param {import("../Map.js").FrameState} frameState Frame state. 53851 */ 53852 applyUniforms(frameState) { 53853 const gl = this.getGL(); 53854 53855 let value; 53856 let textureSlot = 0; 53857 this.uniforms_.forEach( 53858 function (uniform) { 53859 value = 53860 typeof uniform.value === 'function' 53861 ? uniform.value(frameState) 53862 : uniform.value; 53863 53864 // apply value based on type 53865 if ( 53866 value instanceof HTMLCanvasElement || 53867 value instanceof HTMLImageElement || 53868 value instanceof ImageData 53869 ) { 53870 // create a texture & put data 53871 if (!uniform.texture) { 53872 uniform.prevValue = undefined; 53873 uniform.texture = gl.createTexture(); 53874 } 53875 gl.activeTexture(gl[`TEXTURE${textureSlot}`]); 53876 gl.bindTexture(gl.TEXTURE_2D, uniform.texture); 53877 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 53878 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 53879 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 53880 53881 const imageReady = 53882 !(value instanceof HTMLImageElement) || 53883 /** @type {HTMLImageElement} */ (value).complete; 53884 if (imageReady && uniform.prevValue !== value) { 53885 uniform.prevValue = value; 53886 gl.texImage2D( 53887 gl.TEXTURE_2D, 53888 0, 53889 gl.RGBA, 53890 gl.RGBA, 53891 gl.UNSIGNED_BYTE, 53892 value 53893 ); 53894 } 53895 53896 // fill texture slots by increasing index 53897 gl.uniform1i(this.getUniformLocation(uniform.name), textureSlot++); 53898 } else if (Array.isArray(value) && value.length === 6) { 53899 this.setUniformMatrixValue( 53900 uniform.name, 53901 fromTransform(this.tmpMat4_, value) 53902 ); 53903 } else if (Array.isArray(value) && value.length <= 4) { 53904 switch (value.length) { 53905 case 2: 53906 gl.uniform2f( 53907 this.getUniformLocation(uniform.name), 53908 value[0], 53909 value[1] 53910 ); 53911 return; 53912 case 3: 53913 gl.uniform3f( 53914 this.getUniformLocation(uniform.name), 53915 value[0], 53916 value[1], 53917 value[2] 53918 ); 53919 return; 53920 case 4: 53921 gl.uniform4f( 53922 this.getUniformLocation(uniform.name), 53923 value[0], 53924 value[1], 53925 value[2], 53926 value[3] 53927 ); 53928 return; 53929 default: 53930 return; 53931 } 53932 } else if (typeof value === 'number') { 53933 gl.uniform1f(this.getUniformLocation(uniform.name), value); 53934 } 53935 }.bind(this) 53936 ); 53937 } 53938 53939 /** 53940 * Set up a program for use. The program will be set as the current one. Then, the uniforms used 53941 * in the program will be set based on the current frame state and the helper configuration. 53942 * @param {WebGLProgram} program Program. 53943 * @param {import("../Map.js").FrameState} frameState Frame state. 53944 */ 53945 useProgram(program, frameState) { 53946 const gl = this.getGL(); 53947 gl.useProgram(program); 53948 this.currentProgram_ = program; 53949 this.uniformLocations_ = {}; 53950 this.attribLocations_ = {}; 53951 this.applyFrameState(frameState); 53952 this.applyUniforms(frameState); 53953 } 53954 53955 /** 53956 * Will attempt to compile a vertex or fragment shader based on source 53957 * On error, the shader will be returned but 53958 * `gl.getShaderParameter(shader, gl.COMPILE_STATUS)` will return `true` 53959 * Use `gl.getShaderInfoLog(shader)` to have details 53960 * @param {string} source Shader source 53961 * @param {ShaderType} type VERTEX_SHADER or FRAGMENT_SHADER 53962 * @return {WebGLShader} Shader object 53963 */ 53964 compileShader(source, type) { 53965 const gl = this.getGL(); 53966 const shader = gl.createShader(type); 53967 gl.shaderSource(shader, source); 53968 gl.compileShader(shader); 53969 return shader; 53970 } 53971 53972 /** 53973 * Create a program for a vertex and fragment shader. Throws if shader compilation fails. 53974 * @param {string} fragmentShaderSource Fragment shader source. 53975 * @param {string} vertexShaderSource Vertex shader source. 53976 * @return {WebGLProgram} Program 53977 */ 53978 getProgram(fragmentShaderSource, vertexShaderSource) { 53979 const gl = this.getGL(); 53980 53981 const fragmentShader = this.compileShader( 53982 fragmentShaderSource, 53983 gl.FRAGMENT_SHADER 53984 ); 53985 53986 const vertexShader = this.compileShader( 53987 vertexShaderSource, 53988 gl.VERTEX_SHADER 53989 ); 53990 53991 const program = gl.createProgram(); 53992 gl.attachShader(program, fragmentShader); 53993 gl.attachShader(program, vertexShader); 53994 gl.linkProgram(program); 53995 53996 if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { 53997 const message = `Fragment shader compliation failed: ${gl.getShaderInfoLog( 53998 fragmentShader 53999 )}`; 54000 throw new Error(message); 54001 } 54002 gl.deleteShader(fragmentShader); 54003 54004 if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { 54005 const message = `Vertex shader compilation failed: ${gl.getShaderInfoLog( 54006 vertexShader 54007 )}`; 54008 throw new Error(message); 54009 } 54010 gl.deleteShader(vertexShader); 54011 54012 if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { 54013 const message = `GL program linking failed: ${gl.getShaderInfoLog( 54014 vertexShader 54015 )}`; 54016 throw new Error(message); 54017 } 54018 54019 return program; 54020 } 54021 54022 /** 54023 * Will get the location from the shader or the cache 54024 * @param {string} name Uniform name 54025 * @return {WebGLUniformLocation} uniformLocation 54026 */ 54027 getUniformLocation(name) { 54028 if (this.uniformLocations_[name] === undefined) { 54029 this.uniformLocations_[name] = this.getGL().getUniformLocation( 54030 this.currentProgram_, 54031 name 54032 ); 54033 } 54034 return this.uniformLocations_[name]; 54035 } 54036 54037 /** 54038 * Will get the location from the shader or the cache 54039 * @param {string} name Attribute name 54040 * @return {number} attribLocation 54041 */ 54042 getAttributeLocation(name) { 54043 if (this.attribLocations_[name] === undefined) { 54044 this.attribLocations_[name] = this.getGL().getAttribLocation( 54045 this.currentProgram_, 54046 name 54047 ); 54048 } 54049 return this.attribLocations_[name]; 54050 } 54051 54052 /** 54053 * Modifies the given transform to apply the rotation/translation/scaling of the given frame state. 54054 * The resulting transform can be used to convert world space coordinates to view coordinates. 54055 * @param {import("../Map.js").FrameState} frameState Frame state. 54056 * @param {import("../transform").Transform} transform Transform to update. 54057 * @return {import("../transform").Transform} The updated transform object. 54058 */ 54059 makeProjectionTransform(frameState, transform) { 54060 const size = frameState.size; 54061 const rotation = frameState.viewState.rotation; 54062 const resolution = frameState.viewState.resolution; 54063 const center = frameState.viewState.center; 54064 54065 transform_reset(transform); 54066 compose( 54067 transform, 54068 0, 54069 0, 54070 2 / (resolution * size[0]), 54071 2 / (resolution * size[1]), 54072 -rotation, 54073 -center[0], 54074 -center[1] 54075 ); 54076 return transform; 54077 } 54078 54079 /** 54080 * Give a value for a standard float uniform 54081 * @param {string} uniform Uniform name 54082 * @param {number} value Value 54083 */ 54084 setUniformFloatValue(uniform, value) { 54085 this.getGL().uniform1f(this.getUniformLocation(uniform), value); 54086 } 54087 54088 /** 54089 * Give a value for a vec2 uniform 54090 * @param {string} uniform Uniform name 54091 * @param {Array<number>} value Array of length 4. 54092 */ 54093 setUniformFloatVec2(uniform, value) { 54094 this.getGL().uniform2fv(this.getUniformLocation(uniform), value); 54095 } 54096 54097 /** 54098 * Give a value for a vec4 uniform 54099 * @param {string} uniform Uniform name 54100 * @param {Array<number>} value Array of length 4. 54101 */ 54102 setUniformFloatVec4(uniform, value) { 54103 this.getGL().uniform4fv(this.getUniformLocation(uniform), value); 54104 } 54105 54106 /** 54107 * Give a value for a standard matrix4 uniform 54108 * @param {string} uniform Uniform name 54109 * @param {Array<number>} value Matrix value 54110 */ 54111 setUniformMatrixValue(uniform, value) { 54112 this.getGL().uniformMatrix4fv( 54113 this.getUniformLocation(uniform), 54114 false, 54115 value 54116 ); 54117 } 54118 54119 /** 54120 * Will set the currently bound buffer to an attribute of the shader program. Used by `#enableAttributes` 54121 * internally. 54122 * @param {string} attribName Attribute name 54123 * @param {number} size Number of components per attributes 54124 * @param {number} type UNSIGNED_INT, UNSIGNED_BYTE, UNSIGNED_SHORT or FLOAT 54125 * @param {number} stride Stride in bytes (0 means attribs are packed) 54126 * @param {number} offset Offset in bytes 54127 * @private 54128 */ 54129 enableAttributeArray_(attribName, size, type, stride, offset) { 54130 const location = this.getAttributeLocation(attribName); 54131 // the attribute has not been found in the shaders; do not enable it 54132 if (location < 0) { 54133 return; 54134 } 54135 this.getGL().enableVertexAttribArray(location); 54136 this.getGL().vertexAttribPointer( 54137 location, 54138 size, 54139 type, 54140 false,
54141 stride, 54142 offset 54143 ); 54144 } 54145 54146 /** 54147 * Will enable the following attributes to be read from the currently bound buffer, 54148 * i.e. tell the GPU where to read the different attributes in the buffer. An error in the 54149 * size/type/order of attributes will most likely break the rendering and throw a WebGL exception. 54150 * @param {Array<AttributeDescription>} attributes Ordered list of attributes to read from the buffer 54151 */ 54152 enableAttributes(attributes) { 54153 const stride = computeAttributesStride(attributes); 54154 let offset = 0; 54155 for (let i = 0; i < attributes.length; i++) { 54156 const attr = attributes[i]; 54157 this.enableAttributeArray_( 54158 attr.name, 54159 attr.size, 54160 attr.type || FLOAT, 54161 stride, 54162 offset 54163 ); 54164 offset += attr.size * getByteSizeFromType(attr.type); 54165 } 54166 } 54167 54168 /** 54169 * WebGL context was lost 54170 * @private 54171 */ 54172 handleWebGLContextLost() { 54173 clear(this.bufferCache_); 54174 this.currentProgram_ = null; 54175 } 54176 54177 /** 54178 * WebGL context was restored 54179 * @private 54180 */ 54181 handleWebGLContextRestored() {} 54182 54183 /** 54184 * Will create or reuse a given webgl texture and apply the given size. If no image data 54185 * specified, the texture will be empty, otherwise image data will be used and the `size` 54186 * parameter will be ignored. 54187 * Note: wrap parameters are set to clamp to edge, min filter is set to linear. 54188 * @param {Array<number>} size Expected size of the texture 54189 * @param {ImageData|HTMLImageElement|HTMLCanvasElement} [data] Image data/object to bind to the texture 54190 * @param {WebGLTexture} [texture] Existing texture to reuse 54191 * @return {WebGLTexture} The generated texture 54192 */ 54193 createTexture(size, data, texture) { 54194 const gl = this.getGL(); 54195 texture = texture || gl.createTexture(); 54196 54197 // set params & size 54198 const level = 0; 54199 const internalFormat = gl.RGBA; 54200 const border = 0; 54201 const format = gl.RGBA; 54202 const type = gl.UNSIGNED_BYTE; 54203 gl.bindTexture(gl.TEXTURE_2D, texture); 54204 if (data) { 54205 gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, format, type, data); 54206 } else { 54207 gl.texImage2D( 54208 gl.TEXTURE_2D, 54209 level, 54210 internalFormat, 54211 size[0], 54212 size[1], 54213 border, 54214 format, 54215 type, 54216 null 54217 ); 54218 } 54219 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 54220 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 54221 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 54222 54223 return texture; 54224 } 54225} 54226 54227/** 54228 * Compute a stride in bytes based on a list of attributes 54229 * @param {Array<AttributeDescription>} attributes Ordered list of attributes 54230 * @return {number} Stride, ie amount of values for each vertex in the vertex buffer 54231 */ 54232function computeAttributesStride(attributes) { 54233 let stride = 0; 54234 for (let i = 0; i < attributes.length; i++) { 54235 const attr = attributes[i]; 54236 stride += attr.size * getByteSizeFromType(attr.type); 54237 } 54238 return stride; 54239} 54240 54241/** 54242 * Computes the size in byte of an attribute type. 54243 * @param {AttributeType} type Attribute type 54244 * @return {number} The size in bytes 54245 */ 54246function getByteSizeFromType(type) { 54247 switch (type) { 54248 case AttributeType.UNSIGNED_BYTE: 54249 return Uint8Array.BYTES_PER_ELEMENT; 54250 case AttributeType.UNSIGNED_SHORT: 54251 return Uint16Array.BYTES_PER_ELEMENT; 54252 case AttributeType.UNSIGNED_INT: 54253 return Uint32Array.BYTES_PER_ELEMENT; 54254 case AttributeType.FLOAT: 54255 default: 54256 return Float32Array.BYTES_PER_ELEMENT; 54257 } 54258} 54259 54260/* harmony default export */ const Helper = (WebGLHelper); 54261 54262;// CONCATENATED MODULE: ./node_modules/ol/renderer/webgl/Layer.js 54263/** 54264 * @module ol/renderer/webgl/Layer 54265 */ 54266 54267 54268 54269 54270 54271 54272 54273/** 54274 * @typedef {Object} PostProcessesOptions 54275 * @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than 54276 * the main canvas that will then be sampled up (useful for saving resource on blur steps). 54277 * @property {string} [vertexShader] Vertex shader source 54278 * @property {string} [fragmentShader] Fragment shader source 54279 * @property {Object<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process step 54280 */ 54281 54282/** 54283 * @typedef {Object} Options 54284 * @property {Object<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process steps 54285 * @property {Array<PostProcessesOptions>} [postProcesses] Post-processes definitions 54286 */ 54287 54288/** 54289 * @classdesc 54290 * Base WebGL renderer class. 54291 * Holds all logic related to data manipulation & some common rendering logic 54292 * @template {import("../../layer/Layer.js").default} LayerType 54293 * @extends {LayerRenderer<LayerType>} 54294 */ 54295class WebGLLayerRenderer extends renderer_Layer { 54296 /** 54297 * @param {LayerType} layer Layer. 54298 * @param {Options} [options] Options. 54299 */ 54300 constructor(layer, options) { 54301 super(layer); 54302 54303 options = options || {}; 54304 54305 /** 54306 * The transform for viewport CSS pixels to rendered pixels. This transform is only 54307 * set before dispatching rendering events. 54308 * @private 54309 * @type {import("../../transform.js").Transform} 54310 */ 54311 this.inversePixelTransform_ = create(); 54312 54313 /** 54314 * @private 54315 * @type {CanvasRenderingContext2D} 54316 */ 54317 this.pixelContext_ = null; 54318 54319 /** 54320 * @private 54321 */ 54322 this.postProcesses_ = options.postProcesses; 54323 54324 /** 54325 * @private 54326 */ 54327 this.uniforms_ = options.uniforms; 54328 54329 /** 54330 * @type {WebGLHelper} 54331 * @protected 54332 */ 54333 this.helper; 54334 54335 layer.addChangeListener(layer_Property.MAP, this.removeHelper.bind(this)); 54336 54337 this.dispatchPreComposeEvent = this.dispatchPreComposeEvent.bind(this); 54338 this.dispatchPostComposeEvent = this.dispatchPostComposeEvent.bind(this); 54339 } 54340 54341 /** 54342 * @param {WebGLRenderingContext} context The WebGL rendering context. 54343 * @param {import("../../Map.js").FrameState} frameState Frame state. 54344 * @protected 54345 */ 54346 dispatchPreComposeEvent(context, frameState) { 54347 const layer = this.getLayer(); 54348 if (layer.hasListener(render_EventType.PRECOMPOSE)) { 54349 const event = new render_Event( 54350 render_EventType.PRECOMPOSE, 54351 undefined, 54352 frameState, 54353 context 54354 );
54355 layer.dispatchEvent(event); 54356 } 54357 } 54358 54359 /** 54360 * @param {WebGLRenderingContext} context The WebGL rendering context. 54361 * @param {import("../../Map.js").FrameState} frameState Frame state. 54362 * @protected 54363 */ 54364 dispatchPostComposeEvent(context, frameState) { 54365 const layer = this.getLayer(); 54366 if (layer.hasListener(render_EventType.POSTCOMPOSE)) { 54367 const event = new render_Event( 54368 render_EventType.POSTCOMPOSE, 54369 undefined, 54370 frameState, 54371 context 54372 ); 54373 layer.dispatchEvent(event); 54374 } 54375 } 54376 54377 /** 54378 * Reset options (only handles uniforms). 54379 * @param {Options} options Options. 54380 */ 54381 reset(options) { 54382 this.uniforms_ = options.uniforms; 54383 if (this.helper) { 54384 this.helper.setUniforms(this.uniforms_); 54385 } 54386 } 54387 54388 /** 54389 * @protected 54390 */ 54391 removeHelper() { 54392 if (this.helper) { 54393 this.helper.dispose(); 54394 delete this.helper; 54395 } 54396 } 54397 54398 /** 54399 * Determine whether renderFrame should be called. 54400 * @param {import("../../Map.js").FrameState} frameState Frame state. 54401 * @return {boolean} Layer is ready to be rendered. 54402 */ 54403 prepareFrame(frameState) { 54404 if (this.getLayer().getRenderSource()) { 54405 let incrementGroup = true; 54406 let groupNumber = -1; 54407 let className; 54408 for (let i = 0, ii = frameState.layerStatesArray.length; i < ii; i++) { 54409 const layer = frameState.layerStatesArray[i].layer; 54410 const renderer = layer.getRenderer(); 54411 if (!(renderer instanceof WebGLLayerRenderer)) { 54412 incrementGroup = true; 54413 continue; 54414 } 54415 const layerClassName = layer.getClassName(); 54416 if (incrementGroup || layerClassName !== className) { 54417 groupNumber += 1; 54418 incrementGroup = false; 54419 } 54420 className = layerClassName; 54421 if (renderer === this) { 54422 break; 54423 } 54424 } 54425 54426 const canvasCacheKey = 54427 'map/' + frameState.mapId + '/group/' + groupNumber; 54428 54429 if (!this.helper || !this.helper.canvasCacheKeyMatches(canvasCacheKey)) { 54430 this.removeHelper(); 54431 54432 this.helper = new Helper({ 54433 postProcesses: this.postProcesses_, 54434 uniforms: this.uniforms_, 54435 canvasCacheKey: canvasCacheKey, 54436 }); 54437 54438 if (className) { 54439 this.helper.getCanvas().className = className; 54440 } 54441 54442 this.afterHelperCreated(); 54443 } 54444 } 54445 54446 return this.prepareFrameInternal(frameState); 54447 } 54448 54449 /** 54450 * @protected 54451 */ 54452 afterHelperCreated() {} 54453 54454 /** 54455 * Determine whether renderFrame should be called. 54456 * @param {import("../../Map.js").FrameState} frameState Frame state. 54457 * @return {boolean} Layer is ready to be rendered. 54458 * @protected 54459 */ 54460 prepareFrameInternal(frameState) { 54461 return true; 54462 } 54463 54464 /** 54465 * Clean up. 54466 */ 54467 disposeInternal() { 54468 this.removeHelper(); 54469 super.disposeInternal(); 54470 } 54471 54472 /** 54473 * @param {import("../../render/EventType.js").default} type Event type. 54474 * @param {WebGLRenderingContext} context The rendering context. 54475 * @param {import("../../Map.js").FrameState} frameState Frame state. 54476 * @private 54477 */ 54478 dispatchRenderEvent_(type, context, frameState) { 54479 const layer = this.getLayer(); 54480 if (layer.hasListener(type)) { 54481 compose( 54482 this.inversePixelTransform_, 54483 0, 54484 0, 54485 frameState.pixelRatio, 54486 -frameState.pixelRatio, 54487 0, 54488 0, 54489 -frameState.size[1] 54490 ); 54491 54492 const event = new render_Event( 54493 type, 54494 this.inversePixelTransform_, 54495 frameState, 54496 context 54497 ); 54498 layer.dispatchEvent(event); 54499 } 54500 } 54501 54502 /** 54503 * @param {WebGLRenderingContext} context The rendering context. 54504 * @param {import("../../Map.js").FrameState} frameState Frame state. 54505 * @protected 54506 */ 54507 preRender(context, frameState) { 54508 this.dispatchRenderEvent_(render_EventType.PRERENDER, context, frameState); 54509 } 54510 54511 /** 54512 * @param {WebGLRenderingContext} context The rendering context. 54513 * @param {import("../../Map.js").FrameState} frameState Frame state. 54514 * @protected 54515 */ 54516 postRender(context, frameState) { 54517 this.dispatchRenderEvent_(render_EventType.POSTRENDER, context, frameState); 54518 } 54519} 54520 54521/* harmony default export */ const webgl_Layer = (WebGLLayerRenderer); 54522 54523;// CONCATENATED MODULE: ./node_modules/ol/renderer/webgl/TileLayer.js 54524/** 54525 * @module ol/renderer/webgl/TileLayer 54526 */ 54527 54528 54529 54530 54531 54532 54533 54534 54535 54536 54537 54538 54539 54540 54541 54542 54543 54544const Uniforms = { 54545 TILE_TEXTURE_ARRAY: 'u_tileTextures', 54546 TILE_TRANSFORM: 'u_tileTransform', 54547 TRANSITION_ALPHA: 'u_transitionAlpha', 54548 DEPTH: 'u_depth', 54549 TEXTURE_PIXEL_WIDTH: 'u_texturePixelWidth', 54550 TEXTURE_PIXEL_HEIGHT: 'u_texturePixelHeight', 54551 TEXTURE_RESOLUTION: 'u_textureResolution', // map units per texture pixel 54552 TEXTURE_ORIGIN_X: 'u_textureOriginX', // map x coordinate of left edge of texture 54553 TEXTURE_ORIGIN_Y: 'u_textureOriginY', // map y coordinate of top edge of texture 54554 RENDER_EXTENT: 'u_renderExtent', // intersection of layer, source, and view extent 54555 RESOLUTION: 'u_resolution', 54556 ZOOM: 'u_zoom', 54557}; 54558 54559const Attributes = { 54560 TEXTURE_COORD: 'a_textureCoord', 54561}; 54562 54563/** 54564 * @type {Array<import('../../webgl/Helper.js').AttributeDescription>} 54565 */ 54566const attributeDescriptions = [ 54567 { 54568 name: Attributes.TEXTURE_COORD, 54569 size: 2, 54570 type: AttributeType.FLOAT, 54571 }, 54572]; 54573 54574/** 54575 * @type {Object<string, boolean>} 54576 */ 54577const empty = {}; 54578 54579/** 54580 * Transform a zoom level into a depth value ranging from -1 to 1. 54581 * @param {number} z A zoom level. 54582 * @return {number} A depth value. 54583 */ 54584function depthForZ(z) { 54585 return 2 * (1 - 1 / (z + 1)) - 1; 54586} 54587 54588/** 54589 * Add a tile texture to the lookup. 54590 * @param {Object<number, Array<import("../../webgl/TileTexture.js").default>>} tileTexturesByZ Lookup of 54591 * tile textures by zoom level. 54592 * @param {import("../../webgl/TileTexture.js").default} tileTexture A tile texture. 54593 * @param {number} z The zoom level. 54594 */ 54595function addTileTextureToLookup(tileTexturesByZ, tileTexture, z) {
54596 if (!(z in tileTexturesByZ)) { 54597 tileTexturesByZ[z] = []; 54598 } 54599 tileTexturesByZ[z].push(tileTexture); 54600} 54601 54602/** 54603 * @param {import("../../Map.js").FrameState} frameState Frame state. 54604 * @param {import("../../extent.js").Extent} extent The frame extent. 54605 * @return {import("../../extent.js").Extent} Frame extent intersected with layer extents. 54606 */ 54607function getRenderExtent(frameState, extent) { 54608 const layerState = frameState.layerStatesArray[frameState.layerIndex]; 54609 if (layerState.extent) { 54610 extent = getIntersection( 54611 extent, 54612 proj_fromUserExtent(layerState.extent, frameState.viewState.projection) 54613 ); 54614 } 54615 const source = /** @type {import("../../source/Tile.js").default} */ ( 54616 layerState.layer.getRenderSource() 54617 ); 54618 if (!source.getWrapX()) { 54619 const gridExtent = source 54620 .getTileGridForProjection(frameState.viewState.projection) 54621 .getExtent(); 54622 if (gridExtent) { 54623 extent = getIntersection(extent, gridExtent); 54624 } 54625 } 54626 return extent; 54627} 54628 54629function getCacheKey(source, tileCoord) { 54630 return `${source.getKey()},${tilecoord_getKey(tileCoord)}`; 54631} 54632 54633/** 54634 * @typedef {Object} Options 54635 * @property {string} vertexShader Vertex shader source. 54636 * @property {string} fragmentShader Fragment shader source. 54637 * @property {Object<string, import("../../webgl/Helper").UniformValue>} [uniforms] Additional uniforms 54638 * made available to shaders. 54639 * @property {Array<import("../../webgl/PaletteTexture.js").default>} [paletteTextures] Palette textures. 54640 * @property {number} [cacheSize=512] The texture cache size. 54641 */ 54642 54643/** 54644 * @typedef {import("../../layer/WebGLTile.js").default} LayerType 54645 */ 54646 54647/** 54648 * @classdesc 54649 * WebGL renderer for tile layers. 54650 * @extends {WebGLLayerRenderer<LayerType>} 54651 * @api 54652 */ 54653class WebGLTileLayerRenderer extends webgl_Layer { 54654 /** 54655 * @param {LayerType} tileLayer Tile layer. 54656 * @param {Options} options Options. 54657 */ 54658 constructor(tileLayer, options) { 54659 super(tileLayer, { 54660 uniforms: options.uniforms, 54661 }); 54662 54663 /** 54664 * The last call to `renderFrame` was completed with all tiles loaded 54665 * @type {boolean} 54666 */ 54667 this.renderComplete = false; 54668 54669 /** 54670 * This transform converts texture coordinates to screen coordinates. 54671 * @type {import("../../transform.js").Transform} 54672 * @private 54673 */ 54674 this.tileTransform_ = create(); 54675 54676 /** 54677 * @type {Array<number>} 54678 * @private 54679 */ 54680 this.tempMat4_ = mat4_create(); 54681 54682 /** 54683 * @type {import("../../TileRange.js").default} 54684 * @private 54685 */ 54686 this.tempTileRange_ = new ol_TileRange(0, 0, 0, 0); 54687 54688 /** 54689 * @type {import("../../tilecoord.js").TileCoord} 54690 * @private 54691 */ 54692 this.tempTileCoord_ = tilecoord_createOrUpdate(0, 0, 0); 54693 54694 /** 54695 * @type {import("../../size.js").Size} 54696 * @private 54697 */ 54698 this.tempSize_ = [0, 0]; 54699 54700 /** 54701 * @type {WebGLProgram} 54702 * @private 54703 */ 54704 this.program_; 54705 54706 /** 54707 * @private 54708 */ 54709 this.vertexShader_ = options.vertexShader; 54710 54711 /** 54712 * @private 54713 */ 54714 this.fragmentShader_ = options.fragmentShader; 54715 54716 /** 54717 * Tiles are rendered as a quad with the following structure: 54718 * 54719 * [P3]---------[P2] 54720 * |` | 54721 * | ` B | 54722 * | ` | 54723 * | ` | 54724 * | A ` | 54725 * | ` | 54726 * [P0]---------[P1] 54727 * 54728 * Triangle A: P0, P1, P3 54729 * Triangle B: P1, P2, P3 54730 * 54731 * @private 54732 */ 54733 this.indices_ = new Buffer(ELEMENT_ARRAY_BUFFER, STATIC_DRAW); 54734 this.indices_.fromArray([0, 1, 3, 1, 2, 3]); 54735 54736 const cacheSize = options.cacheSize !== undefined ? options.cacheSize : 512; 54737 54738 /** 54739 * @type {import("../../structs/LRUCache.js").default<import("../../webgl/TileTexture.js").default>} 54740 * @private 54741 */ 54742 this.tileTextureCache_ = new structs_LRUCache(cacheSize); 54743 54744 /** 54745 * @type {Array<import("../../webgl/PaletteTexture.js").default>} 54746 * @private 54747 */ 54748 this.paletteTextures_ = options.paletteTextures || []; 54749 54750 /** 54751 * @private 54752 * @type {import("../../Map.js").FrameState|null} 54753 */ 54754 this.frameState_ = null; 54755 } 54756 54757 /** 54758 * @param {Options} options Options. 54759 */ 54760 reset(options) { 54761 super.reset({ 54762 uniforms: options.uniforms, 54763 }); 54764 this.vertexShader_ = options.vertexShader; 54765 this.fragmentShader_ = options.fragmentShader; 54766 this.paletteTextures_ = options.paletteTextures || []; 54767 54768 if (this.helper) { 54769 this.program_ = this.helper.getProgram( 54770 this.fragmentShader_, 54771 this.vertexShader_ 54772 ); 54773 } 54774 } 54775 54776 afterHelperCreated() { 54777 this.program_ = this.helper.getProgram( 54778 this.fragmentShader_, 54779 this.vertexShader_ 54780 ); 54781 54782 this.helper.flushBufferData(this.indices_); 54783 } 54784 54785 /** 54786 * @param {import("../../webgl/TileTexture").TileType} tile Tile. 54787 * @return {boolean} Tile is drawable. 54788 * @private 54789 */ 54790 isDrawableTile_(tile) { 54791 const tileLayer = this.getLayer(); 54792 const tileState = tile.getState(); 54793 const useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); 54794 return ( 54795 tileState == TileState.LOADED || 54796 tileState == TileState.EMPTY || 54797 (tileState == TileState.ERROR && !useInterimTilesOnError) 54798 ); 54799 } 54800 54801 /** 54802 * Determine whether renderFrame should be called. 54803 * @param {import("../../Map.js").FrameState} frameState Frame state. 54804 * @return {boolean} Layer is ready to be rendered. 54805 */ 54806 prepareFrameInternal(frameState) { 54807 const layer = this.getLayer(); 54808 const source = layer.getRenderSource(); 54809 if (!source) { 54810 return false;
54811 } 54812 54813 if (extent_isEmpty(getRenderExtent(frameState, frameState.extent))) { 54814 return false; 54815 } 54816 return source.getState() === 'ready'; 54817 } 54818 54819 /** 54820 * @param {import("../../Map.js").FrameState} frameState Frame state. 54821 * @param {import("../../extent.js").Extent} extent The extent to be rendered. 54822 * @param {number} initialZ The zoom level. 54823 * @param {Object<number, Array<TileTexture>>} tileTexturesByZ The zoom level. 54824 */ 54825 enqueueTiles(frameState, extent, initialZ, tileTexturesByZ) { 54826 const viewState = frameState.viewState; 54827 const tileLayer = this.getLayer(); 54828 const tileSource = tileLayer.getRenderSource(); 54829 const tileGrid = tileSource.getTileGridForProjection(viewState.projection); 54830 const gutter = tileSource.getGutterForProjection(viewState.projection); 54831 54832 const tileSourceKey = getUid(tileSource); 54833 if (!(tileSourceKey in frameState.wantedTiles)) { 54834 frameState.wantedTiles[tileSourceKey] = {}; 54835 } 54836 54837 const wantedTiles = frameState.wantedTiles[tileSourceKey]; 54838 54839 const tileTextureCache = this.tileTextureCache_; 54840 const minZ = Math.max( 54841 initialZ - tileLayer.getPreload(), 54842 tileGrid.getMinZoom(), 54843 tileLayer.getMinZoom() 54844 ); 54845 for (let z = initialZ; z >= minZ; --z) { 54846 const tileRange = tileGrid.getTileRangeForExtentAndZ( 54847 extent, 54848 z, 54849 this.tempTileRange_ 54850 ); 54851 54852 const tileResolution = tileGrid.getResolution(z); 54853 54854 for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { 54855 for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { 54856 const tileCoord = tilecoord_createOrUpdate(z, x, y, this.tempTileCoord_); 54857 const cacheKey = getCacheKey(tileSource, tileCoord); 54858 54859 /** @type {TileTexture} */ 54860 let tileTexture; 54861 54862 /** @type {import("../../webgl/TileTexture").TileType} */ 54863 let tile; 54864 54865 if (tileTextureCache.containsKey(cacheKey)) { 54866 tileTexture = tileTextureCache.get(cacheKey); 54867 tile = tileTexture.tile; 54868 } 54869 if (!tileTexture || tileTexture.tile.key !== tileSource.getKey()) { 54870 tile = tileSource.getTile( 54871 z, 54872 x, 54873 y, 54874 frameState.pixelRatio, 54875 viewState.projection 54876 ); 54877 if (!tileTexture) { 54878 tileTexture = new webgl_TileTexture({ 54879 tile: tile, 54880 grid: tileGrid, 54881 helper: this.helper, 54882 gutter: gutter, 54883 }); 54884 tileTextureCache.set(cacheKey, tileTexture); 54885 } else { 54886 if (this.isDrawableTile_(tile)) { 54887 tileTexture.setTile(tile); 54888 } else { 54889 const interimTile = 54890 /** @type {import("../../webgl/TileTexture").TileType} */ ( 54891 tile.getInterimTile() 54892 ); 54893 tileTexture.setTile(interimTile); 54894 } 54895 } 54896 } 54897 54898 addTileTextureToLookup(tileTexturesByZ, tileTexture, z); 54899 54900 const tileQueueKey = tile.getKey(); 54901 wantedTiles[tileQueueKey] = true; 54902 54903 if (tile.getState() === TileState.IDLE) { 54904 if (!frameState.tileQueue.isKeyQueued(tileQueueKey)) { 54905 frameState.tileQueue.enqueue([ 54906 tile, 54907 tileSourceKey, 54908 tileGrid.getTileCoordCenter(tileCoord), 54909 tileResolution, 54910 ]); 54911 } 54912 } 54913 } 54914 } 54915 } 54916 } 54917 54918 /** 54919 * Render the layer. 54920 * @param {import("../../Map.js").FrameState} frameState Frame state. 54921 * @return {HTMLElement} The rendered element. 54922 */ 54923 renderFrame(frameState) { 54924 this.frameState_ = frameState; 54925 this.renderComplete = true; 54926 const gl = this.helper.getGL(); 54927 this.preRender(gl, frameState); 54928 54929 const viewState = frameState.viewState; 54930 const tileLayer = this.getLayer(); 54931 const tileSource = tileLayer.getRenderSource(); 54932 const tileGrid = tileSource.getTileGridForProjection(viewState.projection); 54933 const gutter = tileSource.getGutterForProjection(viewState.projection); 54934 const extent = getRenderExtent(frameState, frameState.extent); 54935 const z = tileGrid.getZForResolution( 54936 viewState.resolution, 54937 tileSource.zDirection 54938 ); 54939 54940 /** 54941 * @type {Object<number, Array<import("../../webgl/TileTexture.js").default>>} 54942 */ 54943 const tileTexturesByZ = {}; 54944 54945 if (frameState.nextExtent) { 54946 const targetZ = tileGrid.getZForResolution( 54947 viewState.nextResolution, 54948 tileSource.zDirection 54949 ); 54950 const nextExtent = getRenderExtent(frameState, frameState.nextExtent);
54951 this.enqueueTiles(frameState, nextExtent, targetZ, tileTexturesByZ); 54952 } 54953 54954 this.enqueueTiles(frameState, extent, z, tileTexturesByZ); 54955 54956 /** 54957 * A lookup of alpha values for tiles at the target rendering resolution 54958 * for tiles that are in transition. If a tile coord key is absent from 54959 * this lookup, the tile should be rendered at alpha 1. 54960 * @type {Object<string, number>} 54961 */ 54962 const alphaLookup = {}; 54963 54964 const uid = getUid(this); 54965 const time = frameState.time; 54966 let blend = false; 54967 54968 // look for cached tiles to use if a target tile is not ready 54969 const tileTextures = tileTexturesByZ[z]; 54970 for (let i = 0, ii = tileTextures.length; i < ii; ++i) { 54971 const tileTexture = tileTextures[i]; 54972 const tile = tileTexture.tile; 54973 const tileCoord = tile.tileCoord; 54974 54975 if (tileTexture.loaded) { 54976 const alpha = tile.getAlpha(uid, time); 54977 if (alpha === 1) { 54978 // no need to look for alt tiles 54979 tile.endTransition(uid); 54980 continue; 54981 } 54982 blend = true; 54983 const tileCoordKey = tilecoord_getKey(tileCoord); 54984 alphaLookup[tileCoordKey] = alpha; 54985 } 54986 this.renderComplete = false; 54987 54988 // first look for child tiles (at z + 1) 54989 const coveredByChildren = this.findAltTiles_( 54990 tileGrid, 54991 tileCoord, 54992 z + 1, 54993 tileTexturesByZ 54994 ); 54995 54996 if (coveredByChildren) { 54997 continue; 54998 } 54999 55000 // next look for parent tiles 55001 const minZoom = tileGrid.getMinZoom(); 55002 for (let parentZ = z - 1; parentZ >= minZoom; --parentZ) { 55003 const coveredByParent = this.findAltTiles_( 55004 tileGrid, 55005 tileCoord, 55006 parentZ, 55007 tileTexturesByZ 55008 ); 55009 55010 if (coveredByParent) { 55011 break; 55012 } 55013 } 55014 } 55015 55016 this.helper.useProgram(this.program_, frameState); 55017 this.helper.prepareDraw(frameState, !blend); 55018 55019 const zs = Object.keys(tileTexturesByZ) 55020 .map(Number) 55021 .sort(numberSafeCompareFunction); 55022 55023 const centerX = viewState.center[0]; 55024 const centerY = viewState.center[1]; 55025 55026 for (let j = 0, jj = zs.length; j < jj; ++j) { 55027 const tileZ = zs[j]; 55028 const tileResolution = tileGrid.getResolution(tileZ); 55029 const tileSize = toSize(tileGrid.getTileSize(tileZ), this.tempSize_); 55030 const tileOrigin = tileGrid.getOrigin(tileZ); 55031 55032 const tileWidthWithGutter = tileSize[0] + 2 * gutter; 55033 const tileHeightWithGutter = tileSize[1] + 2 * gutter; 55034 const aspectRatio = tileWidthWithGutter / tileHeightWithGutter; 55035 55036 const centerI = 55037 (centerX - tileOrigin[0]) / (tileSize[0] * tileResolution); 55038 const centerJ = 55039 (tileOrigin[1] - centerY) / (tileSize[1] * tileResolution); 55040 55041 const tileScale = viewState.resolution / tileResolution; 55042 55043 const depth = depthForZ(tileZ); 55044 const tileTextures = tileTexturesByZ[tileZ]; 55045 for (let i = 0, ii = tileTextures.length; i < ii; ++i) { 55046 const tileTexture = tileTextures[i]; 55047 if (!tileTexture.loaded) { 55048 continue; 55049 } 55050 const tile = tileTexture.tile; 55051 const tileCoord = tile.tileCoord; 55052 const tileCoordKey = tilecoord_getKey(tileCoord); 55053 55054 const tileCenterI = tileCoord[1]; 55055 const tileCenterJ = tileCoord[2]; 55056 55057 transform_reset(this.tileTransform_); 55058 transform_scale( 55059 this.tileTransform_, 55060 2 / ((frameState.size[0] * tileScale) / tileWidthWithGutter), 55061 -2 / ((frameState.size[1] * tileScale) / tileWidthWithGutter) 55062 ); 55063 transform_rotate(this.tileTransform_, viewState.rotation); 55064 transform_scale(this.tileTransform_, 1, 1 / aspectRatio); 55065 translate( 55066 this.tileTransform_, 55067 (tileSize[0] * (tileCenterI - centerI) - gutter) / 55068 tileWidthWithGutter, 55069 (tileSize[1] * (tileCenterJ - centerJ) - gutter) / 55070 tileHeightWithGutter 55071 ); 55072 55073 this.helper.setUniformMatrixValue( 55074 Uniforms.TILE_TRANSFORM, 55075 fromTransform(this.tempMat4_, this.tileTransform_) 55076 ); 55077 55078 this.helper.bindBuffer(tileTexture.coords); 55079 this.helper.bindBuffer(this.indices_); 55080 this.helper.enableAttributes(attributeDescriptions); 55081 55082 let textureSlot = 0; 55083 while (textureSlot < tileTexture.textures.length) { 55084 const textureProperty = 'TEXTURE' + textureSlot; 55085 const uniformName = `${Uniforms.TILE_TEXTURE_ARRAY}[${textureSlot}]`; 55086 gl.activeTexture(gl[textureProperty]); 55087 gl.bindTexture(gl.TEXTURE_2D, tileTexture.textures[textureSlot]); 55088 gl.uniform1i( 55089 this.helper.getUniformLocation(uniformName), 55090 textureSlot 55091 ); 55092 ++textureSlot; 55093 } 55094 55095 for ( 55096 let paletteIndex = 0; 55097 paletteIndex < this.paletteTextures_.length; 55098 ++paletteIndex 55099 ) { 55100 const paletteTexture = this.paletteTextures_[paletteIndex]; 55101 gl.activeTexture(gl['TEXTURE' + textureSlot]); 55102 const texture = paletteTexture.getTexture(gl); 55103 gl.bindTexture(gl.TEXTURE_2D, texture); 55104 gl.uniform1i( 55105 this.helper.getUniformLocation(paletteTexture.name), 55106 textureSlot 55107 ); 55108 ++textureSlot; 55109 } 55110
55111 const alpha = 55112 tileCoordKey in alphaLookup ? alphaLookup[tileCoordKey] : 1; 55113 55114 if (alpha < 1) { 55115 frameState.animate = true; 55116 } 55117 55118 this.helper.setUniformFloatValue(Uniforms.TRANSITION_ALPHA, alpha); 55119 this.helper.setUniformFloatValue(Uniforms.DEPTH, depth); 55120 this.helper.setUniformFloatValue( 55121 Uniforms.TEXTURE_PIXEL_WIDTH, 55122 tileWidthWithGutter 55123 ); 55124 this.helper.setUniformFloatValue( 55125 Uniforms.TEXTURE_PIXEL_HEIGHT, 55126 tileHeightWithGutter 55127 ); 55128 this.helper.setUniformFloatValue( 55129 Uniforms.TEXTURE_RESOLUTION, 55130 tileResolution 55131 ); 55132 this.helper.setUniformFloatValue( 55133 Uniforms.TEXTURE_ORIGIN_X, 55134 tileOrigin[0] + 55135 tileCenterI * tileSize[0] * tileResolution - 55136 gutter * tileResolution 55137 ); 55138 this.helper.setUniformFloatValue( 55139 Uniforms.TEXTURE_ORIGIN_Y, 55140 tileOrigin[1] - 55141 tileCenterJ * tileSize[1] * tileResolution + 55142 gutter * tileResolution 55143 ); 55144 let gutterExtent = extent; 55145 if (gutter > 0) { 55146 gutterExtent = tileGrid.getTileCoordExtent(tileCoord); 55147 getIntersection(gutterExtent, extent, gutterExtent); 55148 } 55149 this.helper.setUniformFloatVec4(Uniforms.RENDER_EXTENT, gutterExtent); 55150 this.helper.setUniformFloatValue( 55151 Uniforms.RESOLUTION, 55152 viewState.resolution 55153 ); 55154 this.helper.setUniformFloatValue(Uniforms.ZOOM, viewState.zoom); 55155 55156 this.helper.drawElements(0, this.indices_.getSize()); 55157 } 55158 } 55159 55160 this.helper.finalizeDraw( 55161 frameState, 55162 this.dispatchPreComposeEvent, 55163 this.dispatchPostComposeEvent 55164 ); 55165 55166 const canvas = this.helper.getCanvas(); 55167 55168 const tileTextureCache = this.tileTextureCache_; 55169 while (tileTextureCache.canExpireCache()) { 55170 const tileTexture = tileTextureCache.pop(); 55171 tileTexture.dispose(); 55172 } 55173 55174 // TODO: let the renderers manage their own cache instead of managing the source cache 55175 /** 55176 * Here we unconditionally expire the source cache since the renderer maintains 55177 * its own cache. 55178 * @param {import("../../Map.js").default} map Map. 55179 * @param {import("../../Map.js").FrameState} frameState Frame state. 55180 */ 55181 const postRenderFunction = function (map, frameState) { 55182 tileSource.updateCacheSize(0.1, frameState.viewState.projection); 55183 tileSource.expireCache(frameState.viewState.projection, empty); 55184 }; 55185 55186 frameState.postRenderFunctions.push(postRenderFunction); 55187 55188 this.postRender(gl, frameState); 55189 return canvas; 55190 } 55191 55192 /** 55193 * @param {import("../../pixel.js").Pixel} pixel Pixel. 55194 * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView} Data at the pixel location. 55195 */ 55196 getData(pixel) { 55197 const gl = this.helper.getGL(); 55198 if (!gl) { 55199 return null; 55200 } 55201 55202 const frameState = this.frameState_; 55203 if (!frameState) { 55204 return null; 55205 } 55206 55207 const layer = this.getLayer(); 55208 const coordinate = apply( 55209 frameState.pixelToCoordinateTransform, 55210 pixel.slice() 55211 ); 55212 55213 const viewState = frameState.viewState; 55214 const layerExtent = layer.getExtent(); 55215 if (layerExtent) { 55216 if ( 55217 !containsCoordinate( 55218 proj_fromUserExtent(layerExtent, viewState.projection), 55219 coordinate 55220 ) 55221 ) { 55222 return null; 55223 } 55224 } 55225 55226 // determine last source suitable for rendering at coordinate 55227 const sources = layer.getSources( 55228 boundingExtent([coordinate]), 55229 viewState.resolution 55230 ); 55231 let i, source, tileGrid; 55232 for (i = sources.length - 1; i >= 0; --i) { 55233 source = sources[i]; 55234 if (source.getState() === 'ready') { 55235 tileGrid = source.getTileGridForProjection(viewState.projection); 55236 if (source.getWrapX()) { 55237 break; 55238 } 55239 const gridExtent = tileGrid.getExtent(); 55240 if (!gridExtent || containsCoordinate(gridExtent, coordinate)) { 55241 break; 55242 } 55243 } 55244 } 55245 if (i < 0) { 55246 return null; 55247 } 55248 55249 const tileTextureCache = this.tileTextureCache_; 55250 for ( 55251 let z = tileGrid.getZForResolution(viewState.resolution); 55252 z >= tileGrid.getMinZoom(); 55253 --z 55254 ) { 55255 const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z); 55256 const cacheKey = getCacheKey(source, tileCoord); 55257 if (!tileTextureCache.containsKey(cacheKey)) { 55258 continue; 55259 } 55260 const tileTexture = tileTextureCache.get(cacheKey); 55261 if (!tileTexture.loaded) { 55262 continue; 55263 } 55264 const tileOrigin = tileGrid.getOrigin(z); 55265 const tileSize = toSize(tileGrid.getTileSize(z)); 55266 const tileResolution = tileGrid.getResolution(z); 55267 55268 const col = 55269 (coordinate[0] - tileOrigin[0]) / tileResolution - 55270 tileCoord[1] * tileSize[0]; 55271
55272 const row = 55273 (tileOrigin[1] - coordinate[1]) / tileResolution - 55274 tileCoord[2] * tileSize[1]; 55275 55276 return tileTexture.getPixelData(col, row); 55277 } 55278 return null; 55279 } 55280 55281 /** 55282 * Look for tiles covering the provided tile coordinate at an alternate 55283 * zoom level. Loaded tiles will be added to the provided tile texture lookup. 55284 * @param {import("../../tilegrid/TileGrid.js").default} tileGrid The tile grid. 55285 * @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate. 55286 * @param {number} altZ The alternate zoom level. 55287 * @param {Object<number, Array<import("../../webgl/TileTexture.js").default>>} tileTexturesByZ Lookup of 55288 * tile textures by zoom level. 55289 * @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level. 55290 * @private 55291 */ 55292 findAltTiles_(tileGrid, tileCoord, altZ, tileTexturesByZ) { 55293 const tileRange = tileGrid.getTileRangeForTileCoordAndZ( 55294 tileCoord, 55295 altZ, 55296 this.tempTileRange_ 55297 ); 55298 55299 if (!tileRange) { 55300 return false; 55301 } 55302 55303 let covered = true; 55304 const tileTextureCache = this.tileTextureCache_; 55305 const source = this.getLayer().getRenderSource(); 55306 for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { 55307 for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { 55308 const cacheKey = getCacheKey(source, [altZ, x, y]); 55309 let loaded = false; 55310 if (tileTextureCache.containsKey(cacheKey)) { 55311 const tileTexture = tileTextureCache.get(cacheKey); 55312 if (tileTexture.loaded) { 55313 addTileTextureToLookup(tileTexturesByZ, tileTexture, altZ); 55314 loaded = true; 55315 } 55316 } 55317 if (!loaded) { 55318 covered = false; 55319 } 55320 } 55321 } 55322 return covered; 55323 } 55324 55325 removeHelper() { 55326 if (this.helper) { 55327 const tileTextureCache = this.tileTextureCache_; 55328 tileTextureCache.forEach((tileTexture) => tileTexture.dispose()); 55329 tileTextureCache.clear(); 55330 } 55331 55332 super.removeHelper(); 55333 } 55334 55335 /** 55336 * Clean up. 55337 */ 55338 disposeInternal() { 55339 const helper = this.helper; 55340 if (helper) { 55341 const gl = helper.getGL(); 55342 gl.deleteProgram(this.program_); 55343 delete this.program_; 55344 55345 helper.deleteBuffer(this.indices_); 55346 } 55347 55348 super.disposeInternal(); 55349 55350 delete this.indices_; 55351 delete this.tileTextureCache_; 55352 delete this.frameState_; 55353 } 55354} 55355 55356/* harmony default export */ const webgl_TileLayer = (WebGLTileLayerRenderer); 55357 55358;// CONCATENATED MODULE: ./node_modules/ol/webgl/PaletteTexture.js 55359/** 55360 * @module ol/webgl/PaletteTexture 55361 */ 55362 55363class PaletteTexture { 55364 /** 55365 * @param {string} name The name of the texture. 55366 * @param {Uint8Array} data The texture data. 55367 */ 55368 constructor(name, data) { 55369 this.name = name; 55370 this.data = data; 55371 55372 /** 55373 * @type {WebGLTexture} 55374 * @private 55375 */ 55376 this.texture_ = null; 55377 } 55378 55379 /** 55380 * @param {WebGLRenderingContext} gl Rendering context. 55381 * @return {WebGLTexture} The texture. 55382 */ 55383 getTexture(gl) { 55384 if (!this.texture_) { 55385 const texture = gl.createTexture(); 55386 gl.bindTexture(gl.TEXTURE_2D, texture); 55387 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 55388 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 55389 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 55390 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 55391 gl.texImage2D( 55392 gl.TEXTURE_2D, 55393 0, 55394 gl.RGBA, 55395 this.data.length / 4, 55396 1, 55397 0, 55398 gl.RGBA, 55399 gl.UNSIGNED_BYTE, 55400 this.data 55401 ); 55402 this.texture_ = texture; 55403 } 55404 return this.texture_; 55405 } 55406} 55407 55408/* harmony default export */ const webgl_PaletteTexture = (PaletteTexture); 55409 55410;// CONCATENATED MODULE: ./node_modules/ol/style/expressions.js 55411/** 55412 * Operators and utilities used for style expressions 55413 * @module ol/style/expressions 55414 */ 55415 55416 55417 55418 55419 55420/** 55421 * Base type used for literal style parameters; can be a number literal or the output of an operator, 55422 * which in turns takes {@link import("./expressions.js").ExpressionValue} arguments. 55423 * 55424 * The following operators can be used: 55425 * 55426 * * Reading operators: 55427 * * `['band', bandIndex, xOffset, yOffset]` For tile layers only. Fetches pixel values from band 55428 * `bandIndex` of the source's data. The first `bandIndex` of the source data is `1`. Fetched values 55429 * are in the 0..1 range. {@link import("../source/TileImage.js").default} sources have 4 bands: red, 55430 * green, blue and alpha. {@link import("../source/DataTile.js").default} sources can have any number 55431 * of bands, depending on the underlying data source and 55432 * {@link import("../source/GeoTIFF.js").Options configuration}. `xOffset` and `yOffset` are optional 55433 * and allow specifying pixel offsets for x and y. This is used for sampling data from neighboring pixels. 55434 * * `['get', 'attributeName']` fetches a feature attribute (it will be prefixed by `a_` in the shader) 55435 * Note: those will be taken from the attributes provided to the renderer 55436 * * `['resolution']` returns the current resolution 55437 * * `['time']` returns the time in seconds since the creation of the layer 55438 * * `['var', 'varName']` fetches a value from the style variables, or 0 if undefined 55439 * * `['zoom']` returns the current zoom level 55440 * 55441 * * Math operators: 55442 * * `['*', value1, value2]` multiplies `value1` by `value2` 55443 * * `['/', value1, value2]` divides `value1` by `value2` 55444 * * `['+', value1, value2]` adds `value1` and `value2` 55445 * * `['-', value1, value2]` subtracts `value2` from `value1` 55446 * * `['clamp', value, low, high]` clamps `value` between `low` and `high` 55447 * * `['%', value1, value2]` returns the result of `value1 % value2` (modulo) 55448 * * `['^', value1, value2]` returns the value of `value1` raised to the `value2` power 55449 * * `['abs', value1]` returns the absolute value of `value1` 55450 * * `['floor', value1]` returns the nearest integer less than or equal to `value1` 55451 * * `['round', value1]` returns the nearest integer to `value1` 55452 * * `['ceil', value1]` returns the nearest integer greater than or equal to `value1` 55453 * * `['sin', value1]` returns the sine of `value1` 55454 * * `['cos', value1]` returns the cosine of `value1` 55455 * * `['atan', value1, value2]` returns `atan2(value1, value2)`. If `value2` is not provided, returns `atan(value1)` 55456 * 55457 * * Transform operators: 55458 * * `['case', condition1, output1, ...conditionN, outputN, fallback]` selects the first output whose corresponding 55459 * condition evaluates to `true`. If no match is found, returns the `fallback` value. 55460 * All conditions should be `boolean`, output and fallback can be any kind. 55461 * * `['match', input, match1, output1, ...matchN, outputN, fallback]` compares the `input` value against all 55462 * provided `matchX` values, returning the output associated with the first valid match. If no match is found, 55463 * returns the `fallback` value. 55464 * `input` and `matchX` values must all be of the same type, and can be `number` or `str
55464ing`. `outputX` and 55465 * `fallback` values must be of the same type, and can be of any kind. 55466 * * `['interpolate', interpolation, input, stop1, output1, ...stopN, outputN]` returns a value by interpolating between 55467 * pairs of inputs and outputs; `interpolation` can either be `['linear']` or `['exponential', base]` where `base` is 55468 * the rate of increase from stop A to stop B (i.e. power to which the interpolation ratio is raised); a value 55469 * of 1 is equivalent to `['linear']`. 55470 * `input` and `stopX` values must all be of type `number`. `outputX` values can be `number` or `color` values. 55471 * Note: `input` will be clamped between `stop1` and `stopN`, meaning that all output values will be comprised 55472 * between `output1` and `outputN`. 55473 * 55474 * * Logical operators: 55475 * * `['<', value1, value2]` returns `true` if `value1` is strictly lower than `value2`, or `false` otherwise. 55476 * * `['<=', value1, value2]` returns `true` if `value1` is lower than or equals `value2`, or `false` otherwise. 55477 * * `['>', value1, value2]` returns `true` if `value1` is strictly greater than `value2`, or `false` otherwise. 55478 * * `['>=', value1, value2]` returns `true` if `value1` is greater than or equals `value2`, or `false` otherwise. 55479 * * `['==', value1, value2]` returns `true` if `value1` equals `value2`, or `false` otherwise. 55480 * * `['!=', value1, value2]` returns `true` if `value1` does not equal `value2`, or `false` otherwise. 55481 * * `['!', value1]` returns `false` if `value1` is `true` or greater than `0`, or `true` otherwise. 55482 * * `['all', value1, value2, ...]` returns `true` if all the inputs are `true`, `false` otherwise. 55483 * * `['any', value1, value2, ...]` returns `true` if any of the inputs are `true`, `false` otherwise. 55484 * * `['between', value1, value2, value3]` returns `true` if `value1` is contained between `value2` and `value3` 55485 * (inclusively), or `false` otherwise. 55486 * 55487 * * Conversion operators: 55488 * * `['array', value1, ...valueN]` creates a numerical array from `number` values; please note that the amount of 55489 * values can currently only be 2, 3 or 4. 55490 * * `['color', red, green, blue, alpha]` creates a `color` value from `number` values; the `alpha` parameter is 55491 * optional; if not specified, it will be set to 1. 55492 * Note: `red`, `green` and `blue` components must be values between 0 and 255; `alpha` between 0 and 1. 55493 * * `['palette', index, colors]` picks a `color` value from an array of colors using the given index; the `index` 55494 * expression must evaluate to a number; the items in the `colors` array must be strings with hex colors 55495 * (e.g. `'#86A136'`), colors using the rgba[a] functional notation (e.g. `'rgb(134, 161, 54)'` or `'rgba(134, 161, 54, 1)'`), 55496 * named colors (e.g. `'red'`), or array literals with 3 ([r, g, b]) or 4 ([r, g, b, a]) values (with r, g, and b 55497 * in the 0-255 range and a in the 0-1 range). 55498 * 55499 * Values can either be literals or another operator, as they will be evaluated recursively. 55500 * Literal values can be of the following types: 55501 * * `boolean` 55502 * * `number` 55503 * * `string` 55504 * * {@link module:ol/color~Color} 55505 * 55506 * @typedef {Array<*>|import("../color.js").Color|string|number|boolean} ExpressionValue 55507 * @api 55508 */ 55509 55510/** 55511 * Possible inferred types from a given value or expression. 55512 * Note: these are binary flags. 55513 * @enum {number} 55514 */ 55515const ValueTypes = { 55516 NUMBER: 0b00001, 55517 STRING: 0b00010, 55518 COLOR: 0b00100, 55519 BOOLEAN: 0b01000, 55520 NUMBER_ARRAY: 0b10000, 55521 ANY: 0b11111, 55522 NONE: 0, 55523}; 55524 55525/** 55526 * An operator declaration must contain two methods: `getReturnType` which returns a type based on 55527 * the operator arguments, and `toGlsl` which returns a GLSL-compatible string. 55528 * Note: both methods can process arguments recursively. 55529 * @typedef {Object} Operator 55530 * @property {function(Array<ExpressionValue>): ValueTypes|number} getReturnType Returns one or several types 55531 * @property {function(ParsingContext, Array<ExpressionValue>, ValueTypes=): string} toGlsl Returns a GLSL-compatible string 55532 * Note: takes in an optional type hint as 3rd parameter 55533 */ 55534 55535/** 55536 * Operator declarations 55537 * @type {Object<string, Operator>} 55538 */ 55539const Operators = {}; 55540 55541/** 55542 * Returns the possible types for a given value (each type being a binary flag)
55543 * To test a value use e.g. `getValueType(v) & ValueTypes.BOOLEAN` 55544 * @param {ExpressionValue} value Value 55545 * @return {ValueTypes|number} Type or types inferred from the value 55546 */ 55547function getValueType(value) { 55548 if (typeof value === 'number') { 55549 return ValueTypes.NUMBER; 55550 } 55551 if (typeof value === 'boolean') { 55552 return ValueTypes.BOOLEAN; 55553 } 55554 if (typeof value === 'string') { 55555 if (isStringColor(value)) { 55556 return ValueTypes.COLOR | ValueTypes.STRING; 55557 } 55558 return ValueTypes.STRING; 55559 } 55560 if (!Array.isArray(value)) { 55561 throw new Error(`Unhandled value type: ${JSON.stringify(value)}`); 55562 } 55563 const valueArr = /** @type {Array<*>} */ (value); 55564 const onlyNumbers = valueArr.every(function (v) { 55565 return typeof v === 'number'; 55566 }); 55567 if (onlyNumbers) { 55568 if (valueArr.length === 3 || valueArr.length === 4) { 55569 return ValueTypes.COLOR | ValueTypes.NUMBER_ARRAY; 55570 } 55571 return ValueTypes.NUMBER_ARRAY; 55572 } 55573 if (typeof valueArr[0] !== 'string') { 55574 throw new Error( 55575 `Expected an expression operator but received: ${JSON.stringify( 55576 valueArr 55577 )}` 55578 ); 55579 } 55580 const operator = Operators[valueArr[0]]; 55581 if (operator === undefined) { 55582 throw new Error( 55583 `Unrecognized expression operator: ${JSON.stringify(valueArr)}` 55584 ); 55585 } 55586 return operator.getReturnType(valueArr.slice(1)); 55587} 55588 55589/** 55590 * Checks if only one value type is enabled in the input number. 55591 * @param {ValueTypes|number} valueType Number containing value type binary flags 55592 * @return {boolean} True if only one type flag is enabled, false if zero or multiple 55593 */ 55594function isTypeUnique(valueType) { 55595 return Math.log2(valueType) % 1 === 0; 55596} 55597 55598/** 55599 * Context available during the parsing of an expression. 55600 * @typedef {Object} ParsingContext 55601 * @property {boolean} [inFragmentShader] If false, means the expression output should be made for a vertex shader 55602 * @property {Array<string>} variables List of variables used in the expression; contains **unprefixed names** 55603 * @property {Array<string>} attributes List of attributes used in the expression; contains **unprefixed names** 55604 * @property {Object<string, number>} stringLiteralsMap This object maps all encountered string values to a number 55605 * @property {Object<string, string>} functions Lookup of functions used by the style. 55606 * @property {number} [bandCount] Number of bands per pixel. 55607 * @property {Array<PaletteTexture>} [paletteTextures] List of palettes used by the style. 55608 */ 55609 55610/** 55611 * Will return the number as a float with a dot separator, which is required by GLSL. 55612 * @param {number} v Numerical value. 55613 * @return {string} The value as string. 55614 */ 55615function numberToGlsl(v) { 55616 const s = v.toString(); 55617 return s.includes('.') ? s : s + '.0'; 55618} 55619 55620/** 55621 * Will return the number array as a float with a dot separator, concatenated with ', '. 55622 * @param {Array<number>} array Numerical values array. 55623 * @return {string} The array as a vector, e. g.: `vec3(1.0, 2.0, 3.0)`. 55624 */ 55625function arrayToGlsl(array) { 55626 if (array.length < 2 || array.length > 4) { 55627 throw new Error( 55628 '`formatArray` can only output `vec2`, `vec3` or `vec4` arrays.' 55629 ); 55630 } 55631 return `vec${array.length}(${array.map(numberToGlsl).join(', ')})`; 55632} 55633 55634/** 55635 * Will normalize and converts to string a `vec4` color array compatible with GLSL. 55636 * @param {string|import("../color.js").Color} color Color either in string format or [r, g, b, a] array format, 55637 * with RGB components in the 0..255 range and the alpha component in the 0..1 range. 55638 * Note that the final array will always have 4 components. 55639 * @return {string} The color expressed in the `vec4(1.0, 1.0, 1.0, 1.0)` form. 55640 */ 55641function colorToGlsl(color) { 55642 const array = asArray(color).slice(); 55643 if (array.length < 4) { 55644 array.push(1); 55645 } 55646 return arrayToGlsl( 55647 array.map(function (c, i) { 55648 return i < 3 ? c / 255 : c; 55649 }) 55650 ); 55651} 55652 55653/** 55654 * Returns a stable equivalent number for the string literal. 55655 * @param {ParsingContext} context Parsing context 55656 * @param {string} string String literal value 55657 * @return {number} Number equivalent 55658 */ 55659function getStringNumberEquivalent(context, string) { 55660 if (context.stringLiteralsMap[string] === undefined) { 55661 context.stringLiteralsMap[string] = Object.keys( 55662 context.stringLiteralsMap 55663 ).length; 55664 } 55665 return context.stringLiteralsMap[string]; 55666} 55667 55668/** 55669 * Returns a stable equivalent number for the string literal, for use in shaders. This number is then 55670 * converted to be a GLSL-compatible string. 55671 * @param {ParsingContext} context Parsing context 55672 * @param {string} string String literal value 55673 * @return {string} GLSL-compatible string containing a number 55674 */ 55675function stringToGlsl(context, string) { 55676 return numberToGlsl(getStringNumberEquivalent(context, string)); 55677} 55678 55679/** 55680 * Recursively parses a style expression and outputs a GLSL-compatible string. Takes in a parsing context that 55681 * will be read and modified during the parsing operation. 55682 * @param {ParsingContext} context Parsing context 55683 * @param {ExpressionValue} value Value 55684 * @param {ValueTypes|number} [typeHint] Hint for the expected final type (can be several types combined) 55685 * @return {string} GLSL-compatible output 55686 */ 55687function expressionToGlsl(context, value, typeHint) { 55688 // operator
55689 if (Array.isArray(value) && typeof value[0] === 'string') { 55690 const operator = Operators[value[0]]; 55691 if (operator === undefined) { 55692 throw new Error( 55693 `Unrecognized expression operator: ${JSON.stringify(value)}` 55694 ); 55695 } 55696 return operator.toGlsl(context, value.slice(1), typeHint); 55697 } 55698 55699 const valueType = getValueType(value); 55700 if ((valueType & ValueTypes.NUMBER) > 0) { 55701 return numberToGlsl(/** @type {number} */ (value)); 55702 } 55703 55704 if ((valueType & ValueTypes.BOOLEAN) > 0) { 55705 return value.toString(); 55706 } 55707 55708 if ( 55709 (valueType & ValueTypes.STRING) > 0 && 55710 (typeHint === undefined || typeHint == ValueTypes.STRING) 55711 ) { 55712 return stringToGlsl(context, value.toString()); 55713 } 55714 55715 if ( 55716 (valueType & ValueTypes.COLOR) > 0 && 55717 (typeHint === undefined || typeHint == ValueTypes.COLOR) 55718 ) { 55719 return colorToGlsl(/** @type {Array<number> | string} */ (value)); 55720 } 55721 55722 if ((valueType & ValueTypes.NUMBER_ARRAY) > 0) { 55723 return arrayToGlsl(/** @type {Array<number>} */ (value)); 55724 } 55725 55726 throw new Error(`Unexpected expression ${value} (expected type ${typeHint})`); 55727} 55728 55729function assertNumber(value) { 55730 if (!(getValueType(value) & ValueTypes.NUMBER)) { 55731 throw new Error( 55732 `A numeric value was expected, got ${JSON.stringify(value)} instead` 55733 ); 55734 } 55735} 55736function assertNumbers(values) { 55737 for (let i = 0; i < values.length; i++) { 55738 assertNumber(values[i]); 55739 } 55740} 55741function assertString(value) { 55742 if (!(getValueType(value) & ValueTypes.STRING)) { 55743 throw new Error( 55744 `A string value was expected, got ${JSON.stringify(value)} instead` 55745 ); 55746 } 55747} 55748function assertBoolean(value) { 55749 if (!(getValueType(value) & ValueTypes.BOOLEAN)) { 55750 throw new Error( 55751 `A boolean value was expected, got ${JSON.stringify(value)} instead` 55752 ); 55753 } 55754} 55755function assertArgsCount(args, count) { 55756 if (args.length !== count) { 55757 throw new Error( 55758 `Exactly ${count} arguments were expected, got ${args.length} instead` 55759 ); 55760 } 55761} 55762function assertArgsMinCount(args, count) { 55763 if (args.length < count) { 55764 throw new Error( 55765 `At least ${count} arguments were expected, got ${args.length} instead` 55766 ); 55767 } 55768} 55769function assertArgsMaxCount(args, count) { 55770 if (args.length > count) { 55771 throw new Error( 55772 `At most ${count} arguments were expected, got ${args.length} instead` 55773 ); 55774 } 55775} 55776function assertArgsEven(args) { 55777 if (args.length % 2 !== 0) { 55778 throw new Error( 55779 `An even amount of arguments was expected, got ${args} instead` 55780 ); 55781 } 55782} 55783function assertArgsOdd(args) { 55784 if (args.length % 2 === 0) { 55785 throw new Error( 55786 `An odd amount of arguments was expected, got ${args} instead` 55787 ); 55788 } 55789} 55790function assertUniqueInferredType(args, types) { 55791 if (!isTypeUnique(types)) { 55792 throw new Error( 55793 `Could not infer only one type from the following expression: ${JSON.stringify( 55794 args 55795 )}` 55796 ); 55797 } 55798} 55799 55800Operators['get'] = { 55801 getReturnType: function (args) { 55802 return ValueTypes.ANY; 55803 }, 55804 toGlsl: function (context, args) { 55805 assertArgsCount(args, 1); 55806 assertString(args[0]); 55807 const value = args[0].toString(); 55808 if (!context.attributes.includes(value)) { 55809 context.attributes.push(value); 55810 } 55811 const prefix = context.inFragmentShader ? 'v_' : 'a_'; 55812 return prefix + value; 55813 }, 55814}; 55815 55816/** 55817 * Get the uniform name given a variable name. 55818 * @param {string} variableName The variable name. 55819 * @return {string} The uniform name. 55820 */ 55821function uniformNameForVariable(variableName) { 55822 return 'u_var_' + variableName; 55823} 55824 55825Operators['var'] = { 55826 getReturnType: function (args) { 55827 return ValueTypes.ANY; 55828 }, 55829 toGlsl: function (context, args) { 55830 assertArgsCount(args, 1); 55831 assertString(args[0]); 55832 const value = args[0].toString(); 55833 if (!context.variables.includes(value)) { 55834 context.variables.push(value); 55835 } 55836 return uniformNameForVariable(value); 55837 }, 55838}; 55839 55840const PALETTE_TEXTURE_ARRAY = 'u_paletteTextures'; 55841 55842// ['palette', index, colors] 55843Operators['palette'] = { 55844 getReturnType: function (args) { 55845 return ValueTypes.COLOR; 55846 },
55847 toGlsl: function (context, args) { 55848 assertArgsCount(args, 2); 55849 assertNumber(args[0]); 55850 const index = expressionToGlsl(context, args[0]); 55851 const colors = args[1]; 55852 if (!Array.isArray(colors)) { 55853 throw new Error('The second argument of palette must be an array'); 55854 } 55855 const numColors = colors.length; 55856 const palette = new Uint8Array(numColors * 4); 55857 for (let i = 0; i < numColors; i++) { 55858 const candidate = colors[i]; 55859 /** 55860 * @type {import('../color.js').Color} 55861 */ 55862 let color; 55863 if (typeof candidate === 'string') { 55864 color = fromString(candidate); 55865 } else { 55866 if (!Array.isArray(candidate)) { 55867 throw new Error( 55868 'The second argument of palette must be an array of strings or colors' 55869 ); 55870 } 55871 const length = candidate.length; 55872 if (length === 4) { 55873 color = candidate; 55874 } else { 55875 if (length !== 3) { 55876 throw new Error( 55877 `Expected palette color to have 3 or 4 values, got ${length}` 55878 ); 55879 } 55880 color = [candidate[0], candidate[1], candidate[2], 1]; 55881 } 55882 } 55883 const offset = i * 4; 55884 palette[offset] = color[0]; 55885 palette[offset + 1] = color[1]; 55886 palette[offset + 2] = color[2]; 55887 palette[offset + 3] = color[3] * 255; 55888 } 55889 if (!context.paletteTextures) { 55890 context.paletteTextures = []; 55891 } 55892 const paletteName = `${PALETTE_TEXTURE_ARRAY}[${context.paletteTextures.length}]`; 55893 const paletteTexture = new webgl_PaletteTexture(paletteName, palette); 55894 context.paletteTextures.push(paletteTexture); 55895 return `texture2D(${paletteName}, vec2((${index} + 0.5) / ${numColors}.0, 0.5))`; 55896 }, 55897}; 55898 55899const GET_BAND_VALUE_FUNC = 'getBandValue'; 55900 55901Operators['band'] = { 55902 getReturnType: function (args) { 55903 return ValueTypes.NUMBER; 55904 }, 55905 toGlsl: function (context, args) { 55906 assertArgsMinCount(args, 1); 55907 assertArgsMaxCount(args, 3); 55908 const band = args[0]; 55909 55910 if (!(GET_BAND_VALUE_FUNC in context.functions)) { 55911 let ifBlocks = ''; 55912 const bandCount = context.bandCount || 1; 55913 for (let i = 0; i < bandCount; i++) { 55914 const colorIndex = Math.floor(i / 4); 55915 let bandIndex = i % 4; 55916 if (i === bandCount - 1 && bandIndex === 1) { 55917 // LUMINANCE_ALPHA - band 1 assigned to rgb and band 2 assigned to alpha 55918 bandIndex = 3; 55919 } 55920 const textureName = `${Uniforms.TILE_TEXTURE_ARRAY}[${colorIndex}]`; 55921 ifBlocks += ` 55922 if (band == ${i + 1}.0) { 55923 return texture2D(${textureName}, v_textureCoord + vec2(dx, dy))[${bandIndex}]; 55924 } 55925 `; 55926 } 55927 55928 context.functions[GET_BAND_VALUE_FUNC] = ` 55929 float getBandValue(float band, float xOffset, float yOffset) { 55930 float dx = xOffset / ${Uniforms.TEXTURE_PIXEL_WIDTH}; 55931 float dy = yOffset / ${Uniforms.TEXTURE_PIXEL_HEIGHT}; 55932 ${ifBlocks} 55933 } 55934 `; 55935 } 55936 55937 const bandExpression = expressionToGlsl(context, band); 55938 const xOffsetExpression = expressionToGlsl(context, args[1] || 0); 55939 const yOffsetExpression = expressionToGlsl(context, args[2] || 0); 55940 return `${GET_BAND_VALUE_FUNC}(${bandExpression}, ${xOffsetExpression}, ${yOffsetExpression})`; 55941 }, 55942}; 55943 55944Operators['time'] = { 55945 getReturnType: function (args) { 55946 return ValueTypes.NUMBER; 55947 }, 55948 toGlsl: function (context, args) { 55949 assertArgsCount(args, 0); 55950 return 'u_time'; 55951 }, 55952}; 55953 55954Operators['zoom'] = { 55955 getReturnType: function (args) { 55956 return ValueTypes.NUMBER; 55957 }, 55958 toGlsl: function (context, args) { 55959 assertArgsCount(args, 0); 55960 return 'u_zoom'; 55961 }, 55962}; 55963 55964Operators['resolution'] = { 55965 getReturnType: function (args) { 55966 return ValueTypes.NUMBER; 55967 }, 55968 toGlsl: function (context, args) { 55969 assertArgsCount(args, 0); 55970 return 'u_resolution'; 55971 }, 55972}; 55973 55974Operators['*'] = { 55975 getReturnType: function (args) { 55976 return ValueTypes.NUMBER; 55977 }, 55978 toGlsl: function (context, args) { 55979 assertArgsCount(args, 2); 55980 assertNumbers(args); 55981 return `(${expressionToGlsl(context, args[0])} * ${expressionToGlsl( 55982 context, 55983 args[1] 55984 )})`; 55985 }, 55986}; 55987 55988Operators['/'] = { 55989 getReturnType: function (args) { 55990 return ValueTypes.NUMBER; 55991 },
55992 toGlsl: function (context, args) { 55993 assertArgsCount(args, 2); 55994 assertNumbers(args); 55995 return `(${expressionToGlsl(context, args[0])} / ${expressionToGlsl( 55996 context, 55997 args[1] 55998 )})`; 55999 }, 56000}; 56001 56002Operators['+'] = { 56003 getReturnType: function (args) { 56004 return ValueTypes.NUMBER; 56005 }, 56006 toGlsl: function (context, args) { 56007 assertArgsCount(args, 2); 56008 assertNumbers(args); 56009 return `(${expressionToGlsl(context, args[0])} + ${expressionToGlsl( 56010 context, 56011 args[1] 56012 )})`; 56013 }, 56014}; 56015 56016Operators['-'] = { 56017 getReturnType: function (args) { 56018 return ValueTypes.NUMBER; 56019 }, 56020 toGlsl: function (context, args) { 56021 assertArgsCount(args, 2); 56022 assertNumbers(args); 56023 return `(${expressionToGlsl(context, args[0])} - ${expressionToGlsl( 56024 context, 56025 args[1] 56026 )})`; 56027 }, 56028}; 56029 56030Operators['clamp'] = { 56031 getReturnType: function (args) { 56032 return ValueTypes.NUMBER; 56033 }, 56034 toGlsl: function (context, args) { 56035 assertArgsCount(args, 3); 56036 assertNumbers(args); 56037 const min = expressionToGlsl(context, args[1]); 56038 const max = expressionToGlsl(context, args[2]); 56039 return `clamp(${expressionToGlsl(context, args[0])}, ${min}, ${max})`; 56040 }, 56041}; 56042 56043Operators['%'] = { 56044 getReturnType: function (args) { 56045 return ValueTypes.NUMBER; 56046 }, 56047 toGlsl: function (context, args) { 56048 assertArgsCount(args, 2); 56049 assertNumbers(args); 56050 return `mod(${expressionToGlsl(context, args[0])}, ${expressionToGlsl( 56051 context, 56052 args[1] 56053 )})`; 56054 }, 56055}; 56056 56057Operators['^'] = { 56058 getReturnType: function (args) { 56059 return ValueTypes.NUMBER; 56060 }, 56061 toGlsl: function (context, args) { 56062 assertArgsCount(args, 2); 56063 assertNumbers(args); 56064 return `pow(${expressionToGlsl(context, args[0])}, ${expressionToGlsl( 56065 context, 56066 args[1] 56067 )})`; 56068 }, 56069}; 56070 56071Operators['abs'] = { 56072 getReturnType: function (args) { 56073 return ValueTypes.NUMBER; 56074 }, 56075 toGlsl: function (context, args) { 56076 assertArgsCount(args, 1); 56077 assertNumbers(args); 56078 return `abs(${expressionToGlsl(context, args[0])})`; 56079 }, 56080}; 56081 56082Operators['floor'] = { 56083 getReturnType: function (args) { 56084 return ValueTypes.NUMBER; 56085 }, 56086 toGlsl: function (context, args) { 56087 assertArgsCount(args, 1); 56088 assertNumbers(args); 56089 return `floor(${expressionToGlsl(context, args[0])})`; 56090 }, 56091}; 56092 56093Operators['round'] = { 56094 getReturnType: function (args) { 56095 return ValueTypes.NUMBER; 56096 }, 56097 toGlsl: function (context, args) { 56098 assertArgsCount(args, 1); 56099 assertNumbers(args); 56100 return `floor(${expressionToGlsl(context, args[0])} + 0.5)`; 56101 }, 56102}; 56103 56104Operators['ceil'] = { 56105 getReturnType: function (args) { 56106 return ValueTypes.NUMBER; 56107 }, 56108 toGlsl: function (context, args) { 56109 assertArgsCount(args, 1); 56110 assertNumbers(args); 56111 return `ceil(${expressionToGlsl(context, args[0])})`; 56112 }, 56113}; 56114 56115Operators['sin'] = { 56116 getReturnType: function (args) { 56117 return ValueTypes.NUMBER; 56118 }, 56119 toGlsl: function (context, args) { 56120 assertArgsCount(args, 1); 56121 assertNumbers(args); 56122 return `sin(${expressionToGlsl(context, args[0])})`; 56123 }, 56124}; 56125 56126Operators['cos'] = { 56127 getReturnType: function (args) { 56128 return ValueTypes.NUMBER; 56129 }, 56130 toGlsl: function (context, args) { 56131 assertArgsCount(args, 1); 56132 assertNumbers(args); 56133 return `cos(${expressionToGlsl(context, args[0])})`; 56134 }, 56135}; 56136 56137Operators['atan'] = { 56138 getReturnType: function (args) { 56139 return ValueTypes.NUMBER; 56140 }, 56141 toGlsl: function (context, args) { 56142 assertArgsMinCount(args, 1); 56143 assertArgsMaxCount(args, 2); 56144 assertNumbers(args); 56145 return args.length === 2 56146 ? `atan(${expressionToGlsl(context, args[0])}, ${expressionToGlsl( 56147 context, 56148 args[1] 56149 )})` 56150 : `atan(${expressionToGlsl(context, args[0])})`; 56151 }, 56152}; 56153 56154Operators['>'] = { 56155 getReturnType: function (args) { 56156 return ValueTypes.BOOLEAN; 56157 }, 56158 toGlsl: function (context, args) { 56159 assertArgsCount(args, 2); 56160 assertNumbers(args); 56161 return `(${expressionToGlsl(context, args[0])} > ${expressionToGlsl( 56162 context, 56163 args[1] 56164 )})`; 56165 }, 56166}; 56167 56168Operators['>='] = { 56169 getReturnType: function (args) { 56170 return ValueTypes.BOOLEAN; 56171 },
56172 toGlsl: function (context, args) { 56173 assertArgsCount(args, 2); 56174 assertNumbers(args); 56175 return `(${expressionToGlsl(context, args[0])} >= ${expressionToGlsl( 56176 context, 56177 args[1] 56178 )})`; 56179 }, 56180}; 56181 56182Operators['<'] = { 56183 getReturnType: function (args) { 56184 return ValueTypes.BOOLEAN; 56185 }, 56186 toGlsl: function (context, args) { 56187 assertArgsCount(args, 2); 56188 assertNumbers(args); 56189 return `(${expressionToGlsl(context, args[0])} < ${expressionToGlsl( 56190 context, 56191 args[1] 56192 )})`; 56193 }, 56194}; 56195 56196Operators['<='] = { 56197 getReturnType: function (args) { 56198 return ValueTypes.BOOLEAN; 56199 }, 56200 toGlsl: function (context, args) { 56201 assertArgsCount(args, 2); 56202 assertNumbers(args); 56203 return `(${expressionToGlsl(context, args[0])} <= ${expressionToGlsl( 56204 context, 56205 args[1] 56206 )})`; 56207 }, 56208}; 56209 56210function getEqualOperator(operator) { 56211 return { 56212 getReturnType: function (args) { 56213 return ValueTypes.BOOLEAN; 56214 }, 56215 toGlsl: function (context, args) { 56216 assertArgsCount(args, 2); 56217 56218 // find common type 56219 let type = ValueTypes.ANY; 56220 for (let i = 0; i < args.length; i++) { 56221 type &= getValueType(args[i]); 56222 } 56223 if (type === ValueTypes.NONE) { 56224 throw new Error( 56225 `All arguments should be of compatible type, got ${JSON.stringify( 56226 args 56227 )} instead` 56228 ); 56229 } 56230 56231 // Since it's not possible to have color types here, we can leave it out 56232 // This fixes issues in case the value type is ambiguously detected as a color (e.g. the string 'red') 56233 type &= ~ValueTypes.COLOR; 56234 56235 return `(${expressionToGlsl( 56236 context, 56237 args[0], 56238 type 56239 )} ${operator} ${expressionToGlsl(context, args[1], type)})`; 56240 }, 56241 }; 56242} 56243 56244Operators['=='] = getEqualOperator('=='); 56245 56246Operators['!='] = getEqualOperator('!='); 56247 56248Operators['!'] = { 56249 getReturnType: function (args) { 56250 return ValueTypes.BOOLEAN; 56251 }, 56252 toGlsl: function (context, args) { 56253 assertArgsCount(args, 1); 56254 assertBoolean(args[0]); 56255 return `(!${expressionToGlsl(context, args[0])})`; 56256 }, 56257}; 56258 56259function getDecisionOperator(operator) { 56260 return { 56261 getReturnType: function (args) { 56262 return ValueTypes.BOOLEAN; 56263 }, 56264 toGlsl: function (context, args) { 56265 assertArgsMinCount(args, 2); 56266 for (let i = 0; i < args.length; i++) { 56267 assertBoolean(args[i]); 56268 } 56269 let result = ''; 56270 result = args 56271 .map((arg) => expressionToGlsl(context, arg)) 56272 .join(` ${operator} `); 56273 result = `(${result})`; 56274 return result; 56275 }, 56276 }; 56277} 56278 56279Operators['all'] = getDecisionOperator('&&'); 56280 56281Operators['any'] = getDecisionOperator('||'); 56282 56283Operators['between'] = { 56284 getReturnType: function (args) { 56285 return ValueTypes.BOOLEAN; 56286 }, 56287 toGlsl: function (context, args) { 56288 assertArgsCount(args, 3); 56289 assertNumbers(args); 56290 const min = expressionToGlsl(context, args[1]); 56291 const max = expressionToGlsl(context, args[2]); 56292 const value = expressionToGlsl(context, args[0]); 56293 return `(${value} >= ${min} && ${value} <= ${max})`; 56294 }, 56295}; 56296 56297Operators['array'] = { 56298 getReturnType: function (args) { 56299 return ValueTypes.NUMBER_ARRAY; 56300 }, 56301 toGlsl: function (context, args) { 56302 assertArgsMinCount(args, 2); 56303 assertArgsMaxCount(args, 4); 56304 assertNumbers(args); 56305 const parsedArgs = args.map(function (val) { 56306 return expressionToGlsl(context, val, ValueTypes.NUMBER); 56307 }); 56308 return `vec${args.length}(${parsedArgs.join(', ')})`; 56309 }, 56310}; 56311 56312Operators['color'] = { 56313 getReturnType: function (args) { 56314 return ValueTypes.COLOR; 56315 }, 56316 toGlsl: function (context, args) { 56317 assertArgsMinCount(args, 3); 56318 assertArgsMaxCount(args, 4); 56319 assertNumbers(args); 56320 const array = /** @type {Array<number>} */ (args); 56321 if (args.length === 3) { 56322 array.push(1); 56323 } 56324 const parsedArgs = args.map(function (val, i) { 56325 return ( 56326 expressionToGlsl(context, val, ValueTypes.NUMBER) + 56327 (i < 3 ? ' / 255.0' : '') 56328 ); 56329 }); 56330 return `vec${args.length}(${parsedArgs.join(', ')})`; 56331 }, 56332}; 56333 56334Operators['interpolate'] = { 56335 getReturnType: function (args) { 56336 let type = ValueTypes.COLOR | ValueTypes.NUMBER; 56337 for (let i = 3; i < args.length; i += 2) { 56338 type = type & getValueType(args[i]); 56339 } 56340 return type; 56341 }, 56342 toGlsl: function (context, args, typeHint) { 56343 assertArgsEven(args); 56344 assertArgsMinCount(args, 6); 56345 56346 // validate interpolation type 56347 const type = args[0]; 56348 let interpolation; 56349 switch (type[0]) { 56350 case 'linear': 56351 interpolation = 1; 56352 break; 56353 case 'exponential': 56354 interpolation = type[1]; 56355 break; 56356 default: 56357 interpolation = null; 56358 } 56359 if (!interpolation) { 56360 throw new Error( 56361 `Invalid interpolation type for "interpolate" operator, received: ${JSON.stringify( 56362 type 56363 )}` 56364 ); 56365 } 56366 56367 // compute input/output types 56368 typeHint = typeHint !== undefined ? typeHint : ValueTypes.ANY; 56369 const outputType = Operators['interpolate'].getReturnType(args) & typeHint; 56370 assertUniqueInferredType(args, outputType); 56371
56372 const input = expressionToGlsl(context, args[1]); 56373 const exponent = numberToGlsl(interpolation); 56374 56375 let result = ''; 56376 for (let i = 2; i < args.length - 2; i += 2) { 56377 const stop1 = expressionToGlsl(context, args[i]); 56378 const output1 = 56379 result || expressionToGlsl(context, args[i + 1], outputType); 56380 const stop2 = expressionToGlsl(context, args[i + 2]); 56381 const output2 = expressionToGlsl(context, args[i + 3], outputType); 56382 result = `mix(${output1}, ${output2}, pow(clamp((${input} - ${stop1}) / (${stop2} - ${stop1}), 0.0, 1.0), ${exponent}))`; 56383 } 56384 return result; 56385 }, 56386}; 56387 56388Operators['match'] = { 56389 getReturnType: function (args) { 56390 let type = ValueTypes.ANY; 56391 for (let i = 2; i < args.length; i += 2) { 56392 type = type & getValueType(args[i]); 56393 } 56394 type = type & getValueType(args[args.length - 1]); 56395 return type; 56396 }, 56397 toGlsl: function (context, args, typeHint) { 56398 assertArgsEven(args); 56399 assertArgsMinCount(args, 4); 56400 56401 typeHint = typeHint !== undefined ? typeHint : ValueTypes.ANY; 56402 const outputType = Operators['match'].getReturnType(args) & typeHint; 56403 assertUniqueInferredType(args, outputType); 56404 56405 const input = expressionToGlsl(context, args[0]); 56406 const fallback = expressionToGlsl( 56407 context, 56408 args[args.length - 1], 56409 outputType 56410 ); 56411 let result = null; 56412 for (let i = args.length - 3; i >= 1; i -= 2) { 56413 const match = expressionToGlsl(context, args[i]); 56414 const output = expressionToGlsl(context, args[i + 1], outputType); 56415 result = `(${input} == ${match} ? ${output} : ${result || fallback})`; 56416 } 56417 return result; 56418 }, 56419}; 56420 56421Operators['case'] = { 56422 getReturnType: function (args) { 56423 let type = ValueTypes.ANY; 56424 for (let i = 1; i < args.length; i += 2) { 56425 type = type & getValueType(args[i]); 56426 } 56427 type = type & getValueType(args[args.length - 1]); 56428 return type; 56429 }, 56430 toGlsl: function (context, args, typeHint) { 56431 assertArgsOdd(args); 56432 assertArgsMinCount(args, 3); 56433 56434 typeHint = typeHint !== undefined ? typeHint : ValueTypes.ANY; 56435 const outputType = Operators['case'].getReturnType(args) & typeHint; 56436 assertUniqueInferredType(args, outputType); 56437 for (let i = 0; i < args.length - 1; i += 2) { 56438 assertBoolean(args[i]); 56439 } 56440 56441 const fallback = expressionToGlsl( 56442 context, 56443 args[args.length - 1], 56444 outputType 56445 ); 56446 let result = null; 56447 for (let i = args.length - 3; i >= 0; i -= 2) { 56448 const condition = expressionToGlsl(context, args[i]); 56449 const output = expressionToGlsl(context, args[i + 1], outputType); 56450 result = `(${condition} ? ${output} : ${result || fallback})`; 56451 } 56452 return result; 56453 }, 56454}; 56455 56456;// CONCATENATED MODULE: ./node_modules/ol/layer/WebGLTile.js 56457/** 56458 * @module ol/layer/WebGLTile 56459 */ 56460 56461 56462 56463 56464 56465/** 56466 * @typedef {import("../source/DataTile.js").default|import("../source/TileImage.js").default} SourceType 56467 */ 56468 56469/** 56470 * @typedef {Object} Style 56471 * Translates tile data to rendered pixels. 56472 * 56473 * @property {Object<string, (string|number)>} [variables] Style variables. Each variable must hold a number or string. These 56474 * variables can be used in the `color`, `brightness`, `contrast`, `exposure`, `saturation` and `gamma` 56475 * {@link import("../style/expressions.js").ExpressionValue expressions}, using the `['var', 'varName']` operator. 56476 * To update style variables, use the {@link import("./WebGLTile.js").default#updateStyleVariables} method. 56477 * @property {import("../style/expressions.js").ExpressionValue} [color] An expression applied to color values. 56478 * @property {import("../style/expressions.js").ExpressionValue} [brightness=0] Value used to decrease or increase 56479 * the layer brightness. Values range from -1 to 1. 56480 * @property {import("../style/expressions.js").ExpressionValue} [contrast=0] Value used to decrease or increase 56481 * the layer contrast. Values range from -1 to 1. 56482 * @property {import("../style/expressions.js").ExpressionValue} [exposure=0] Value used to decrease or increase 56483 * the layer exposure. Values range from -1 to 1. 56484 * @property {import("../style/expressions.js").ExpressionValue} [saturation=0] Value used to decrease or increase 56485 * the layer saturation. Values range from -1 to 1. 56486 * @property {import("../style/expressions.js").ExpressionValue} [gamma=1] Apply a gamma correction to the layer. 56487 * Values range from 0 to infinity. 56488 */ 56489 56490/** 56491 * @typedef {Object} Options 56492 * @property {Style} [style] Style to apply to the layer. 56493 * @property {string} [className='ol-layer'] A CSS class name to set to the layer element. 56494 * @property {number} [opacity=1] Opacity (0, 1). 56495 * @property {boolean} [visible=true] Visibility. 56496 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be 56497 * rendered outside of this extent. 56498 * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers 56499 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed 56500 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()` 56501 * method was used. 56502 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be 56503 * visible. 56504 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will 56505 * be visible. 56506 * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be 56507 * visible. 56508 * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will 56509 * be visible. 56510 * @property {number} [preload=0] Preload. Load low-resolution tiles up to `preload` levels. `0` 56511 * means no preloading. 56512 * @property {SourceType} [source] Source for this layer. 56513 * @property {Array<SourceType>|function(import("../extent.js").Extent, number):Array<SourceType>} [sources] Array 56514 * of sources for this layer. Takes precedence over `source`. Can either be an array of sources, or a function that 56515 * expects an extent and a resolution (in view projection units per pixel) and returns an array of sources. See 56516 * {@link module:ol/source.sourcesFromTileGrid} for a helper function to generate sources that are organized in a 56517 * pyramid following the same pattern as a tile grid. **Note:** All sources must have the same band count and content. 56518 * @property {import("../Map.js").default} [map] Sets the layer as overlay on a map. The map will not manage
56519 * this layer in its layers collection, and the layer will be rendered on top. This is useful for 56520 * temporary layers. The standard way to add a layer to a map and have it managed by the map is to 56521 * use {@link module:ol/Map~Map#addLayer}. 56522 * @property {boolean} [useInterimTilesOnError=true] Use interim tiles on error. 56523 * @property {number} [cacheSize=512] The internal texture cache size. This needs to be large enough to render 56524 * two zoom levels worth of tiles. 56525 */ 56526 56527/** 56528 * @typedef {Object} ParsedStyle 56529 * @property {string} vertexShader The vertex shader. 56530 * @property {string} fragmentShader The fragment shader. 56531 * @property {Object<string,import("../webgl/Helper.js").UniformValue>} uniforms Uniform definitions. 56532 * @property {Array<import("../webgl/PaletteTexture.js").default>} paletteTextures Palette textures. 56533 */ 56534 56535/** 56536 * @param {Style} style The layer style. 56537 * @param {number} [bandCount] The number of bands. 56538 * @return {ParsedStyle} Shaders and uniforms generated from the style. 56539 */ 56540function parseStyle(style, bandCount) { 56541 const vertexShader = ` 56542 attribute vec2 ${Attributes.TEXTURE_COORD}; 56543 uniform mat4 ${Uniforms.TILE_TRANSFORM}; 56544 uniform float ${Uniforms.TEXTURE_PIXEL_WIDTH}; 56545 uniform float ${Uniforms.TEXTURE_PIXEL_HEIGHT}; 56546 uniform float ${Uniforms.TEXTURE_RESOLUTION}; 56547 uniform float ${Uniforms.TEXTURE_ORIGIN_X}; 56548 uniform float ${Uniforms.TEXTURE_ORIGIN_Y}; 56549 uniform float ${Uniforms.DEPTH}; 56550 56551 varying vec2 v_textureCoord; 56552 varying vec2 v_mapCoord; 56553 56554 void main() { 56555 v_textureCoord = ${Attributes.TEXTURE_COORD}; 56556 v_mapCoord = vec2( 56557 ${Uniforms.TEXTURE_ORIGIN_X} + ${Uniforms.TEXTURE_RESOLUTION} * ${Uniforms.TEXTURE_PIXEL_WIDTH} * v_textureCoord[0], 56558 ${Uniforms.TEXTURE_ORIGIN_Y} - ${Uniforms.TEXTURE_RESOLUTION} * ${Uniforms.TEXTURE_PIXEL_HEIGHT} * v_textureCoord[1] 56559 ); 56560 gl_Position = ${Uniforms.TILE_TRANSFORM} * vec4(${Attributes.TEXTURE_COORD}, ${Uniforms.DEPTH}, 1.0); 56561 } 56562 `; 56563 56564 /** 56565 * @type {import("../style/expressions.js").ParsingContext} 56566 */ 56567 const context = { 56568 inFragmentShader: true, 56569 variables: [], 56570 attributes: [], 56571 stringLiteralsMap: {}, 56572 functions: {}, 56573 bandCount: bandCount, 56574 }; 56575 56576 const pipeline = []; 56577 56578 if (style.color !== undefined) { 56579 const color = expressionToGlsl(context, style.color, ValueTypes.COLOR); 56580 pipeline.push(`color = ${color};`); 56581 } 56582 56583 if (style.contrast !== undefined) { 56584 const contrast = expressionToGlsl( 56585 context, 56586 style.contrast, 56587 ValueTypes.NUMBER 56588 ); 56589 pipeline.push( 56590 `color.rgb = clamp((${contrast} + 1.0) * color.rgb - (${contrast} / 2.0), vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));` 56591 ); 56592 } 56593 56594 if (style.exposure !== undefined) { 56595 const exposure = expressionToGlsl( 56596 context, 56597 style.exposure, 56598 ValueTypes.NUMBER 56599 ); 56600 pipeline.push( 56601 `color.rgb = clamp((${exposure} + 1.0) * color.rgb, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));` 56602 ); 56603 } 56604 56605 if (style.saturation !== undefined) { 56606 const saturation = expressionToGlsl( 56607 context, 56608 style.saturation, 56609 ValueTypes.NUMBER 56610 ); 56611 pipeline.push(` 56612 float saturation = ${saturation} + 1.0; 56613 float sr = (1.0 - saturation) * 0.2126; 56614 float sg = (1.0 - saturation) * 0.7152; 56615 float sb = (1.0 - saturation) * 0.0722; 56616 mat3 saturationMatrix = mat3( 56617 sr + saturation, sr, sr, 56618 sg, sg + saturation, sg, 56619 sb, sb, sb + saturation 56620 ); 56621 color.rgb = clamp(saturationMatrix * color.rgb, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0)); 56622 `); 56623 } 56624 56625 if (style.gamma !== undefined) { 56626 const gamma = expressionToGlsl(context, style.gamma, ValueTypes.NUMBER); 56627 pipeline.push(`color.rgb = pow(color.rgb, vec3(1.0 / ${gamma}));`); 56628 } 56629 56630 if (style.brightness !== undefined) { 56631 const brightness = expressionToGlsl( 56632 context, 56633 style.brightness, 56634 ValueTypes.NUMBER 56635 ); 56636 pipeline.push( 56637 `color.rgb = clamp(color.rgb + ${brightness}, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));` 56638 ); 56639 } 56640 56641 /** @type {Object<string,import("../webgl/Helper").UniformValue>} */ 56642 const uniforms = {}; 56643 56644 const numVariables = context.variables.length; 56645 if (numVariables > 1 && !style.variables) { 56646 throw new Error( 56647 `Missing variables in style (expected ${context.variables})` 56648 ); 56649 } 56650 56651 for (let i = 0; i < numVariables; ++i) { 56652 const variableName = context.variables[i]; 56653 if (!(variableName in style.variables)) { 56654 throw new Error(`Missing '${variableName}' in style variables`); 56655 } 56656 const uniformName = uniformNameForVariable(variableName); 56657 uniforms[uniformName] = function () { 56658 let value = style.variables[variableName]; 56659 if (typeof value === 'string') { 56660 value = getStringNumberEquivalent(context, value); 56661 } 56662 return value !== undefined ? value : -9999999; // to avoid matching with the first string literal 56663 }; 56664 } 56665 56666 const uniformDeclarations = Object.keys(uniforms).map(function (name) { 56667 return `uniform float ${name};`; 56668 }); 56669
56670 const textureCount = Math.ceil(bandCount / 4); 56671 uniformDeclarations.push( 56672 `uniform sampler2D ${Uniforms.TILE_TEXTURE_ARRAY}[${textureCount}];` 56673 ); 56674 56675 if (context.paletteTextures) { 56676 uniformDeclarations.push( 56677 `uniform sampler2D ${PALETTE_TEXTURE_ARRAY}[${context.paletteTextures.length}];` 56678 ); 56679 } 56680 56681 const functionDefintions = Object.keys(context.functions).map(function ( 56682 name 56683 ) { 56684 return context.functions[name]; 56685 }); 56686 56687 const fragmentShader = ` 56688 #ifdef GL_FRAGMENT_PRECISION_HIGH 56689 precision highp float; 56690 #else 56691 precision mediump float; 56692 #endif 56693 56694 varying vec2 v_textureCoord; 56695 varying vec2 v_mapCoord; 56696 uniform vec4 ${Uniforms.RENDER_EXTENT}; 56697 uniform float ${Uniforms.TRANSITION_ALPHA}; 56698 uniform float ${Uniforms.TEXTURE_PIXEL_WIDTH}; 56699 uniform float ${Uniforms.TEXTURE_PIXEL_HEIGHT}; 56700 uniform float ${Uniforms.RESOLUTION}; 56701 uniform float ${Uniforms.ZOOM}; 56702 56703 ${uniformDeclarations.join('\n')} 56704 56705 ${functionDefintions.join('\n')} 56706 56707 void main() { 56708 if ( 56709 v_mapCoord[0] < ${Uniforms.RENDER_EXTENT}[0] || 56710 v_mapCoord[1] < ${Uniforms.RENDER_EXTENT}[1] || 56711 v_mapCoord[0] > ${Uniforms.RENDER_EXTENT}[2] || 56712 v_mapCoord[1] > ${Uniforms.RENDER_EXTENT}[3] 56713 ) { 56714 discard; 56715 } 56716 56717 vec4 color = texture2D(${ 56718 Uniforms.TILE_TEXTURE_ARRAY 56719 }[0], v_textureCoord); 56720 56721 ${pipeline.join('\n')} 56722 56723 if (color.a == 0.0) { 56724 discard; 56725 } 56726 56727 gl_FragColor = color; 56728 gl_FragColor.rgb *= gl_FragColor.a; 56729 gl_FragColor *= ${Uniforms.TRANSITION_ALPHA}; 56730 }`; 56731 56732 return { 56733 vertexShader: vertexShader, 56734 fragmentShader: fragmentShader, 56735 uniforms: uniforms, 56736 paletteTextures: context.paletteTextures, 56737 }; 56738} 56739 56740/** 56741 * @classdesc 56742 * For layer sources that provide pre-rendered, tiled images in grids that are 56743 * organized by zoom levels for specific resolutions. 56744 * Note that any property set in the options is set as a {@link module:ol/Object~BaseObject} 56745 * property on the layer object; for example, setting `title: 'My Title'` in the 56746 * options means that `title` is observable, and has get/set accessors. 56747 * 56748 * @extends BaseTileLayer<SourceType, WebGLTileLayerRenderer> 56749 * @fires import("../render/Event.js").RenderEvent 56750 * @api 56751 */ 56752class WebGLTileLayer extends BaseTile { 56753 /** 56754 * @param {Options} options Tile layer options. 56755 */ 56756 constructor(options) { 56757 options = options ? Object.assign({}, options) : {}; 56758 56759 const style = options.style || {}; 56760 delete options.style; 56761 56762 const cacheSize = options.cacheSize; 56763 delete options.cacheSize; 56764 56765 super(options); 56766 56767 /** 56768 * @type {Array<SourceType>|function(import("../extent.js").Extent, number):Array<SourceType>} 56769 * @private 56770 */ 56771 this.sources_ = options.sources; 56772 56773 /** 56774 * @type {SourceType|null} 56775 * @private 56776 */ 56777 this.renderedSource_ = null; 56778 56779 /** 56780 * @type {number} 56781 * @private 56782 */ 56783 this.renderedResolution_ = NaN; 56784 56785 /** 56786 * @type {Style} 56787 * @private 56788 */ 56789 this.style_ = style; 56790 56791 /** 56792 * @type {number} 56793 * @private 56794 */ 56795 this.cacheSize_ = cacheSize; 56796 56797 /** 56798 * @type {Object<string, (string|number)>} 56799 * @private 56800 */ 56801 this.styleVariables_ = this.style_.variables || {}; 56802 56803 this.addChangeListener(layer_Property.SOURCE, this.handleSourceUpdate_); 56804 } 56805 56806 /** 56807 * Gets the sources for this layer, for a given extent and resolution. 56808 * @param {import("../extent.js").Extent} extent Extent. 56809 * @param {number} resolution Resolution. 56810 * @return {Array<SourceType>} Sources. 56811 */ 56812 getSources(extent, resolution) { 56813 const source = this.getSource(); 56814 return this.sources_ 56815 ? typeof this.sources_ === 'function' 56816 ? this.sources_(extent, resolution) 56817 : this.sources_ 56818 : source 56819 ? [source] 56820 : []; 56821 } 56822 56823 /** 56824 * @return {SourceType} The source being rendered. 56825 */ 56826 getRenderSource() { 56827 return this.renderedSource_ || this.getSource(); 56828 } 56829 56830 /** 56831 * @return {import("../source/Source.js").State} Source state. 56832 */ 56833 getSourceState() { 56834 const source = this.getRenderSource(); 56835 return source ? source.getState() : 'undefined'; 56836 } 56837 56838 /** 56839 * @private 56840 */ 56841 handleSourceUpdate_() { 56842 if (this.getSource()) { 56843 this.setStyle(this.style_); 56844 } 56845 } 56846 56847 /** 56848 * @private 56849 * @return {number} The number of source bands. 56850 */ 56851 getSourceBandCount_() { 56852 const max = Number.MAX_SAFE_INTEGER;
56853 const sources = this.getSources([-max, -max, max, max], max); 56854 return sources && sources.length && 'bandCount' in sources[0] 56855 ? sources[0].bandCount 56856 : 4; 56857 } 56858 56859 createRenderer() { 56860 const parsedStyle = parseStyle(this.style_, this.getSourceBandCount_()); 56861 56862 return new webgl_TileLayer(this, { 56863 vertexShader: parsedStyle.vertexShader, 56864 fragmentShader: parsedStyle.fragmentShader, 56865 uniforms: parsedStyle.uniforms, 56866 cacheSize: this.cacheSize_, 56867 paletteTextures: parsedStyle.paletteTextures, 56868 }); 56869 } 56870 56871 /** 56872 * @param {import("../Map").FrameState} frameState Frame state. 56873 * @param {Array<SourceType>} sources Sources. 56874 * @return {HTMLElement} Canvas. 56875 */ 56876 renderSources(frameState, sources) { 56877 const layerRenderer = this.getRenderer(); 56878 let canvas; 56879 for (let i = 0, ii = sources.length; i < ii; ++i) { 56880 this.renderedSource_ = sources[i]; 56881 if (layerRenderer.prepareFrame(frameState)) { 56882 canvas = layerRenderer.renderFrame(frameState); 56883 } 56884 } 56885 return canvas; 56886 } 56887 56888 /** 56889 * @param {?import("../Map.js").FrameState} frameState Frame state. 56890 * @param {HTMLElement} target Target which the renderer may (but need not) use 56891 * for rendering its content. 56892 * @return {HTMLElement} The rendered element. 56893 */ 56894 render(frameState, target) { 56895 this.rendered = true; 56896 const viewState = frameState.viewState; 56897 const sources = this.getSources(frameState.extent, viewState.resolution); 56898 let ready = true; 56899 for (let i = 0, ii = sources.length; i < ii; ++i) { 56900 const source = sources[i]; 56901 const sourceState = source.getState(); 56902 if (sourceState == 'loading') { 56903 const onChange = () => { 56904 if (source.getState() == 'ready') { 56905 source.removeEventListener('change', onChange); 56906 this.changed(); 56907 } 56908 }; 56909 source.addEventListener('change', onChange); 56910 } 56911 ready = ready && sourceState == 'ready'; 56912 } 56913 const canvas = this.renderSources(frameState, sources); 56914 if (this.getRenderer().renderComplete && ready) { 56915 // Fully rendered, done. 56916 this.renderedResolution_ = viewState.resolution; 56917 return canvas; 56918 } 56919 // Render sources from previously fully rendered frames 56920 if (this.renderedResolution_ > 0.5 * viewState.resolution) { 56921 const altSources = this.getSources( 56922 frameState.extent, 56923 this.renderedResolution_ 56924 ).filter((source) => !sources.includes(source)); 56925 if (altSources.length > 0) { 56926 return this.renderSources(frameState, altSources); 56927 } 56928 } 56929 return canvas; 56930 } 56931 56932 /** 56933 * Update the layer style. The `updateStyleVariables` function is a more efficient 56934 * way to update layer rendering. In cases where the whole style needs to be updated, 56935 * this method may be called instead. Note that calling this method will also replace 56936 * any previously set variables, so the new style also needs to include new variables, 56937 * if needed. 56938 * @param {Style} style The new style. 56939 */ 56940 setStyle(style) { 56941 this.styleVariables_ = style.variables || {}; 56942 this.style_ = style; 56943 const parsedStyle = parseStyle(this.style_, this.getSourceBandCount_()); 56944 const renderer = this.getRenderer(); 56945 renderer.reset({ 56946 vertexShader: parsedStyle.vertexShader, 56947 fragmentShader: parsedStyle.fragmentShader, 56948 uniforms: parsedStyle.uniforms, 56949 paletteTextures: parsedStyle.paletteTextures, 56950 }); 56951 this.changed(); 56952 } 56953 56954 /** 56955 * Update any variables used by the layer style and trigger a re-render. 56956 * @param {Object<string, number>} variables Variables to update. 56957 * @api 56958 */ 56959 updateStyleVariables(variables) { 56960 Object.assign(this.styleVariables_, variables); 56961 this.changed(); 56962 } 56963} 56964 56965/** 56966 * Clean up underlying WebGL resources. 56967 * @function 56968 * @api 56969 */ 56970WebGLTileLayer.prototype.dispose; 56971 56972/* harmony default export */ const WebGLTile = (WebGLTileLayer); 56973 56974;// CONCATENATED MODULE: ./node_modules/ol/geom/GeometryCollection.js 56975/** 56976 * @module ol/geom/GeometryCollection 56977 */ 56978 56979 56980 56981 56982 56983/** 56984 * @classdesc 56985 * An array of {@link module:ol/geom/Geometry~Geometry} objects. 56986 * 56987 * @api 56988 */ 56989class GeometryCollection extends geom_Geometry { 56990 /** 56991 * @param {Array<Geometry>} [geometries] Geometries. 56992 */ 56993 constructor(geometries) { 56994 super(); 56995 56996 /** 56997 * @private 56998 * @type {Array<Geometry>} 56999 */ 57000 this.geometries_ = geometries ? geometries : null; 57001 57002 /** 57003 * @type {Array<import("../events.js").EventsKey>} 57004 */ 57005 this.changeEventsKeys_ = []; 57006 57007 this.listenGeometriesChange_(); 57008 } 57009 57010 /** 57011 * @private 57012 */ 57013 unlistenGeometriesChange_() { 57014 this.changeEventsKeys_.forEach(unlistenByKey); 57015 this.changeEventsKeys_.length = 0; 57016 } 57017 57018 /** 57019 * @private 57020 */ 57021 listenGeometriesChange_() { 57022 if (!this.geometries_) { 57023 return; 57024 } 57025 for (let i = 0, ii = this.geometries_.length; i < ii; ++i) { 57026 this.changeEventsKeys_.push( 57027 listen(this.geometries_[i], EventType.CHANGE, this.changed, this) 57028 ); 57029 } 57030 } 57031 57032 /** 57033 * Make a complete copy of the geometry. 57034 * @return {!GeometryCollection} Clone. 57035 * @api 57036 */ 57037 clone() { 57038 const geometryCollection = new GeometryCollection(null); 57039 geometryCollection.setGeometries(this.geometries_); 57040 geometryCollection.applyProperties(this); 57041 return geometryCollection; 57042 } 57043 57044 /** 57045 * @param {number} x X. 57046 * @param {number} y Y. 57047 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 57048 * @param {number} minSquaredDistance Minimum squared distance. 57049 * @return {number} Minimum squared distance. 57050 */ 57051 closestPointXY(x, y, closestPoint, minSquaredDistance) { 57052 if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) { 57053 return minSquaredDistance; 57054 } 57055 const geometries = this.geometries_; 57056 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57057 minSquaredDistance = geometries[i].closestPointXY( 57058 x, 57059 y, 57060 closestPoint, 57061 minSquaredDistance 57062 ); 57063 } 57064 return minSquaredDistance; 57065 } 57066 57067 /** 57068 * @param {number} x X. 57069 * @param {number} y Y. 57070 * @return {boolean} Contains (x, y). 57071 */ 57072 containsXY(x, y) { 57073 const geometries = this.geometries_; 57074 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57075 if (geometries[i].containsXY(x, y)) { 57076 return true; 57077 } 57078 } 57079 return false;
57080 } 57081 57082 /** 57083 * @param {import("../extent.js").Extent} extent Extent. 57084 * @protected 57085 * @return {import("../extent.js").Extent} extent Extent. 57086 */ 57087 computeExtent(extent) { 57088 createOrUpdateEmpty(extent); 57089 const geometries = this.geometries_; 57090 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57091 extent_extend(extent, geometries[i].getExtent()); 57092 } 57093 return extent; 57094 } 57095 57096 /** 57097 * Return the geometries that make up this geometry collection. 57098 * @return {Array<Geometry>} Geometries. 57099 * @api 57100 */ 57101 getGeometries() { 57102 return cloneGeometries(this.geometries_); 57103 } 57104 57105 /** 57106 * @return {Array<Geometry>} Geometries. 57107 */ 57108 getGeometriesArray() { 57109 return this.geometries_; 57110 } 57111 57112 /** 57113 * @return {Array<Geometry>} Geometries. 57114 */ 57115 getGeometriesArrayRecursive() { 57116 /** @type {Array<Geometry>} */ 57117 let geometriesArray = []; 57118 const geometries = this.geometries_; 57119 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57120 if (geometries[i].getType() === this.getType()) { 57121 geometriesArray = geometriesArray.concat( 57122 /** @type {GeometryCollection} */ ( 57123 geometries[i] 57124 ).getGeometriesArrayRecursive() 57125 ); 57126 } else { 57127 geometriesArray.push(geometries[i]); 57128 } 57129 } 57130 return geometriesArray; 57131 } 57132 57133 /** 57134 * Create a simplified version of this geometry using the Douglas Peucker algorithm. 57135 * @param {number} squaredTolerance Squared tolerance. 57136 * @return {GeometryCollection} Simplified GeometryCollection. 57137 */ 57138 getSimplifiedGeometry(squaredTolerance) { 57139 if (this.simplifiedGeometryRevision !== this.getRevision()) { 57140 this.simplifiedGeometryMaxMinSquaredTolerance = 0; 57141 this.simplifiedGeometryRevision = this.getRevision(); 57142 } 57143 if ( 57144 squaredTolerance < 0 || 57145 (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && 57146 squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance) 57147 ) { 57148 return this; 57149 } 57150 57151 const simplifiedGeometries = []; 57152 const geometries = this.geometries_; 57153 let simplified = false; 57154 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57155 const geometry = geometries[i]; 57156 const simplifiedGeometry = 57157 geometry.getSimplifiedGeometry(squaredTolerance); 57158 simplifiedGeometries.push(simplifiedGeometry); 57159 if (simplifiedGeometry !== geometry) { 57160 simplified = true; 57161 } 57162 } 57163 if (simplified) { 57164 const simplifiedGeometryCollection = new GeometryCollection(null); 57165 simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries); 57166 return simplifiedGeometryCollection; 57167 } else { 57168 this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; 57169 return this; 57170 } 57171 } 57172 57173 /** 57174 * Get the type of this geometry. 57175 * @return {import("./Geometry.js").Type} Geometry type. 57176 * @api 57177 */ 57178 getType() { 57179 return 'GeometryCollection'; 57180 } 57181 57182 /** 57183 * Test if the geometry and the passed extent intersect. 57184 * @param {import("../extent.js").Extent} extent Extent. 57185 * @return {boolean} `true` if the geometry and the extent intersect. 57186 * @api 57187 */ 57188 intersectsExtent(extent) { 57189 const geometries = this.geometries_; 57190 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57191 if (geometries[i].intersectsExtent(extent)) { 57192 return true; 57193 } 57194 } 57195 return false; 57196 } 57197 57198 /** 57199 * @return {boolean} Is empty. 57200 */ 57201 isEmpty() { 57202 return this.geometries_.length === 0; 57203 } 57204 57205 /** 57206 * Rotate the geometry around a given coordinate. This modifies the geometry 57207 * coordinates in place. 57208 * @param {number} angle Rotation angle in radians. 57209 * @param {import("../coordinate.js").Coordinate} anchor The rotation center. 57210 * @api 57211 */ 57212 rotate(angle, anchor) { 57213 const geometries = this.geometries_; 57214 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57215 geometries[i].rotate(angle, anchor); 57216 } 57217 this.changed(); 57218 } 57219 57220 /** 57221 * Scale the geometry (with an optional origin). This modifies the geometry 57222 * coordinates in place. 57223 * @abstract 57224 * @param {number} sx The scaling factor in the x-direction. 57225 * @param {number} [sy] The scaling factor in the y-direction (defaults to sx). 57226 * @param {import("../coordinate.js").Coordinate} [anchor] The scale origin (defaults to the center 57227 * of the geometry extent). 57228 * @api 57229 */ 57230 scale(sx, sy, anchor) { 57231 if (!anchor) { 57232 anchor = getCenter(this.getExtent()); 57233 } 57234 const geometries = this.geometries_; 57235 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57236 geometries[i].scale(sx, sy, anchor); 57237 } 57238 this.changed(); 57239 } 57240 57241 /** 57242 * Set the geometries that make up this geometry collection. 57243 * @param {Array<Geometry>} geometries Geometries. 57244 * @api 57245 */ 57246 setGeometries(geometries) { 57247 this.setGeometriesArray(cloneGeometries(geometries)); 57248 } 57249 57250 /** 57251 * @param {Array<Geometry>} geometries Geometries. 57252 */ 57253 setGeometriesArray(geometries) { 57254 this.unlistenGeometriesChange_(); 57255 this.geometries_ = geometries; 57256 this.listenGeometriesChange_(); 57257 this.changed(); 57258 } 57259 57260 /** 57261 * Apply a transform function to the coordinates of the geometry. 57262 * The geometry is modified in place. 57263 * If you do not want the geometry modified in place, first `clone()` it and 57264 * then use this function on the clone. 57265 * @param {import("../proj.js").TransformFunction} transformFn Transform function. 57266 * Called with a flat array of geometry coordinates. 57267 * @api 57268 */ 57269 applyTransform(transformFn) { 57270 const geometries = this.geometries_; 57271 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57272 geometries[i].applyTransform(transformFn); 57273 } 57274 this.changed(); 57275 } 57276 57277 /** 57278 * Translate the geometry. This modifies the geometry coordinates in place. If 57279 * instead you want a new geometry, first `clone()` this geometry. 57280 * @param {number} deltaX Delta X. 57281 * @param {number} deltaY Delta Y. 57282 * @api 57283 */ 57284 translate(deltaX, deltaY) { 57285 const geometries = this.geometries_; 57286 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57287 geometries[i].translate(deltaX, deltaY); 57288 } 57289 this.changed(); 57290 } 57291 57292 /** 57293 * Clean up. 57294 */ 57295 disposeInternal() { 57296 this.unlistenGeometriesChange_(); 57297 super.disposeInternal(); 57298 } 57299} 57300 57301/** 57302 * @param {Array<Geometry>} geometries Geometries. 57303 * @return {Array<Geometry>} Cloned geometries. 57304 */ 57305function cloneGeometries(geometries) { 57306 const clonedGeometries = []; 57307 for (let i = 0, ii = geometries.length; i < ii; ++i) { 57308 clonedGeometries.push(geometries[i].clone()); 57309 } 57310 return clonedGeometries; 57311} 57312 57313/* harmony default export */ const geom_GeometryCollection = (GeometryCollection); 57314 57315;// CONCATENATED MODULE: ./node_modules/ol/format/Feature.js 57316/** 57317 * @module ol/format/Feature 57318 */ 57319 57320 57321 57322/** 57323 * @typedef {Object} ReadOptions 57324 * @property {import("../proj.js").ProjectionLike} [dataProjection] Projection of the data we are reading. 57325 * If not provided, the projection will be derived from the data (where possible) or 57326 * the `dataProjection` of the format is assigned (where set). If the projection 57327 * can not be derived from the data and if no `dataProjection` is set for a format, 57328 * the features will not be reprojected. 57329 * @property {import("../extent.js").Extent} [extent] Tile extent in map units of the tile being read. 57330 * This is only required when reading data with tile pixels as geometry units. When configured, 57331 * a `dataProjection` with `TILE_PIXELS` as `units` and the tile's pixel extent as `extent` needs to be 57332 * provided. 57333 * @property {import("../proj.js").ProjectionLike} [featureProjection] Projection of the feature geometries 57334 * created by the format reader. If not provided, features will be returned in the 57335 * `dataProjection`. 57336 */ 57337 57338/** 57339 * @typedef {Object} WriteOptions 57340 * @property {import("../proj.js").ProjectionLike} [dataProjection] Projection of the data we are writing. 57341 * If not provided, the `dataProjection` of the format is assigned (where set). 57342 * If no `dataProjection` is set for a format, the features will be returned 57343 * in the `featureProjection`. 57344 * @property {import("../proj.js").ProjectionLike} [featureProjection] Projection of the feature geometries 57345 * that will be serialized by the format writer. If not provided, geometries are assumed 57346 * to be in the `dataProjection` if that is set; in other words, they are not transformed. 57347 * @property {boolean} [rightHanded] When writing geometries, follow the right-hand 57348 * rule for linear ring orientation. This means that polygons will have counter-clockwise 57349 * exterior rings and clockwise interior rings. By default, coordinates are serialized 57350 * as they are provided at construction. If `true`, the right-hand rule will 57351 * be applied. If `false`, the left-hand rule will be applied (clockwise for 57352 * exterior and counter-clockwise for interior rings). Note that not all 57353 * formats support this. The GeoJSON format does use this property when writing 57354 * geometries. 57355 * @property {number} [decimals] Maximum number of decimal places for coordinates. 57356 * Coordinates are stored internally as floats, but floating-point arithmetic can create 57357 * coordinates with a large number of decimal places, not generally wanted on output. 57358 * Set a number here to round coordinates. Can also be used to ensure that 57359 * coordinates read in can be written back out with the same number of decimals. 57360 * Default is no rounding. 57361 */ 57362 57363/** 57364 * @typedef {'arraybuffer' | 'json' | 'text' | 'xml'} Type 57365 */ 57366 57367/** 57368 * @classdesc 57369 * Abstract base class; normally only used for creating subclasses and not 57370 * instantiated in apps. 57371 * Base class for feature formats. 57372 * {@link module:ol/format/Feature~FeatureFormat} subclasses provide the ability to decode and encode 57373 * {@link module:ol/Feature~Feature} objects from a variety of commonly used geospatial 57374 * file formats. See the documentation for each format for more details. 57375 * 57376 * @abstract 57377 * @api 57378 */ 57379class FeatureFormat { 57380 constructor() { 57381 /** 57382 * @protected 57383 * @type {import("../proj/Projection.js").default|undefined} 57384 */ 57385 this.dataProjection = undefined; 57386 57387 /** 57388 * @protected 57389 * @type {import("../proj/Projection.js").default|undefined} 57390 */ 57391 this.defaultFeatureProjection = undefined; 57392 57393 /** 57394 * A list media types supported by the format in descending order of preference. 57395 * @type {Array<string>} 57396 */ 57397 this.supportedMediaTypes = null; 57398 } 57399 57400 /** 57401 * Adds the data projection to the read options.
57402 * @param {Document|Element|Object|string} source Source. 57403 * @param {ReadOptions} [options] Options. 57404 * @return {ReadOptions|undefined} Options. 57405 * @protected 57406 */ 57407 getReadOptions(source, options) { 57408 if (options) { 57409 let dataProjection = options.dataProjection 57410 ? proj_get(options.dataProjection) 57411 : this.readProjection(source); 57412 if ( 57413 options.extent && 57414 dataProjection && 57415 dataProjection.getUnits() === 'tile-pixels' 57416 ) { 57417 dataProjection = proj_get(dataProjection); 57418 dataProjection.setWorldExtent(options.extent); 57419 } 57420 options = { 57421 dataProjection: dataProjection, 57422 featureProjection: options.featureProjection, 57423 }; 57424 } 57425 return this.adaptOptions(options); 57426 } 57427 57428 /** 57429 * Sets the `dataProjection` on the options, if no `dataProjection` 57430 * is set. 57431 * @param {WriteOptions|ReadOptions|undefined} options 57432 * Options. 57433 * @protected 57434 * @return {WriteOptions|ReadOptions|undefined} 57435 * Updated options. 57436 */ 57437 adaptOptions(options) { 57438 return Object.assign( 57439 { 57440 dataProjection: this.dataProjection, 57441 featureProjection: this.defaultFeatureProjection, 57442 }, 57443 options 57444 ); 57445 } 57446 57447 /** 57448 * @abstract 57449 * @return {Type} The format type. 57450 */ 57451 getType() { 57452 return util_abstract(); 57453 } 57454 57455 /** 57456 * Read a single feature from a source. 57457 * 57458 * @abstract 57459 * @param {Document|Element|Object|string} source Source. 57460 * @param {ReadOptions} [options] Read options. 57461 * @return {import("../Feature.js").FeatureLike} Feature. 57462 */ 57463 readFeature(source, options) { 57464 return util_abstract(); 57465 } 57466 57467 /** 57468 * Read all features from a source. 57469 * 57470 * @abstract 57471 * @param {Document|Element|ArrayBuffer|Object|string} source Source. 57472 * @param {ReadOptions} [options] Read options. 57473 * @return {Array<import("../Feature.js").FeatureLike>} Features. 57474 */ 57475 readFeatures(source, options) { 57476 return util_abstract(); 57477 } 57478 57479 /** 57480 * Read a single geometry from a source. 57481 * 57482 * @abstract 57483 * @param {Document|Element|Object|string} source Source. 57484 * @param {ReadOptions} [options] Read options. 57485 * @return {import("../geom/Geometry.js").default} Geometry. 57486 */ 57487 readGeometry(source, options) { 57488 return util_abstract(); 57489 } 57490 57491 /** 57492 * Read the projection from a source. 57493 * 57494 * @abstract 57495 * @param {Document|Element|Object|string} source Source. 57496 * @return {import("../proj/Projection.js").default|undefined} Projection. 57497 */ 57498 readProjection(source) { 57499 return util_abstract(); 57500 } 57501 57502 /** 57503 * Encode a feature in this format. 57504 * 57505 * @abstract 57506 * @param {import("../Feature.js").default} feature Feature. 57507 * @param {WriteOptions} [options] Write options. 57508 * @return {string|ArrayBuffer} Result. 57509 */ 57510 writeFeature(feature, options) { 57511 return util_abstract(); 57512 } 57513 57514 /** 57515 * Encode an array of features in this format. 57516 * 57517 * @abstract 57518 * @param {Array<import("../Feature.js").default>} features Features. 57519 * @param {WriteOptions} [options] Write options. 57520 * @return {string|ArrayBuffer} Result. 57521 */ 57522 writeFeatures(features, options) { 57523 return util_abstract(); 57524 } 57525 57526 /** 57527 * Write a single geometry in this format. 57528 * 57529 * @abstract 57530 * @param {import("../geom/Geometry.js").default} geometry Geometry. 57531 * @param {WriteOptions} [options] Write options. 57532 * @return {string|ArrayBuffer} Result. 57533 */ 57534 writeGeometry(geometry, options) { 57535 return util_abstract(); 57536 } 57537} 57538 57539/* harmony default export */ const format_Feature = (FeatureFormat); 57540 57541/** 57542 * @param {import("../geom/Geometry.js").default} geometry Geometry. 57543 * @param {boolean} write Set to true for writing, false for reading. 57544 * @param {WriteOptions|ReadOptions} [options] Options. 57545 * @return {import("../geom/Geometry.js").default} Transformed geometry. 57546 */ 57547function transformGeometryWithOptions(geometry, write, options) { 57548 const featureProjection = options 57549 ? proj_get(options.featureProjection) 57550 : null; 57551 const dataProjection = options ? proj_get(options.dataProjection) : null; 57552 57553 let transformed; 57554 if ( 57555 featureProjection && 57556 dataProjection && 57557 !equivalent(featureProjection, dataProjection) 57558 ) { 57559 transformed = (write ? geometry.clone() : geometry).transform( 57560 write ? featureProjection : dataProjection, 57561 write ? dataProjection : featureProjection 57562 ); 57563 } else { 57564 transformed = geometry; 57565 } 57566 if ( 57567 write && 57568 options && 57569 /** @type {WriteOptions} */ (options).decimals !== undefined 57570 ) { 57571 const power = Math.pow(10, /** @type {WriteOptions} */ (options).decimals); 57572 // if decimals option on write, round each coordinate appropriately 57573 /** 57574 * @param {Array<number>} coordinates Coordinates. 57575 * @return {Array<number>} Transformed coordinates. 57576 */ 57577 const transform = function (coordinates) { 57578 for (let i = 0, ii = coordinates.length; i < ii; ++i) { 57579 coordinates[i] = Math.round(coordinates[i] * power) / power; 57580 } 57581 return coordinates; 57582 }; 57583 if (transformed === geometry) { 57584 transformed = geometry.clone(); 57585 } 57586 transformed.applyTransform(transform); 57587 } 57588 return transformed; 57589} 57590 57591/** 57592 * @param {import("../extent.js").Extent} extent Extent. 57593 * @param {ReadOptions} [options] Read options. 57594 * @return {import("../extent.js").Extent} Transformed extent. 57595 */ 57596function transformExtentWithOptions(extent, options) { 57597 const featureProjection = options 57598 ? getProjection(options.featureProjection) 57599 : null; 57600 const dataProjection = options ? getProjection(options.dataProjection) : null; 57601 57602 if ( 57603 featureProjection && 57604 dataProjection && 57605 !equivalentProjection(featureProjection, dataProjection) 57606 ) { 57607 return transformExtent(extent, dataProjection, featureProjection); 57608 } else { 57609 return extent; 57610 } 57611} 57612 57613;// CONCATENATED MODULE: ./node_modules/ol/format/JSONFeature.js 57614/** 57615 * @module ol/format/JSONFeature 57616 */ 57617 57618 57619 57620/** 57621 * @classdesc 57622 * Abstract base class; normally only used for creating subclasses and not 57623 * instantiated in apps. 57624 * Base class for JSON feature formats. 57625 * 57626 * @abstract 57627 */ 57628class JSONFeature extends format_Feature { 57629 constructor() { 57630 super(); 57631 } 57632 57633 /** 57634 * @return {import("./Feature.js").Type} Format. 57635 */ 57636 getType() { 57637 return 'json'; 57638 } 57639 57640 /** 57641 * Read a feature. Only works for a single feature. Use `readFeatures` to 57642 * read a feature collection. 57643 *
57644 * @param {ArrayBuffer|Document|Element|Object|string} source Source. 57645 * @param {import("./Feature.js").ReadOptions} [options] Read options. 57646 * @return {import("../Feature.js").default} Feature. 57647 * @api 57648 */ 57649 readFeature(source, options) { 57650 return this.readFeatureFromObject( 57651 getObject(source), 57652 this.getReadOptions(source, options) 57653 ); 57654 } 57655 57656 /** 57657 * Read all features. Works with both a single feature and a feature 57658 * collection. 57659 * 57660 * @param {ArrayBuffer|Document|Element|Object|string} source Source. 57661 * @param {import("./Feature.js").ReadOptions} [options] Read options. 57662 * @return {Array<import("../Feature.js").default>} Features. 57663 * @api 57664 */ 57665 readFeatures(source, options) { 57666 return this.readFeaturesFromObject( 57667 getObject(source), 57668 this.getReadOptions(source, options) 57669 ); 57670 } 57671 57672 /** 57673 * @abstract 57674 * @param {Object} object Object. 57675 * @param {import("./Feature.js").ReadOptions} [options] Read options. 57676 * @protected 57677 * @return {import("../Feature.js").default} Feature. 57678 */ 57679 readFeatureFromObject(object, options) { 57680 return util_abstract(); 57681 } 57682 57683 /** 57684 * @abstract 57685 * @param {Object} object Object. 57686 * @param {import("./Feature.js").ReadOptions} [options] Read options. 57687 * @protected 57688 * @return {Array<import("../Feature.js").default>} Features. 57689 */ 57690 readFeaturesFromObject(object, options) { 57691 return util_abstract(); 57692 } 57693 57694 /** 57695 * Read a geometry. 57696 * 57697 * @param {ArrayBuffer|Document|Element|Object|string} source Source. 57698 * @param {import("./Feature.js").ReadOptions} [options] Read options. 57699 * @return {import("../geom/Geometry.js").default} Geometry. 57700 * @api 57701 */ 57702 readGeometry(source, options) { 57703 return this.readGeometryFromObject( 57704 getObject(source), 57705 this.getReadOptions(source, options) 57706 ); 57707 } 57708 57709 /** 57710 * @abstract 57711 * @param {Object} object Object. 57712 * @param {import("./Feature.js").ReadOptions} [options] Read options. 57713 * @protected 57714 * @return {import("../geom/Geometry.js").default} Geometry. 57715 */ 57716 readGeometryFromObject(object, options) { 57717 return util_abstract(); 57718 } 57719 57720 /** 57721 * Read the projection. 57722 * 57723 * @param {ArrayBuffer|Document|Element|Object|string} source Source. 57724 * @return {import("../proj/Projection.js").default} Projection. 57725 * @api 57726 */ 57727 readProjection(source) { 57728 return this.readProjectionFromObject(getObject(source)); 57729 } 57730 57731 /** 57732 * @abstract 57733 * @param {Object} object Object. 57734 * @protected 57735 * @return {import("../proj/Projection.js").default} Projection. 57736 */ 57737 readProjectionFromObject(object) { 57738 return util_abstract(); 57739 } 57740 57741 /** 57742 * Encode a feature as string. 57743 * 57744 * @param {import("../Feature.js").default} feature Feature. 57745 * @param {import("./Feature.js").WriteOptions} [options] Write options. 57746 * @return {string} Encoded feature. 57747 * @api 57748 */ 57749 writeFeature(feature, options) { 57750 return JSON.stringify(this.writeFeatureObject(feature, options)); 57751 } 57752 57753 /** 57754 * @abstract 57755 * @param {import("../Feature.js").default} feature Feature. 57756 * @param {import("./Feature.js").WriteOptions} [options] Write options. 57757 * @return {Object} Object. 57758 */ 57759 writeFeatureObject(feature, options) { 57760 return util_abstract(); 57761 } 57762 57763 /** 57764 * Encode an array of features as string. 57765 * 57766 * @param {Array<import("../Feature.js").default>} features Features. 57767 * @param {import("./Feature.js").WriteOptions} [options] Write options. 57768 * @return {string} Encoded features. 57769 * @api 57770 */ 57771 writeFeatures(features, options) { 57772 return JSON.stringify(this.writeFeaturesObject(features, options)); 57773 } 57774 57775 /** 57776 * @abstract 57777 * @param {Array<import("../Feature.js").default>} features Features. 57778 * @param {import("./Feature.js").WriteOptions} [options] Write options. 57779 * @return {Object} Object. 57780 */ 57781 writeFeaturesObject(features, options) { 57782 return util_abstract(); 57783 } 57784 57785 /** 57786 * Encode a geometry as string. 57787 * 57788 * @param {import("../geom/Geometry.js").default} geometry Geometry. 57789 * @param {import("./Feature.js").WriteOptions} [options] Write options. 57790 * @return {string} Encoded geometry. 57791 * @api 57792 */ 57793 writeGeometry(geometry, options) { 57794 return JSON.stringify(this.writeGeometryObject(geometry, options)); 57795 } 57796 57797 /** 57798 * @abstract 57799 * @param {import("../geom/Geometry.js").default} geometry Geometry. 57800 * @param {import("./Feature.js").WriteOptions} [options] Write options. 57801 * @return {Object} Object. 57802 */ 57803 writeGeometryObject(geometry, options) { 57804 return util_abstract(); 57805 } 57806} 57807 57808/**
57809 * @param {Document|Element|Object|string} source Source. 57810 * @return {Object} Object. 57811 */ 57812function getObject(source) { 57813 if (typeof source === 'string') { 57814 const object = JSON.parse(source); 57815 return object ? /** @type {Object} */ (object) : null; 57816 } else if (source !== null) { 57817 return source; 57818 } else { 57819 return null; 57820 } 57821} 57822 57823/* harmony default export */ const format_JSONFeature = (JSONFeature); 57824 57825;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/interpolate.js 57826/** 57827 * @module ol/geom/flat/interpolate 57828 */ 57829 57830 57831 57832/** 57833 * @param {Array<number>} flatCoordinates Flat coordinates. 57834 * @param {number} offset Offset. 57835 * @param {number} end End. 57836 * @param {number} stride Stride. 57837 * @param {number} fraction Fraction. 57838 * @param {Array<number>} [dest] Destination. 57839 * @param {number} [dimension] Destination dimension (default is `2`) 57840 * @return {Array<number>} Destination. 57841 */ 57842function interpolatePoint( 57843 flatCoordinates, 57844 offset, 57845 end, 57846 stride, 57847 fraction, 57848 dest, 57849 dimension 57850) { 57851 let o, t; 57852 const n = (end - offset) / stride; 57853 if (n === 1) { 57854 o = offset; 57855 } else if (n === 2) { 57856 o = offset; 57857 t = fraction; 57858 } else if (n !== 0) { 57859 let x1 = flatCoordinates[offset]; 57860 let y1 = flatCoordinates[offset + 1]; 57861 let length = 0; 57862 const cumulativeLengths = [0]; 57863 for (let i = offset + stride; i < end; i += stride) { 57864 const x2 = flatCoordinates[i]; 57865 const y2 = flatCoordinates[i + 1]; 57866 length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); 57867 cumulativeLengths.push(length); 57868 x1 = x2; 57869 y1 = y2; 57870 } 57871 const target = fraction * length; 57872 const index = binarySearch(cumulativeLengths, target); 57873 if (index < 0) { 57874 t = 57875 (target - cumulativeLengths[-index - 2]) / 57876 (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]); 57877 o = offset + (-index - 2) * stride; 57878 } else { 57879 o = offset + index * stride; 57880 } 57881 } 57882 dimension = dimension > 1 ? dimension : 2; 57883 dest = dest ? dest : new Array(dimension); 57884 for (let i = 0; i < dimension; ++i) { 57885 dest[i] = 57886 o === undefined 57887 ? NaN 57888 : t === undefined 57889 ? flatCoordinates[o + i] 57890 : lerp(flatCoordinates[o + i], flatCoordinates[o + stride + i], t); 57891 } 57892 return dest; 57893} 57894 57895/** 57896 * @param {Array<number>} flatCoordinates Flat coordinates. 57897 * @param {number} offset Offset. 57898 * @param {number} end End. 57899 * @param {number} stride Stride. 57900 * @param {number} m M. 57901 * @param {boolean} extrapolate Extrapolate. 57902 * @return {import("../../coordinate.js").Coordinate|null} Coordinate. 57903 */ 57904function lineStringCoordinateAtM( 57905 flatCoordinates, 57906 offset, 57907 end, 57908 stride, 57909 m, 57910 extrapolate 57911) { 57912 if (end == offset) { 57913 return null; 57914 } 57915 let coordinate; 57916 if (m < flatCoordinates[offset + stride - 1]) { 57917 if (extrapolate) { 57918 coordinate = flatCoordinates.slice(offset, offset + stride); 57919 coordinate[stride - 1] = m; 57920 return coordinate; 57921 } else { 57922 return null; 57923 } 57924 } else if (flatCoordinates[end - 1] < m) { 57925 if (extrapolate) { 57926 coordinate = flatCoordinates.slice(end - stride, end); 57927 coordinate[stride - 1] = m; 57928 return coordinate; 57929 } else { 57930 return null; 57931 } 57932 } 57933 // FIXME use O(1) search 57934 if (m == flatCoordinates[offset + stride - 1]) { 57935 return flatCoordinates.slice(offset, offset + stride); 57936 } 57937 let lo = offset / stride; 57938 let hi = end / stride; 57939 while (lo < hi) { 57940 const mid = (lo + hi) >> 1; 57941 if (m < flatCoordinates[(mid + 1) * stride - 1]) { 57942 hi = mid; 57943 } else { 57944 lo = mid + 1; 57945 } 57946 } 57947 const m0 = flatCoordinates[lo * stride - 1]; 57948 if (m == m0) { 57949 return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride); 57950 } 57951 const m1 = flatCoordinates[(lo + 1) * stride - 1]; 57952 const t = (m - m0) / (m1 - m0); 57953 coordinate = []; 57954 for (let i = 0; i < stride - 1; ++i) { 57955 coordinate.push( 57956 lerp( 57957 flatCoordinates[(lo - 1) * stride + i], 57958 flatCoordinates[lo * stride + i], 57959 t 57960 ) 57961 ); 57962 } 57963 coordinate.push(m); 57964 return coordinate; 57965} 57966 57967/** 57968 * @param {Array<number>} flatCoordinates Flat coordinates. 57969 * @param {number} offset Offset. 57970 * @param {Array<number>} ends Ends. 57971 * @param {number} stride Stride. 57972 * @param {number} m M. 57973 * @param {boolean} extrapolate Extrapolate. 57974 * @param {boolean} interpolate Interpolate. 57975 * @return {import("../../coordinate.js").Coordinate|null} Coordinate. 57976 */ 57977function lineStringsCoordinateAtM( 57978 flatCoordinates, 57979 offset, 57980 ends, 57981 stride, 57982 m, 57983 extrapolate, 57984 interpolate 57985) { 57986 if (interpolate) { 57987 return lineStringCoordinateAtM( 57988 flatCoordinates, 57989 offset, 57990 ends[ends.length - 1],
57991 stride, 57992 m, 57993 extrapolate 57994 ); 57995 } 57996 let coordinate; 57997 if (m < flatCoordinates[stride - 1]) { 57998 if (extrapolate) { 57999 coordinate = flatCoordinates.slice(0, stride); 58000 coordinate[stride - 1] = m; 58001 return coordinate; 58002 } else { 58003 return null; 58004 } 58005 } 58006 if (flatCoordinates[flatCoordinates.length - 1] < m) { 58007 if (extrapolate) { 58008 coordinate = flatCoordinates.slice(flatCoordinates.length - stride); 58009 coordinate[stride - 1] = m; 58010 return coordinate; 58011 } else { 58012 return null; 58013 } 58014 } 58015 for (let i = 0, ii = ends.length; i < ii; ++i) { 58016 const end = ends[i]; 58017 if (offset == end) { 58018 continue; 58019 } 58020 if (m < flatCoordinates[offset + stride - 1]) { 58021 return null; 58022 } else if (m <= flatCoordinates[end - 1]) { 58023 return lineStringCoordinateAtM( 58024 flatCoordinates, 58025 offset, 58026 end, 58027 stride, 58028 m, 58029 false 58030 ); 58031 } 58032 offset = end; 58033 } 58034 return null; 58035} 58036 58037;// CONCATENATED MODULE: ./node_modules/ol/geom/LineString.js 58038/** 58039 * @module ol/geom/LineString 58040 */ 58041 58042 58043 58044 58045 58046 58047 58048 58049 58050 58051 58052 58053/** 58054 * @classdesc 58055 * Linestring geometry. 58056 * 58057 * @api 58058 */ 58059class LineString extends geom_SimpleGeometry { 58060 /** 58061 * @param {Array<import("../coordinate.js").Coordinate>|Array<number>} coordinates Coordinates. 58062 * For internal use, flat coordinates in combination with `layout` are also accepted. 58063 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 58064 */ 58065 constructor(coordinates, layout) { 58066 super(); 58067 58068 /** 58069 * @private 58070 * @type {import("../coordinate.js").Coordinate} 58071 */ 58072 this.flatMidpoint_ = null; 58073 58074 /** 58075 * @private 58076 * @type {number} 58077 */ 58078 this.flatMidpointRevision_ = -1; 58079 58080 /** 58081 * @private 58082 * @type {number} 58083 */ 58084 this.maxDelta_ = -1; 58085 58086 /** 58087 * @private 58088 * @type {number} 58089 */ 58090 this.maxDeltaRevision_ = -1; 58091 58092 if (layout !== undefined && !Array.isArray(coordinates[0])) { 58093 this.setFlatCoordinates( 58094 layout, 58095 /** @type {Array<number>} */ (coordinates) 58096 ); 58097 } else { 58098 this.setCoordinates( 58099 /** @type {Array<import("../coordinate.js").Coordinate>} */ ( 58100 coordinates 58101 ), 58102 layout 58103 ); 58104 } 58105 } 58106 58107 /** 58108 * Append the passed coordinate to the coordinates of the linestring. 58109 * @param {import("../coordinate.js").Coordinate} coordinate Coordinate. 58110 * @api 58111 */ 58112 appendCoordinate(coordinate) { 58113 if (!this.flatCoordinates) { 58114 this.flatCoordinates = coordinate.slice(); 58115 } else { 58116 array_extend(this.flatCoordinates, coordinate); 58117 } 58118 this.changed(); 58119 } 58120 58121 /** 58122 * Make a complete copy of the geometry. 58123 * @return {!LineString} Clone. 58124 * @api 58125 */ 58126 clone() { 58127 const lineString = new LineString( 58128 this.flatCoordinates.slice(), 58129 this.layout 58130 ); 58131 lineString.applyProperties(this); 58132 return lineString; 58133 } 58134 58135 /** 58136 * @param {number} x X. 58137 * @param {number} y Y. 58138 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 58139 * @param {number} minSquaredDistance Minimum squared distance. 58140 * @return {number} Minimum squared distance. 58141 */ 58142 closestPointXY(x, y, closestPoint, minSquaredDistance) { 58143 if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) { 58144 return minSquaredDistance; 58145 } 58146 if (this.maxDeltaRevision_ != this.getRevision()) { 58147 this.maxDelta_ = Math.sqrt( 58148 maxSquaredDelta( 58149 this.flatCoordinates, 58150 0, 58151 this.flatCoordinates.length, 58152 this.stride, 58153 0 58154 ) 58155 ); 58156 this.maxDeltaRevision_ = this.getRevision(); 58157 } 58158 return assignClosestPoint( 58159 this.flatCoordinates, 58160 0, 58161 this.flatCoordinates.length, 58162 this.stride, 58163 this.maxDelta_, 58164 false, 58165 x, 58166 y, 58167 closestPoint, 58168 minSquaredDistance 58169 ); 58170 } 58171 58172 /** 58173 * Iterate over each segment, calling the provided callback. 58174 * If the callback returns a truthy value the function returns that 58175 * value immediately. Otherwise the function returns `false`. 58176 * 58177 * @param {function(this: S, import("../coordinate.js").Coordinate, import("../coordinate.js").Coordinate): T} callback Function 58178 * called for each segment. The function will receive two arguments, the start and end coordinates of the segment. 58179 * @return {T|boolean} Value. 58180 * @template T,S 58181 * @api 58182 */ 58183 forEachSegment(callback) { 58184 return forEach( 58185 this.flatCoordinates, 58186 0, 58187 this.flatCoordinates.length, 58188 this.stride, 58189 callback 58190 ); 58191 } 58192 58193 /** 58194 * Returns the coordinate at `m` using linear interpolation, or `null` if no 58195 * such coordinate exists. 58196 * 58197 * `extrapolate` controls extrapolation beyond the range of Ms in the 58198 * MultiLineString. If `extrapolate` is `true` then Ms less than the first 58199 * M will return the first coordinate and Ms greater than the last M will 58200 * return the last coordinate. 58201 * 58202 * @param {number} m M. 58203 * @param {boolean} [extrapolate] Extrapolate. Default is `false`. 58204 * @return {import("../coordinate.js").Coordinate|null} Coordinate. 58205 * @api 58206 */ 58207 getCoordinateAtM(m, extrapolate) { 58208 if (this.layout != 'XYM' && this.layout != 'XYZM') { 58209 return null; 58210 } 58211 extrapolate = extrapolate !== undefined ? extrapolate : false;
58212 return lineStringCoordinateAtM( 58213 this.flatCoordinates, 58214 0, 58215 this.flatCoordinates.length, 58216 this.stride, 58217 m, 58218 extrapolate 58219 ); 58220 } 58221 58222 /** 58223 * Return the coordinates of the linestring. 58224 * @return {Array<import("../coordinate.js").Coordinate>} Coordinates. 58225 * @api 58226 */ 58227 getCoordinates() { 58228 return inflateCoordinates( 58229 this.flatCoordinates, 58230 0, 58231 this.flatCoordinates.length, 58232 this.stride 58233 ); 58234 } 58235 58236 /** 58237 * Return the coordinate at the provided fraction along the linestring. 58238 * The `fraction` is a number between 0 and 1, where 0 is the start of the 58239 * linestring and 1 is the end. 58240 * @param {number} fraction Fraction. 58241 * @param {import("../coordinate.js").Coordinate} [dest] Optional coordinate whose values will 58242 * be modified. If not provided, a new coordinate will be returned. 58243 * @return {import("../coordinate.js").Coordinate} Coordinate of the interpolated point. 58244 * @api 58245 */ 58246 getCoordinateAt(fraction, dest) { 58247 return interpolatePoint( 58248 this.flatCoordinates, 58249 0, 58250 this.flatCoordinates.length, 58251 this.stride, 58252 fraction, 58253 dest, 58254 this.stride 58255 ); 58256 } 58257 58258 /** 58259 * Return the length of the linestring on projected plane. 58260 * @return {number} Length (on projected plane). 58261 * @api 58262 */ 58263 getLength() { 58264 return lineStringLength( 58265 this.flatCoordinates, 58266 0, 58267 this.flatCoordinates.length, 58268 this.stride 58269 ); 58270 } 58271 58272 /** 58273 * @return {Array<number>} Flat midpoint. 58274 */ 58275 getFlatMidpoint() { 58276 if (this.flatMidpointRevision_ != this.getRevision()) { 58277 this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_); 58278 this.flatMidpointRevision_ = this.getRevision(); 58279 } 58280 return this.flatMidpoint_; 58281 } 58282 58283 /** 58284 * @param {number} squaredTolerance Squared tolerance. 58285 * @return {LineString} Simplified LineString. 58286 * @protected 58287 */ 58288 getSimplifiedGeometryInternal(squaredTolerance) { 58289 const simplifiedFlatCoordinates = []; 58290 simplifiedFlatCoordinates.length = douglasPeucker( 58291 this.flatCoordinates, 58292 0, 58293 this.flatCoordinates.length, 58294 this.stride, 58295 squaredTolerance, 58296 simplifiedFlatCoordinates, 58297 0 58298 ); 58299 return new LineString(simplifiedFlatCoordinates, 'XY'); 58300 } 58301 58302 /** 58303 * Get the type of this geometry. 58304 * @return {import("./Geometry.js").Type} Geometry type. 58305 * @api 58306 */ 58307 getType() { 58308 return 'LineString'; 58309 } 58310 58311 /** 58312 * Test if the geometry and the passed extent intersect. 58313 * @param {import("../extent.js").Extent} extent Extent. 58314 * @return {boolean} `true` if the geometry and the extent intersect. 58315 * @api 58316 */ 58317 intersectsExtent(extent) { 58318 return intersectsLineString( 58319 this.flatCoordinates, 58320 0, 58321 this.flatCoordinates.length, 58322 this.stride, 58323 extent 58324 ); 58325 } 58326 58327 /** 58328 * Set the coordinates of the linestring. 58329 * @param {!Array<import("../coordinate.js").Coordinate>} coordinates Coordinates. 58330 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 58331 * @api 58332 */ 58333 setCoordinates(coordinates, layout) { 58334 this.setLayout(layout, coordinates, 1); 58335 if (!this.flatCoordinates) { 58336 this.flatCoordinates = []; 58337 } 58338 this.flatCoordinates.length = deflateCoordinates( 58339 this.flatCoordinates, 58340 0, 58341 coordinates, 58342 this.stride 58343 ); 58344 this.changed(); 58345 } 58346} 58347 58348/* harmony default export */ const geom_LineString = (LineString); 58349 58350;// CONCATENATED MODULE: ./node_modules/ol/geom/MultiLineString.js 58351/** 58352 * @module ol/geom/MultiLineString 58353 */ 58354 58355 58356 58357 58358 58359 58360 58361 58362 58363 58364 58365/** 58366 * @classdesc 58367 * Multi-linestring geometry. 58368 * 58369 * @api 58370 */ 58371class MultiLineString extends geom_SimpleGeometry { 58372 /** 58373 * @param {Array<Array<import("../coordinate.js").Coordinate>|LineString>|Array<number>} coordinates 58374 * Coordinates or LineString geometries. (For internal use, flat coordinates in 58375 * combination with `layout` and `ends` are also accepted.) 58376 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 58377 * @param {Array<number>} [ends] Flat coordinate ends for internal use. 58378 */ 58379 constructor(coordinates, layout, ends) { 58380 super(); 58381 58382 /** 58383 * @type {Array<number>} 58384 * @private 58385 */ 58386 this.ends_ = []; 58387 58388 /** 58389 * @private 58390 * @type {number} 58391 */ 58392 this.maxDelta_ = -1; 58393 58394 /** 58395 * @private 58396 * @type {number} 58397 */ 58398 this.maxDeltaRevision_ = -1; 58399 58400 if (Array.isArray(coordinates[0])) { 58401 this.setCoordinates( 58402 /** @type {Array<Array<import("../coordinate.js").Coordinate>>} */ ( 58403 coordinates 58404 ), 58405 layout 58406 ); 58407 } else if (layout !== undefined && ends) { 58408 this.setFlatCoordinates( 58409 layout, 58410 /** @type {Array<number>} */ (coordinates) 58411 ); 58412 this.ends_ = ends; 58413 } else { 58414 let layout = this.getLayout(); 58415 const lineStrings = /** @type {Array<LineString>} */ (coordinates); 58416 const flatCoordinates = []; 58417 const ends = []; 58418 for (let i = 0, ii = lineStrings.length; i < ii; ++i) { 58419 const lineString = lineStrings[i]; 58420 if (i === 0) { 58421 layout = lineString.getLayout(); 58422 } 58423 array_extend(flatCoordinates, lineString.getFlatCoordinates()); 58424 ends.push(flatCoordinates.length); 58425 } 58426 this.setFlatCoordinates(layout, flatCoordinates); 58427 this.ends_ = ends; 58428 } 58429 } 58430 58431 /** 58432 * Append the passed linestring to the multilinestring. 58433 * @param {LineString} lineString LineString. 58434 * @api 58435 */ 58436 appendLineString(lineString) { 58437 if (!this.flatCoordinates) { 58438 this.flatCoordinates = lineString.getFlatCoordinates().slice(); 58439 } else { 58440 array_extend(this.flatCoordinates, lineString.getFlatCoordinates().slice()); 58441 } 58442 this.ends_.push(this.flatCoordinates.length); 58443 this.changed(); 58444 } 58445 58446 /** 58447 * Make a complete copy of the geometry. 58448 * @return {!MultiLineString} Clone. 58449 * @api 58450 */ 58451 clone() { 58452 const multiLineString = new MultiLineString( 58453 this.flatCoordinates.slice(), 58454 this.layout, 58455 this.ends_.slice() 58456 ); 58457 multiLineString.applyProperties(this); 58458 return multiLineString; 58459 } 58460 58461 /** 58462 * @param {number} x X. 58463 * @param {number} y Y. 58464 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 58465 * @param {number} minSquaredDistance Minimum squared distance. 58466 * @return {number} Minimum squared distance. 58467 */ 58468 closestPointXY(x, y, closestPoint, minSquaredDistance) { 58469 if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) { 58470 return minSquaredDistance; 58471 } 58472 if (this.maxDeltaRevision_ != this.getRevision()) { 58473 this.maxDelta_ = Math.sqrt( 58474 arrayMaxSquaredDelta( 58475 this.flatCoordinates, 58476 0, 58477 this.ends_, 58478 this.stride, 58479 0 58480 ) 58481 ); 58482 this.maxDeltaRevision_ = this.getRevision(); 58483 } 58484 return assignClosestArrayPoint( 58485 this.flatCoordinates, 58486 0, 58487 this.ends_, 58488 this.stride, 58489 this.maxDelta_, 58490 false, 58491 x, 58492 y, 58493 closestPoint, 58494 minSquaredDistance 58495 ); 58496 } 58497 58498 /** 58499 * Returns the coordinate at `m` using linear interpolation, or `null` if no 58500 * such coordinate exists. 58501 * 58502 * `extrapolate` controls extrapolation beyond the range of Ms in the 58503 * MultiLineString. If `extrapolate` is `true` then Ms less than the first 58504 * M will return the first coordinate and Ms greater than the last M will 58505 * return the last coordinate. 58506 * 58507 * `interpolate` controls interpolation between consecutive LineStrings 58508 * within the MultiLineString. If `interpolate` is `true` the coordinates 58509 * will be linearly interpolated between the last coordinate of one LineString 58510 * and the first coordinate of the next LineString. If `interpolate` is 58511 * `false` then the function will return `null` for Ms falling between 58512 * LineStrings. 58513 * 58514 * @param {number} m M. 58515 * @param {boolean} [extrapolate] Extrapolate. Default is `false`. 58516 * @param {boolean} [interpolate] Interpolate. Default is `false`. 58517 * @return {import("../coordinate.js").Coordinate|null} Coordinate. 58518 * @api 58519 */ 58520 getCoordinateAtM(m, extrapolate, interpolate) { 58521 if ( 58522 (this.layout != 'XYM' && this.layout != 'XYZM') || 58523 this.flatCoordinates.length === 0 58524 ) { 58525 return null; 58526 } 58527 extrapolate = extrapolate !== undefined ? extrapolate : false;
vendor: 6,135 bytes, lines 58528-58781
58528 interpolate = interpolate !== undefined ? interpolate : false; 58529 return lineStringsCoordinateAtM( 58530 this.flatCoordinates, 58531 0, 58532 this.ends_, 58533 this.stride, 58534 m, 58535 extrapolate, 58536 interpolate 58537 ); 58538 } 58539 58540 /** 58541 * Return the coordinates of the multilinestring. 58542 * @return {Array<Array<import("../coordinate.js").Coordinate>>} Coordinates. 58543 * @api 58544 */ 58545 getCoordinates() { 58546 return inflateCoordinatesArray( 58547 this.flatCoordinates, 58548 0, 58549 this.ends_, 58550 this.stride 58551 ); 58552 } 58553 58554 /** 58555 * @return {Array<number>} Ends. 58556 */ 58557 getEnds() { 58558 return this.ends_; 58559 } 58560 58561 /** 58562 * Return the linestring at the specified index. 58563 * @param {number} index Index. 58564 * @return {LineString} LineString. 58565 * @api 58566 */ 58567 getLineString(index) { 58568 if (index < 0 || this.ends_.length <= index) { 58569 return null; 58570 } 58571 return new geom_LineString( 58572 this.flatCoordinates.slice( 58573 index === 0 ? 0 : this.ends_[index - 1], 58574 this.ends_[index] 58575 ), 58576 this.layout 58577 ); 58578 } 58579 58580 /** 58581 * Return the linestrings of this multilinestring. 58582 * @return {Array<LineString>} LineStrings. 58583 * @api 58584 */ 58585 getLineStrings() { 58586 const flatCoordinates = this.flatCoordinates; 58587 const ends = this.ends_; 58588 const layout = this.layout; 58589 /** @type {Array<LineString>} */ 58590 const lineStrings = []; 58591 let offset = 0; 58592 for (let i = 0, ii = ends.length; i < ii; ++i) { 58593 const end = ends[i]; 58594 const lineString = new geom_LineString( 58595 flatCoordinates.slice(offset, end), 58596 layout 58597 ); 58598 lineStrings.push(lineString); 58599 offset = end; 58600 } 58601 return lineStrings; 58602 } 58603 58604 /** 58605 * @return {Array<number>} Flat midpoints. 58606 */ 58607 getFlatMidpoints() { 58608 const midpoints = []; 58609 const flatCoordinates = this.flatCoordinates; 58610 let offset = 0; 58611 const ends = this.ends_; 58612 const stride = this.stride; 58613 for (let i = 0, ii = ends.length; i < ii; ++i) { 58614 const end = ends[i]; 58615 const midpoint = interpolatePoint( 58616 flatCoordinates, 58617 offset, 58618 end, 58619 stride, 58620 0.5 58621 ); 58622 array_extend(midpoints, midpoint); 58623 offset = end; 58624 } 58625 return midpoints; 58626 } 58627 58628 /** 58629 * @param {number} squaredTolerance Squared tolerance. 58630 * @return {MultiLineString} Simplified MultiLineString. 58631 * @protected 58632 */ 58633 getSimplifiedGeometryInternal(squaredTolerance) { 58634 const simplifiedFlatCoordinates = []; 58635 const simplifiedEnds = []; 58636 simplifiedFlatCoordinates.length = douglasPeuckerArray( 58637 this.flatCoordinates, 58638 0, 58639 this.ends_, 58640 this.stride, 58641 squaredTolerance, 58642 simplifiedFlatCoordinates, 58643 0, 58644 simplifiedEnds 58645 ); 58646 return new MultiLineString(simplifiedFlatCoordinates, 'XY', simplifiedEnds); 58647 } 58648 58649 /** 58650 * Get the type of this geometry. 58651 * @return {import("./Geometry.js").Type} Geometry type. 58652 * @api 58653 */ 58654 getType() { 58655 return 'MultiLineString'; 58656 } 58657 58658 /** 58659 * Test if the geometry and the passed extent intersect. 58660 * @param {import("../extent.js").Extent} extent Extent. 58661 * @return {boolean} `true` if the geometry and the extent intersect. 58662 * @api 58663 */ 58664 intersectsExtent(extent) { 58665 return intersectsLineStringArray( 58666 this.flatCoordinates, 58667 0, 58668 this.ends_, 58669 this.stride, 58670 extent 58671 ); 58672 } 58673 58674 /** 58675 * Set the coordinates of the multilinestring. 58676 * @param {!Array<Array<import("../coordinate.js").Coordinate>>} coordinates Coordinates. 58677 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 58678 * @api 58679 */ 58680 setCoordinates(coordinates, layout) { 58681 this.setLayout(layout, coordinates, 2); 58682 if (!this.flatCoordinates) { 58683 this.flatCoordinates = []; 58684 } 58685 const ends = deflateCoordinatesArray( 58686 this.flatCoordinates, 58687 0, 58688 coordinates, 58689 this.stride, 58690 this.ends_ 58691 ); 58692 this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1]; 58693 this.changed(); 58694 } 58695} 58696 58697/* harmony default export */ const geom_MultiLineString = (MultiLineString); 58698 58699;// CONCATENATED MODULE: ./node_modules/ol/geom/MultiPoint.js 58700/** 58701 * @module ol/geom/MultiPoint 58702 */ 58703 58704 58705 58706 58707 58708 58709 58710 58711/** 58712 * @classdesc 58713 * Multi-point geometry. 58714 * 58715 * @api 58716 */ 58717class MultiPoint extends geom_SimpleGeometry { 58718 /** 58719 * @param {Array<import("../coordinate.js").Coordinate>|Array<number>} coordinates Coordinates. 58720 * For internal use, flat coordinates in combination with `layout` are also accepted. 58721 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 58722 */ 58723 constructor(coordinates, layout) { 58724 super(); 58725 if (layout && !Array.isArray(coordinates[0])) { 58726 this.setFlatCoordinates( 58727 layout, 58728 /** @type {Array<number>} */ (coordinates) 58729 ); 58730 } else { 58731 this.setCoordinates( 58732 /** @type {Array<import("../coordinate.js").Coordinate>} */ ( 58733 coordinates 58734 ), 58735 layout 58736 ); 58737 } 58738 } 58739 58740 /** 58741 * Append the passed point to this multipoint. 58742 * @param {Point} point Point. 58743 * @api 58744 */ 58745 appendPoint(point) { 58746 if (!this.flatCoordinates) { 58747 this.flatCoordinates = point.getFlatCoordinates().slice(); 58748 } else { 58749 array_extend(this.flatCoordinates, point.getFlatCoordinates()); 58750 } 58751 this.changed(); 58752 } 58753 58754 /** 58755 * Make a complete copy of the geometry. 58756 * @return {!MultiPoint} Clone. 58757 * @api 58758 */ 58759 clone() { 58760 const multiPoint = new MultiPoint( 58761 this.flatCoordinates.slice(), 58762 this.layout 58763 ); 58764 multiPoint.applyProperties(this); 58765 return multiPoint; 58766 } 58767 58768 /** 58769 * @param {number} x X. 58770 * @param {number} y Y. 58771 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 58772 * @param {number} minSquaredDistance Minimum squared distance. 58773 * @return {number} Minimum squared distance. 58774 */ 58775 closestPointXY(x, y, closestPoint, minSquaredDistance) { 58776 if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) { 58777 return minSquaredDistance; 58778 } 58779 const flatCoordinates = this.flatCoordinates; 58780 const stride = this.stride; 58781 for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
58782 const squaredDistance = math_squaredDistance( 58783 x, 58784 y, 58785 flatCoordinates[i], 58786 flatCoordinates[i + 1] 58787 ); 58788 if (squaredDistance < minSquaredDistance) { 58789 minSquaredDistance = squaredDistance; 58790 for (let j = 0; j < stride; ++j) { 58791 closestPoint[j] = flatCoordinates[i + j]; 58792 } 58793 closestPoint.length = stride; 58794 } 58795 } 58796 return minSquaredDistance; 58797 } 58798 58799 /** 58800 * Return the coordinates of the multipoint. 58801 * @return {Array<import("../coordinate.js").Coordinate>} Coordinates. 58802 * @api 58803 */ 58804 getCoordinates() { 58805 return inflateCoordinates( 58806 this.flatCoordinates, 58807 0, 58808 this.flatCoordinates.length, 58809 this.stride 58810 ); 58811 } 58812 58813 /** 58814 * Return the point at the specified index. 58815 * @param {number} index Index. 58816 * @return {Point} Point. 58817 * @api 58818 */ 58819 getPoint(index) { 58820 const n = !this.flatCoordinates 58821 ? 0 58822 : this.flatCoordinates.length / this.stride; 58823 if (index < 0 || n <= index) { 58824 return null; 58825 } 58826 return new geom_Point( 58827 this.flatCoordinates.slice( 58828 index * this.stride, 58829 (index + 1) * this.stride 58830 ), 58831 this.layout 58832 ); 58833 } 58834 58835 /** 58836 * Return the points of this multipoint. 58837 * @return {Array<Point>} Points. 58838 * @api 58839 */ 58840 getPoints() { 58841 const flatCoordinates = this.flatCoordinates; 58842 const layout = this.layout; 58843 const stride = this.stride; 58844 /** @type {Array<Point>} */ 58845 const points = []; 58846 for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) { 58847 const point = new geom_Point(flatCoordinates.slice(i, i + stride), layout); 58848 points.push(point); 58849 } 58850 return points; 58851 } 58852 58853 /** 58854 * Get the type of this geometry. 58855 * @return {import("./Geometry.js").Type} Geometry type. 58856 * @api 58857 */ 58858 getType() { 58859 return 'MultiPoint'; 58860 } 58861 58862 /** 58863 * Test if the geometry and the passed extent intersect. 58864 * @param {import("../extent.js").Extent} extent Extent. 58865 * @return {boolean} `true` if the geometry and the extent intersect. 58866 * @api 58867 */ 58868 intersectsExtent(extent) { 58869 const flatCoordinates = this.flatCoordinates; 58870 const stride = this.stride; 58871 for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) { 58872 const x = flatCoordinates[i]; 58873 const y = flatCoordinates[i + 1]; 58874 if (containsXY(extent, x, y)) { 58875 return true; 58876 } 58877 } 58878 return false; 58879 } 58880 58881 /** 58882 * Set the coordinates of the multipoint. 58883 * @param {!Array<import("../coordinate.js").Coordinate>} coordinates Coordinates. 58884 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 58885 * @api 58886 */ 58887 setCoordinates(coordinates, layout) { 58888 this.setLayout(layout, coordinates, 1); 58889 if (!this.flatCoordinates) { 58890 this.flatCoordinates = []; 58891 } 58892 this.flatCoordinates.length = deflateCoordinates( 58893 this.flatCoordinates, 58894 0, 58895 coordinates, 58896 this.stride 58897 ); 58898 this.changed(); 58899 } 58900} 58901 58902/* harmony default export */ const geom_MultiPoint = (MultiPoint); 58903 58904;// CONCATENATED MODULE: ./node_modules/ol/geom/flat/center.js 58905/** 58906 * @module ol/geom/flat/center 58907 */ 58908 58909 58910/** 58911 * @param {Array<number>} flatCoordinates Flat coordinates. 58912 * @param {number} offset Offset. 58913 * @param {Array<Array<number>>} endss Endss. 58914 * @param {number} stride Stride. 58915 * @return {Array<number>} Flat centers. 58916 */ 58917function center_linearRingss(flatCoordinates, offset, endss, stride) { 58918 const flatCenters = []; 58919 let extent = createEmpty(); 58920 for (let i = 0, ii = endss.length; i < ii; ++i) { 58921 const ends = endss[i]; 58922 extent = createOrUpdateFromFlatCoordinates( 58923 flatCoordinates, 58924 offset, 58925 ends[0], 58926 stride 58927 ); 58928 flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2); 58929 offset = ends[ends.length - 1]; 58930 } 58931 return flatCenters; 58932} 58933 58934;// CONCATENATED MODULE: ./node_modules/ol/geom/MultiPolygon.js 58935/** 58936 * @module ol/geom/MultiPolygon 58937 */ 58938 58939 58940 58941 58942 58943 58944 58945 58946 58947 58948 58949 58950 58951 58952 58953 58954/** 58955 * @classdesc 58956 * Multi-polygon geometry. 58957 * 58958 * @api 58959 */ 58960class MultiPolygon extends geom_SimpleGeometry { 58961 /** 58962 * @param {Array<Array<Array<import("../coordinate.js").Coordinate>>|Polygon>|Array<number>} coordinates Coordinates. 58963 * For internal use, flat coordinates in combination with `layout` and `endss` are also accepted. 58964 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 58965 * @param {Array<Array<number>>} [endss] Array of ends for internal use with flat coordinates. 58966 */ 58967 constructor(coordinates, layout, endss) { 58968 super(); 58969 58970 /** 58971 * @type {Array<Array<number>>} 58972 * @private 58973 */ 58974 this.endss_ = []; 58975 58976 /** 58977 * @private 58978 * @type {number} 58979 */ 58980 this.flatInteriorPointsRevision_ = -1; 58981 58982 /** 58983 * @private 58984 * @type {Array<number>} 58985 */ 58986 this.flatInteriorPoints_ = null; 58987 58988 /** 58989 * @private 58990 * @type {number} 58991 */ 58992 this.maxDelta_ = -1; 58993 58994 /** 58995 * @private 58996 * @type {number} 58997 */ 58998 this.maxDeltaRevision_ = -1; 58999 59000 /** 59001 * @private 59002 * @type {number} 59003 */ 59004 this.orientedRevision_ = -1; 59005 59006 /** 59007 * @private 59008 * @type {Array<number>} 59009 */ 59010 this.orientedFlatCoordinates_ = null; 59011 59012 if (!endss && !Array.isArray(coordinates[0])) { 59013 let thisLayout = this.getLayout(); 59014 const polygons = /** @type {Array<Polygon>} */ (coordinates); 59015 const flatCoordinates = []; 59016 const thisEndss = []; 59017 for (let i = 0, ii = polygons.length; i < ii; ++i) { 59018 const polygon = polygons[i]; 59019 if (i === 0) { 59020 thisLayout = polygon.getLayout(); 59021 } 59022 const offset = flatCoordinates.length; 59023 const ends = polygon.getEnds(); 59024 for (let j = 0, jj = ends.length; j < jj; ++j) { 59025 ends[j] += offset; 59026 }
vendor: 13,004 bytes, lines 59027-59516
59027 array_extend(flatCoordinates, polygon.getFlatCoordinates()); 59028 thisEndss.push(ends); 59029 } 59030 layout = thisLayout; 59031 coordinates = flatCoordinates; 59032 endss = thisEndss; 59033 } 59034 if (layout !== undefined && endss) { 59035 this.setFlatCoordinates( 59036 layout, 59037 /** @type {Array<number>} */ (coordinates) 59038 ); 59039 this.endss_ = endss; 59040 } else { 59041 this.setCoordinates( 59042 /** @type {Array<Array<Array<import("../coordinate.js").Coordinate>>>} */ ( 59043 coordinates 59044 ), 59045 layout 59046 ); 59047 } 59048 } 59049 59050 /** 59051 * Append the passed polygon to this multipolygon. 59052 * @param {Polygon} polygon Polygon. 59053 * @api 59054 */ 59055 appendPolygon(polygon) { 59056 /** @type {Array<number>} */ 59057 let ends; 59058 if (!this.flatCoordinates) { 59059 this.flatCoordinates = polygon.getFlatCoordinates().slice(); 59060 ends = polygon.getEnds().slice(); 59061 this.endss_.push(); 59062 } else { 59063 const offset = this.flatCoordinates.length; 59064 array_extend(this.flatCoordinates, polygon.getFlatCoordinates()); 59065 ends = polygon.getEnds().slice(); 59066 for (let i = 0, ii = ends.length; i < ii; ++i) { 59067 ends[i] += offset; 59068 } 59069 } 59070 this.endss_.push(ends); 59071 this.changed(); 59072 } 59073 59074 /** 59075 * Make a complete copy of the geometry. 59076 * @return {!MultiPolygon} Clone. 59077 * @api 59078 */ 59079 clone() { 59080 const len = this.endss_.length; 59081 const newEndss = new Array(len); 59082 for (let i = 0; i < len; ++i) { 59083 newEndss[i] = this.endss_[i].slice(); 59084 } 59085 59086 const multiPolygon = new MultiPolygon( 59087 this.flatCoordinates.slice(), 59088 this.layout, 59089 newEndss 59090 ); 59091 multiPolygon.applyProperties(this); 59092 59093 return multiPolygon; 59094 } 59095 59096 /** 59097 * @param {number} x X. 59098 * @param {number} y Y. 59099 * @param {import("../coordinate.js").Coordinate} closestPoint Closest point. 59100 * @param {number} minSquaredDistance Minimum squared distance. 59101 * @return {number} Minimum squared distance. 59102 */ 59103 closestPointXY(x, y, closestPoint, minSquaredDistance) { 59104 if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) { 59105 return minSquaredDistance; 59106 } 59107 if (this.maxDeltaRevision_ != this.getRevision()) { 59108 this.maxDelta_ = Math.sqrt( 59109 multiArrayMaxSquaredDelta( 59110 this.flatCoordinates, 59111 0, 59112 this.endss_, 59113 this.stride, 59114 0 59115 ) 59116 ); 59117 this.maxDeltaRevision_ = this.getRevision(); 59118 } 59119 return assignClosestMultiArrayPoint( 59120 this.getOrientedFlatCoordinates(), 59121 0, 59122 this.endss_, 59123 this.stride, 59124 this.maxDelta_, 59125 true, 59126 x, 59127 y, 59128 closestPoint, 59129 minSquaredDistance 59130 ); 59131 } 59132 59133 /** 59134 * @param {number} x X. 59135 * @param {number} y Y. 59136 * @return {boolean} Contains (x, y). 59137 */ 59138 containsXY(x, y) { 59139 return linearRingssContainsXY( 59140 this.getOrientedFlatCoordinates(), 59141 0, 59142 this.endss_, 59143 this.stride, 59144 x, 59145 y 59146 ); 59147 } 59148 59149 /** 59150 * Return the area of the multipolygon on projected plane. 59151 * @return {number} Area (on projected plane). 59152 * @api 59153 */ 59154 getArea() { 59155 return linearRingss( 59156 this.getOrientedFlatCoordinates(), 59157 0, 59158 this.endss_, 59159 this.stride 59160 ); 59161 } 59162 59163 /** 59164 * Get the coordinate array for this geometry. This array has the structure 59165 * of a GeoJSON coordinate array for multi-polygons. 59166 * 59167 * @param {boolean} [right] Orient coordinates according to the right-hand 59168 * rule (counter-clockwise for exterior and clockwise for interior rings). 59169 * If `false`, coordinates will be oriented according to the left-hand rule 59170 * (clockwise for exterior and counter-clockwise for interior rings). 59171 * By default, coordinate orientation will depend on how the geometry was 59172 * constructed. 59173 * @return {Array<Array<Array<import("../coordinate.js").Coordinate>>>} Coordinates. 59174 * @api 59175 */ 59176 getCoordinates(right) { 59177 let flatCoordinates; 59178 if (right !== undefined) { 59179 flatCoordinates = this.getOrientedFlatCoordinates().slice(); 59180 orientLinearRingsArray( 59181 flatCoordinates, 59182 0, 59183 this.endss_, 59184 this.stride, 59185 right 59186 ); 59187 } else { 59188 flatCoordinates = this.flatCoordinates; 59189 } 59190 59191 return inflateMultiCoordinatesArray( 59192 flatCoordinates, 59193 0, 59194 this.endss_, 59195 this.stride 59196 ); 59197 } 59198 59199 /** 59200 * @return {Array<Array<number>>} Endss. 59201 */ 59202 getEndss() { 59203 return this.endss_; 59204 } 59205 59206 /** 59207 * @return {Array<number>} Flat interior points. 59208 */ 59209 getFlatInteriorPoints() { 59210 if (this.flatInteriorPointsRevision_ != this.getRevision()) { 59211 const flatCenters = center_linearRingss( 59212 this.flatCoordinates, 59213 0, 59214 this.endss_, 59215 this.stride 59216 ); 59217 this.flatInteriorPoints_ = getInteriorPointsOfMultiArray( 59218 this.getOrientedFlatCoordinates(), 59219 0, 59220 this.endss_, 59221 this.stride, 59222 flatCenters 59223 ); 59224 this.flatInteriorPointsRevision_ = this.getRevision(); 59225 } 59226 return this.flatInteriorPoints_; 59227 } 59228 59229 /** 59230 * Return the interior points as {@link module:ol/geom/MultiPoint~MultiPoint multipoint}. 59231 * @return {MultiPoint} Interior points as XYM coordinates, where M is 59232 * the length of the horizontal intersection that the point belongs to. 59233 * @api 59234 */ 59235 getInteriorPoints() { 59236 return new geom_MultiPoint(this.getFlatInteriorPoints().slice(), 'XYM'); 59237 } 59238 59239 /** 59240 * @return {Array<number>} Oriented flat coordinates. 59241 */ 59242 getOrientedFlatCoordinates() { 59243 if (this.orientedRevision_ != this.getRevision()) { 59244 const flatCoordinates = this.flatCoordinates; 59245 if ( 59246 linearRingssAreOriented(flatCoordinates, 0, this.endss_, this.stride) 59247 ) { 59248 this.orientedFlatCoordinates_ = flatCoordinates; 59249 } else { 59250 this.orientedFlatCoordinates_ = flatCoordinates.slice(); 59251 this.orientedFlatCoordinates_.length = orientLinearRingsArray( 59252 this.orientedFlatCoordinates_, 59253 0, 59254 this.endss_, 59255 this.stride 59256 ); 59257 } 59258 this.orientedRevision_ = this.getRevision(); 59259 } 59260 return this.orientedFlatCoordinates_; 59261 } 59262 59263 /** 59264 * @param {number} squaredTolerance Squared tolerance. 59265 * @return {MultiPolygon} Simplified MultiPolygon. 59266 * @protected 59267 */ 59268 getSimplifiedGeometryInternal(squaredTolerance) { 59269 const simplifiedFlatCoordinates = []; 59270 const simplifiedEndss = []; 59271 simplifiedFlatCoordinates.length = quantizeMultiArray( 59272 this.flatCoordinates, 59273 0, 59274 this.endss_, 59275 this.stride, 59276 Math.sqrt(squaredTolerance), 59277 simplifiedFlatCoordinates, 59278 0, 59279 simplifiedEndss 59280 ); 59281 return new MultiPolygon(simplifiedFlatCoordinates, 'XY', simplifiedEndss); 59282 } 59283 59284 /** 59285 * Return the polygon at the specified index. 59286 * @param {number} index Index. 59287 * @return {Polygon} Polygon. 59288 * @api 59289 */ 59290 getPolygon(index) { 59291 if (index < 0 || this.endss_.length <= index) { 59292 return null; 59293 } 59294 let offset; 59295 if (index === 0) { 59296 offset = 0; 59297 } else { 59298 const prevEnds = this.endss_[index - 1]; 59299 offset = prevEnds[prevEnds.length - 1]; 59300 } 59301 const ends = this.endss_[index].slice(); 59302 const end = ends[ends.length - 1]; 59303 if (offset !== 0) { 59304 for (let i = 0, ii = ends.length; i < ii; ++i) { 59305 ends[i] -= offset; 59306 } 59307 } 59308 return new geom_Polygon( 59309 this.flatCoordinates.slice(offset, end), 59310 this.layout, 59311 ends 59312 ); 59313 } 59314 59315 /** 59316 * Return the polygons of this multipolygon. 59317 * @return {Array<Polygon>} Polygons. 59318 * @api 59319 */ 59320 getPolygons() { 59321 const layout = this.layout; 59322 const flatCoordinates = this.flatCoordinates; 59323 const endss = this.endss_; 59324 const polygons = []; 59325 let offset = 0; 59326 for (let i = 0, ii = endss.length; i < ii; ++i) { 59327 const ends = endss[i].slice(); 59328 const end = ends[ends.length - 1]; 59329 if (offset !== 0) { 59330 for (let j = 0, jj = ends.length; j < jj; ++j) { 59331 ends[j] -= offset; 59332 } 59333 } 59334 const polygon = new geom_Polygon( 59335 flatCoordinates.slice(offset, end), 59336 layout, 59337 ends 59338 ); 59339 polygons.push(polygon); 59340 offset = end; 59341 } 59342 return polygons; 59343 } 59344 59345 /** 59346 * Get the type of this geometry. 59347 * @return {import("./Geometry.js").Type} Geometry type. 59348 * @api 59349 */ 59350 getType() { 59351 return 'MultiPolygon'; 59352 } 59353 59354 /** 59355 * Test if the geometry and the passed extent intersect. 59356 * @param {import("../extent.js").Extent} extent Extent. 59357 * @return {boolean} `true` if the geometry and the extent intersect. 59358 * @api 59359 */ 59360 intersectsExtent(extent) { 59361 return intersectsLinearRingMultiArray( 59362 this.getOrientedFlatCoordinates(), 59363 0, 59364 this.endss_, 59365 this.stride, 59366 extent 59367 ); 59368 } 59369 59370 /** 59371 * Set the coordinates of the multipolygon. 59372 * @param {!Array<Array<Array<import("../coordinate.js").Coordinate>>>} coordinates Coordinates. 59373 * @param {import("./Geometry.js").GeometryLayout} [layout] Layout. 59374 * @api 59375 */ 59376 setCoordinates(coordinates, layout) { 59377 this.setLayout(layout, coordinates, 3); 59378 if (!this.flatCoordinates) { 59379 this.flatCoordinates = []; 59380 } 59381 const endss = deflateMultiCoordinatesArray( 59382 this.flatCoordinates, 59383 0, 59384 coordinates, 59385 this.stride, 59386 this.endss_ 59387 ); 59388 if (endss.length === 0) { 59389 this.flatCoordinates.length = 0; 59390 } else { 59391 const lastEnds = endss[endss.length - 1]; 59392 this.flatCoordinates.length = 59393 lastEnds.length === 0 ? 0 : lastEnds[lastEnds.length - 1]; 59394 } 59395 this.changed(); 59396 } 59397} 59398 59399/* harmony default export */ const geom_MultiPolygon = (MultiPolygon); 59400 59401;// CONCATENATED MODULE: ./node_modules/ol/format/GeoJSON.js 59402/** 59403 * @module ol/format/GeoJSON 59404 */ 59405 59406 59407 59408 59409 59410 59411 59412 59413 59414 59415 59416 59417 59418 59419 59420/** 59421 * @typedef {import("geojson").GeoJSON} GeoJSONObject 59422 * @typedef {import("geojson").Feature} GeoJSONFeature 59423 * @typedef {import("geojson").FeatureCollection} GeoJSONFeatureCollection 59424 * @typedef {import("geojson").Geometry} GeoJSONGeometry 59425 * @typedef {import("geojson").Point} GeoJSONPoint 59426 * @typedef {import("geojson").LineString} GeoJSONLineString 59427 * @typedef {import("geojson").Polygon} GeoJSONPolygon 59428 * @typedef {import("geojson").MultiPoint} GeoJSONMultiPoint 59429 * @typedef {import("geojson").MultiLineString} GeoJSONMultiLineString 59430 * @typedef {import("geojson").MultiPolygon} GeoJSONMultiPolygon 59431 * @typedef {import("geojson").GeometryCollection} GeoJSONGeometryCollection 59432 */ 59433 59434/** 59435 * @typedef {Object} Options 59436 * @property {import("../proj.js").ProjectionLike} [dataProjection='EPSG:4326'] Default data projection. 59437 * @property {import("../proj.js").ProjectionLike} [featureProjection] Projection for features read or 59438 * written by the format. Options passed to read or write methods will take precedence. 59439 * @property {string} [geometryName] Geometry name to use when creating features. 59440 * @property {boolean} [extractGeometryName=false] Certain GeoJSON providers include 59441 * the geometry_name field in the feature GeoJSON. If set to `true` the GeoJSON reader 59442 * will look for that field to set the geometry name. If both this field is set to `true` 59443 * and a `geometryName` is provided, the `geometryName` will take precedence. 59444 */ 59445 59446/** 59447 * @classdesc 59448 * Feature format for reading and writing data in the GeoJSON format. 59449 * 59450 * @api 59451 */ 59452class GeoJSON extends format_JSONFeature { 59453 /** 59454 * @param {Options} [options] Options. 59455 */ 59456 constructor(options) { 59457 options = options ? options : {}; 59458 59459 super(); 59460 59461 /** 59462 * @type {import("../proj/Projection.js").default} 59463 */ 59464 this.dataProjection = proj_get( 59465 options.dataProjection ? options.dataProjection : 'EPSG:4326' 59466 ); 59467 59468 if (options.featureProjection) { 59469 /** 59470 * @type {import("../proj/Projection.js").default} 59471 */ 59472 this.defaultFeatureProjection = proj_get(options.featureProjection); 59473 } 59474 59475 /** 59476 * Name of the geometry attribute for features. 59477 * @type {string|undefined} 59478 * @private 59479 */ 59480 this.geometryName_ = options.geometryName; 59481 59482 /** 59483 * Look for the geometry name in the feature GeoJSON 59484 * @type {boolean|undefined} 59485 * @private 59486 */ 59487 this.extractGeometryName_ = options.extractGeometryName; 59488 59489 this.supportedMediaTypes = [ 59490 'application/geo+json', 59491 'application/vnd.geo+json', 59492 ]; 59493 } 59494 59495 /** 59496 * @param {Object} object Object. 59497 * @param {import("./Feature.js").ReadOptions} [options] Read options. 59498 * @protected 59499 * @return {import("../Feature.js").default} Feature. 59500 */ 59501 readFeatureFromObject(object, options) { 59502 /** 59503 * @type {GeoJSONFeature} 59504 */ 59505 let geoJSONFeature = null; 59506 if (object['type'] === 'Feature') { 59507 geoJSONFeature = /** @type {GeoJSONFeature} */ (object); 59508 } else { 59509 geoJSONFeature = { 59510 'type': 'Feature', 59511 'geometry': /** @type {GeoJSONGeometry} */ (object), 59512 'properties': null, 59513 }; 59514 } 59515 59516 const geometry = readGeometry(geoJSONFeature['geometry'], options);
59517 const feature = new ol_Feature(); 59518 if (this.geometryName_) { 59519 feature.setGeometryName(this.geometryName_); 59520 } else if ( 59521 this.extractGeometryName_ && 59522 'geometry_name' in geoJSONFeature !== undefined 59523 ) { 59524 feature.setGeometryName(geoJSONFeature['geometry_name']); 59525 } 59526 feature.setGeometry(geometry); 59527 59528 if ('id' in geoJSONFeature) { 59529 feature.setId(geoJSONFeature['id']); 59530 } 59531 59532 if (geoJSONFeature['properties']) { 59533 feature.setProperties(geoJSONFeature['properties'], true); 59534 } 59535 return feature; 59536 } 59537 59538 /** 59539 * @param {Object} object Object. 59540 * @param {import("./Feature.js").ReadOptions} [options] Read options. 59541 * @protected 59542 * @return {Array<Feature>} Features. 59543 */ 59544 readFeaturesFromObject(object, options) { 59545 const geoJSONObject = /** @type {GeoJSONObject} */ (object); 59546 /** @type {Array<import("../Feature.js").default>} */ 59547 let features = null; 59548 if (geoJSONObject['type'] === 'FeatureCollection') { 59549 const geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */ ( 59550 object 59551 ); 59552 features = []; 59553 const geoJSONFeatures = geoJSONFeatureCollection['features']; 59554 for (let i = 0, ii = geoJSONFeatures.length; i < ii; ++i) { 59555 features.push(this.readFeatureFromObject(geoJSONFeatures[i], options)); 59556 } 59557 } else { 59558 features = [this.readFeatureFromObject(object, options)]; 59559 } 59560 return features; 59561 } 59562 59563 /** 59564 * @param {GeoJSONGeometry} object Object. 59565 * @param {import("./Feature.js").ReadOptions} [options] Read options. 59566 * @protected 59567 * @return {import("../geom/Geometry.js").default} Geometry. 59568 */ 59569 readGeometryFromObject(object, options) { 59570 return readGeometry(object, options); 59571 } 59572 59573 /** 59574 * @param {Object} object Object. 59575 * @protected 59576 * @return {import("../proj/Projection.js").default} Projection. 59577 */ 59578 readProjectionFromObject(object) { 59579 const crs = object['crs']; 59580 let projection; 59581 if (crs) { 59582 if (crs['type'] == 'name') { 59583 projection = proj_get(crs['properties']['name']); 59584 } else if (crs['type'] === 'EPSG') { 59585 projection = proj_get('EPSG:' + crs['properties']['code']); 59586 } else { 59587 asserts_assert(false, 36); // Unknown SRS type 59588 } 59589 } else { 59590 projection = this.dataProjection; 59591 } 59592 return /** @type {import("../proj/Projection.js").default} */ (projection); 59593 } 59594 59595 /** 59596 * Encode a feature as a GeoJSON Feature object. 59597 * 59598 * @param {import("../Feature.js").default} feature Feature. 59599 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59600 * @return {GeoJSONFeature} Object. 59601 * @api 59602 */ 59603 writeFeatureObject(feature, options) { 59604 options = this.adaptOptions(options); 59605 59606 /** @type {GeoJSONFeature} */ 59607 const object = { 59608 'type': 'Feature', 59609 geometry: null, 59610 properties: null, 59611 }; 59612 59613 const id = feature.getId(); 59614 if (id !== undefined) { 59615 object.id = id; 59616 } 59617 59618 if (!feature.hasProperties()) { 59619 return object; 59620 } 59621 59622 const properties = feature.getProperties(); 59623 const geometry = feature.getGeometry(); 59624 if (geometry) { 59625 object.geometry = writeGeometry(geometry, options); 59626 59627 delete properties[feature.getGeometryName()]; 59628 } 59629 59630 if (!obj_isEmpty(properties)) { 59631 object.properties = properties; 59632 } 59633 59634 return object; 59635 } 59636 59637 /** 59638 * Encode an array of features as a GeoJSON object. 59639 * 59640 * @param {Array<import("../Feature.js").default>} features Features. 59641 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59642 * @return {GeoJSONFeatureCollection} GeoJSON Object. 59643 * @api 59644 */ 59645 writeFeaturesObject(features, options) { 59646 options = this.adaptOptions(options); 59647 const objects = []; 59648 for (let i = 0, ii = features.length; i < ii; ++i) { 59649 objects.push(this.writeFeatureObject(features[i], options)); 59650 } 59651 return { 59652 type: 'FeatureCollection', 59653 features: objects, 59654 }; 59655 } 59656 59657 /** 59658 * Encode a geometry as a GeoJSON object. 59659 * 59660 * @param {import("../geom/Geometry.js").default} geometry Geometry. 59661 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59662 * @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object. 59663 * @api 59664 */ 59665 writeGeometryObject(geometry, options) { 59666 return writeGeometry(geometry, this.adaptOptions(options)); 59667 } 59668} 59669 59670/** 59671 * @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object. 59672 * @param {import("./Feature.js").ReadOptions} [options] Read options. 59673 * @return {import("../geom/Geometry.js").default} Geometry. 59674 */ 59675function readGeometry(object, options) { 59676 if (!object) { 59677 return null; 59678 } 59679 59680 /** 59681 * @type {import("../geom/Geometry.js").default} 59682 */ 59683 let geometry; 59684 switch (object['type']) { 59685 case 'Point': { 59686 geometry = readPointGeometry(/** @type {GeoJSONPoint} */ (object)); 59687 break; 59688 } 59689 case 'LineString': { 59690 geometry = readLineStringGeometry( 59691 /** @type {GeoJSONLineString} */ (object) 59692 ); 59693 break; 59694 } 59695 case 'Polygon': { 59696 geometry = readPolygonGeometry(/** @type {GeoJSONPolygon} */ (object)); 59697 break; 59698 } 59699 case 'MultiPoint': { 59700 geometry = readMultiPointGeometry( 59701 /** @type {GeoJSONMultiPoint} */ (object) 59702 ); 59703 break; 59704 } 59705 case 'MultiLineString': { 59706 geometry = readMultiLineStringGeometry( 59707 /** @type {GeoJSONMultiLineString} */ (object) 59708 ); 59709 break; 59710 } 59711 case 'MultiPolygon': { 59712 geometry = readMultiPolygonGeometry( 59713 /** @type {GeoJSONMultiPolygon} */ (object) 59714 ); 59715 break; 59716 } 59717 case 'GeometryCollection': { 59718 geometry = readGeometryCollectionGeometry( 59719 /** @type {GeoJSONGeometryCollection} */ (object) 59720 ); 59721 break; 59722 } 59723 default: { 59724 throw new Error('Unsupported GeoJSON type: ' + object['type']); 59725 } 59726 } 59727 return transformGeometryWithOptions(geometry, false, options); 59728} 59729 59730/** 59731 * @param {GeoJSONGeometryCollection} object Object. 59732 * @param {import("./Feature.js").ReadOptions} [options] Read options. 59733 * @return {GeometryCollection} Geometry collection. 59734 */ 59735function readGeometryCollectionGeometry(object, options) { 59736 const geometries = object['geometries'].map( 59737 /** 59738 * @param {GeoJSONGeometry} geometry Geometry. 59739 * @return {import("../geom/Geometry.js").default} geometry Geometry. 59740 */ 59741 function (geometry) { 59742 return readGeometry(geometry, options); 59743 } 59744 ); 59745 return new geom_GeometryCollection(geometries); 59746} 59747 59748/** 59749 * @param {GeoJSONPoint} object Object. 59750 * @return {Point} Point. 59751 */ 59752function readPointGeometry(object) { 59753 return new geom_Point(object['coordinates']); 59754} 59755 59756/** 59757 * @param {GeoJSONLineString} object Object. 59758 * @return {LineString} LineString. 59759 */ 59760function readLineStringGeometry(object) { 59761 return new geom_LineString(object['coordinates']); 59762} 59763 59764/** 59765 * @param {GeoJSONMultiLineString} object Object. 59766 * @return {MultiLineString} MultiLineString. 59767 */ 59768function readMultiLineStringGeometry(object) { 59769 return new geom_MultiLineString(object['coordinates']); 59770} 59771 59772/** 59773 * @param {GeoJSONMultiPoint} object Object. 59774 * @return {MultiPoint} MultiPoint. 59775 */ 59776function readMultiPointGeometry(object) { 59777 return new geom_MultiPoint(object['coordinates']); 59778} 59779 59780/** 59781 * @param {GeoJSONMultiPolygon} object Object. 59782 * @return {MultiPolygon} MultiPolygon. 59783 */ 59784function readMultiPolygonGeometry(object) { 59785 return new geom_MultiPolygon(object['coordinates']); 59786} 59787 59788/** 59789 * @param {GeoJSONPolygon} object Object. 59790 * @return {Polygon} Polygon. 59791 */ 59792function readPolygonGeometry(object) { 59793 return new geom_Polygon(object['coordinates']); 59794} 59795 59796/** 59797 * @param {import("../geom/Geometry.js").default} geometry Geometry. 59798 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59799 * @return {GeoJSONGeometry} GeoJSON geometry. 59800 */ 59801function writeGeometry(geometry, options) { 59802 geometry = transformGeometryWithOptions(geometry, true, options); 59803 const type = geometry.getType(); 59804 59805 /** @type {GeoJSONGeometry} */ 59806 let geoJSON; 59807 switch (type) { 59808 case 'Point': { 59809 geoJSON = writePointGeometry(/** @type {Point} */ (geometry), options); 59810 break; 59811 } 59812 case 'LineString': { 59813 geoJSON = writeLineStringGeometry( 59814 /** @type {LineString} */ (geometry), 59815 options 59816 ); 59817 break; 59818 } 59819 case 'Polygon': { 59820 geoJSON = writePolygonGeometry( 59821 /** @type {Polygon} */ (geometry), 59822 options 59823 ); 59824 break; 59825 } 59826 case 'MultiPoint': { 59827 geoJSON = writeMultiPointGeometry( 59828 /** @type {MultiPoint} */ (geometry), 59829 options 59830 ); 59831 break; 59832 } 59833 case 'MultiLineString': { 59834 geoJSON = writeMultiLineStringGeometry( 59835 /** @type {MultiLineString} */ (geometry), 59836 options 59837 ); 59838 break; 59839 } 59840 case 'MultiPolygon': { 59841 geoJSON = writeMultiPolygonGeometry( 59842 /** @type {MultiPolygon} */ (geometry), 59843 options 59844 ); 59845 break; 59846 } 59847 case 'GeometryCollection': { 59848 geoJSON = writeGeometryCollectionGeometry( 59849 /** @type {GeometryCollection} */ (geometry), 59850 options 59851 ); 59852 break; 59853 } 59854 case 'Circle': { 59855 geoJSON = { 59856 type: 'GeometryCollection', 59857 geometries: [], 59858 }; 59859 break; 59860 } 59861 default: { 59862 throw new Error('Unsupported geometry type: ' + type); 59863 } 59864 } 59865 return geoJSON; 59866} 59867 59868/** 59869 * @param {GeometryCollection} geometry Geometry. 59870 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59871 * @return {GeoJSONGeometryCollection} GeoJSON geometry collection. 59872 */ 59873function writeGeometryCollectionGeometry(geometry, options) { 59874 options = Object.assign({}, options); 59875 delete options.featureProjection; 59876 const geometries = geometry.getGeometriesArray().map(function (geometry) { 59877 return writeGeometry(geometry, options); 59878 }); 59879 return { 59880 type: 'GeometryCollection', 59881 geometries: geometries, 59882 }; 59883} 59884 59885/** 59886 * @param {LineString} geometry Geometry. 59887 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59888 * @return {GeoJSONGeometry} GeoJSON geometry. 59889 */ 59890function writeLineStringGeometry(geometry, options) { 59891 return { 59892 type: 'LineString', 59893 coordinates: geometry.getCoordinates(), 59894 }; 59895} 59896 59897/** 59898 * @param {MultiLineString} geometry Geometry. 59899 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59900 * @return {GeoJSONGeometry} GeoJSON geometry. 59901 */ 59902function writeMultiLineStringGeometry(geometry, options) { 59903 return { 59904 type: 'MultiLineString', 59905 coordinates: geometry.getCoordinates(), 59906 }; 59907} 59908 59909/** 59910 * @param {MultiPoint} geometry Geometry. 59911 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59912 * @return {GeoJSONGeometry} GeoJSON geometry. 59913 */ 59914function writeMultiPointGeometry(geometry, options) { 59915 return { 59916 type: 'MultiPoint', 59917 coordinates: geometry.getCoordinates(), 59918 }; 59919} 59920 59921/** 59922 * @param {MultiPolygon} geometry Geometry. 59923 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59924 * @return {GeoJSONGeometry} GeoJSON geometry. 59925 */ 59926function writeMultiPolygonGeometry(geometry, options) { 59927 let right; 59928 if (options) { 59929 right = options.rightHanded; 59930 } 59931 return { 59932 type: 'MultiPolygon', 59933 coordinates: geometry.getCoordinates(right), 59934 }; 59935} 59936 59937/** 59938 * @param {Point} geometry Geometry. 59939 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59940 * @return {GeoJSONGeometry} GeoJSON geometry. 59941 */ 59942function writePointGeometry(geometry, options) { 59943 return { 59944 type: 'Point', 59945 coordinates: geometry.getCoordinates(), 59946 }; 59947} 59948 59949/** 59950 * @param {Polygon} geometry Geometry. 59951 * @param {import("./Feature.js").WriteOptions} [options] Write options. 59952 * @return {GeoJSONGeometry} GeoJSON geometry. 59953 */ 59954function writePolygonGeometry(geometry, options) { 59955 let right; 59956 if (options) { 59957 right = options.rightHanded; 59958 } 59959 return { 59960 type: 'Polygon', 59961 coordinates: geometry.getCoordinates(right), 59962 }; 59963} 59964 59965/* harmony default export */ const format_GeoJSON = (GeoJSON); 59966 59967;// CONCATENATED MODULE: ./wwwroot/js/event-emitter.js 59968class EventEmitter { constructor() { this.events = {} } on(e, t) { return "object" != typeof this.events[e] && (this.events[e] = []), this.events[e].push(t), () => this.removeListener(e, t) } removeListener(e, t) { "object" != typeof this.events[e] || -1 < (t = this.events[e].indexOf(t)) && this.events[e].splice(t, 1) } emit(e, ...t) { "object" == typeof this.events[e] && this.events[e].forEach(e => e.apply(this, t)) } once(e, t) { const s = this.on(e, (...e) => { s(), t.apply(this, e) }) } }
59968 class EventManager extends EventEmitter { constructor() { super() } trigger_copter_selecting(e) { this.emit("copterselecting", { copter: e }) } trigger_copter_selected(e) { this.emit("copterselected", e) } trigger_waypoint_added(e) { this.emit("waypoint_added", e) } } 59969;// CONCATENATED MODULE: ./wwwroot/js/domain-map-openlayers.js 59970/* provided dependency */ var $ = __webpack_require__(755); 59971//import jQuery from "./bundle.min.js"; 59972//import "https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.14.1/build/ol.js"; 59973 59974 59975 59976 59977 59978 59979 59980 59981 59982 59983 59984 59985 59986 59987 59988 59989 59990 59991 59992 59993 59994//const $ = jQuery; 59995 59996class ControlOverlay extends control_Control { 59997 constructor(opt_options) { 59998 const options = opt_options || {}; 59999 60000 super({ 60001 element: options.element, 60002 target: options.target, 60003 }); 60004 } 60005} 60006 60007Number.prototype.toDegrees = function () { 60008 return this * 180 / Math.PI; 60009} 60010 60011Number.prototype.toRadians = function () { 60012 return this * Math.PI / 180; 60013} 60014 60015class LonLat { 60016 constructor(lon, lat) { 60017 this.lat = Number(lat); 60018 this.lon = Number(lon); 60019 } 60020 60021 destinationPoint(distance, bearing, radius) { 60022 radius = (radius === undefined) ? 6371e3 : Number(radius); 60023 60024 var delta = Number(distance) / radius; 60025 var Theta = Number(bearing).toRadians(); 60026 60027 var Phi1 = this.lat.toRadians(); 60028 var Lambda1 = this.lon.toRadians(); 60029 60030 var sinPhi1 = Math.sin(Phi1), cosPhi1 = Math.cos(Phi1); 60031 var sindelta = Math.sin(delta), cosdelta = Math.cos(delta); 60032 var sinTheta = Math.sin(Theta), cosTheta = Math.cos(Theta); 60033 60034 var sinPhi2 = sinPhi1 * cosdelta + cosPhi1 * sindelta * cosTheta; 60035 var Phi2 = Math.asin(sinPhi2); 60036 var y = sinTheta * sindelta * cosPhi1; 60037 var x = cosdelta - sinPhi1 * sinPhi2; 60038 var Lambda2 = Lambda1 + Math.atan2(y, x); 60039 60040 return new LonLat((Lambda2.toDegrees() + 540) % 360 - 180, Phi2.toDegrees()); 60041 // normalise to â180..+180° 60042 } 60043} 60044 60045const container = document.getElementById('popup'); 60046const content = document.getElementById('popup-content'); 60047const closer = document.getElementById('popup-closer'); 60048 60049const overlay = new ol_Overlay({ 60050 element: container, 60051 autoPan: { 60052 animation: { 60053 duration: 250, 60054 }, 60055 }, 60056}); 60057 60058const nexradLayer = new WebGLTile({ 60059 source: new source_XYZ({ 60060 attributions: '', 60061 url: 'http://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/nexrad-n0q-900913/{z}/{x}/{y}.png', 60062 maxZoom: 16, 60063 }), 60064}); 60065 60066 60067function refresher() { 60068 $.getJSON('https://mesonet.agron.iastate.edu/json/tms.json', function (data) { 60069 $.each(data.services, function (key, val) { 60070 if (val.id == 'ridge_uscomp_n0q') { 60071 var dt = new Date(val.utc_valid); 60072 nexradLayer.set('title', "NEXRAD N0Q @" 60073 + ("0" + dt.getUTCHours()).slice(-2) 60074 + ("0" + dt.getUTCMinutes()).slice(-2) 60075 + " UTC"); 60076 nexradLayer.setSource(new XYZ({ 60077 url: 'https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/' + val.layername + '/{z}/{x}/{y}.png' 60078 })); 60079 } 60080 }) 60081 }); 60082 60083} 60084 60085closer.onclick = function () { 60086 overlay.setPosition(undefined); 60087 closer.blur(); 60088 return false; 60089}; 60090 60091function colorWithAlpha(color, alpha) { 60092 const [r, g, b] = Array.from(asArray(color)); 60093 return asString([r, g, b, alpha]); 60094} 60095 60096function DomainMap(centralLatInput, centralLongInput, mapId, showControls) { 60097 60098 60099 var wofs_map = { 60100 domainSize: 900000, // meters 60101 map: {}, 60102 overlay_urls: { 60103 "tornado": "https://www.spc.noaa.gov/products/outlook/day1otlk_torn.nolyr.geojson", 60104 "hail": "https://www.spc.noaa.gov/products/outlook/day1otlk_hail.nolyr.geojson", 60105 "wind": "https://www.spc.noaa.gov/products/outlook/day1otlk_wind.nolyr.geojson", 60106 "radars": "../json/radars.geojson" 60107 }, 60108 domain: new Vector(), 60109 tornado: new Vector(), 60110 wind: new Vector(), 60111 hail: new Vector(), 60112 radars: new Vector(), 60113 lat: 0, 60114 lon: 0, 60115 selected_copter: '', 60116 eventManager: new EventManager(), 60117 controlOverlay: {}, 60118 waypoints: [], 60119 update_copter_location: function (id, lat, lon) { 60120 var f = wofs_map.domain.getSource().getFeatures().filter(a => a.get('name') === id); 60121 60122 if (f && f.length > 0) { 60123 f[0].setGeometry(new geom_Point(fromLonLat([lon, lat]))); 60124 } 60125 }, 60126 loadControlOverlay: function () { 60127 $('.overlay input').on('change', function () { 60128 var cat = $(this).attr('data-category'); 60129 if ($(this).prop('checked')) { 60130 if (wofs_map.overlay_urls[cat]) { 60131 const vectorSource = new source_Vector({ 60132 format: new format_GeoJSON(), 60133 url: wofs_map.overlay_urls[cat] 60134 }); 60135 wofs_map[cat].setSource(vectorSource); 60136 60137 } 60138 60139 wofs_map[cat].setVisible(true); 60140 } 60141 else { 60142 wofs_map[cat].setVisible(false); 60143 } 60144 }); 60145 60146 wofs_map.controlOverlay = $('.overlay').show(); 60147 }, 60148 initDomain: function () { 60149 //wofs_map.domain.setStyle(new Style({ 60150 // fill: new Fill({ 60151 // color: colorWithAlpha('#000', 0.15) 60152 // }), 60153 // stroke: new Stroke({ 60154 // color: colorWithAlpha('#000', 0.5) 60155 // }) 60156 //})); 60157 60158 wofs_map.lat = centralLatInput.val(); 60159 wofs_map.lon = centralLongInput.val(); 60160 60161 wofs_map.drawCopters(wofs_map.lon, wofs_map.lat); 60162 60163 $(`#${centralLatInput.attr('id')}, #${centralLongInput.attr('id')}`).on('change', function () { 60164 wofs_map.drawDomain(centralLongInput.val(), centralLatInput.val()); 60165 }); 60166 }, 60167 drawCopters: function (lng, lat) { 60168 fetch('GetRecent').then(function (response) { 60169 return response.json(); 60170 }).then(function (data) { 60171 var features = []; 60172 60173 for (const copter of data) {
60174 var feature = new ol_Feature({ 60175 geometry: new geom_Point(fromLonLat([copter.longitude, copter.latitude])), 60176 name: copter.id, 60177 last_seen: copter.last_seen, 60178 live_url: copter.live_url 60179 }); 60180 features.push(feature); 60181 } 60182 60183 wofs_map.domain.setSource(new source_Vector({ 60184 features: features 60185 })); 60186 60187 wofs_map.map.getView().fit(wofs_map.domain.getSource().getExtent(), { maxZoom: 16 }); 60188 60189 }); 60190 }, 60191 get_copter_color: function(last_seen) { 60192 if (last_seen <= 15) return 'rgba(6, 127, 0,1)'; 60193 else if (last_seen <= 30) return 'rgba(234, 0, 0,1)'; 60194 else return 'rgba(128,128,128,0.8)'; 60195 }, 60196 init: function () { 60197 var mapOptions = { 60198 controls: defaults().extend([new ControlOverlay({ element: $('.overlay')[0] }), new ControlOverlay({ element: $('.overlay-copter')[0] })]), 60199 interactions: defaults_defaults({ doubleClickZoom: false }), 60200 target: mapId, 60201 units: 'm', 60202 layers: [ 60203 new layer_Tile({ 60204 source: new source_OSM() 60205 }), 60206 //nexradLayer, 60207 wofs_map.tornado, 60208 wofs_map.hail, 60209 wofs_map.wind, 60210 wofs_map.domain 60211 ], 60212 overlays: [overlay], 60213 view: new ol_View({ 60214 center: fromLonLat([centralLongInput.val(), centralLatInput.val()]), 60215 zoom: 7 60216 }) 60217 }; 60218 60219 wofs_map.map = new ol_Map(mapOptions); 60220 60221 //wofs_map.map.on('dblclick', function (event) { 60222 // event.preventDefault(); 60223 // if (event.coordinate) { 60224 // const [lon, lat] = transform(event.coordinate, 'EPSG:3857', 'EPSG:4326'); 60225 // centralLongInput.val(lon); 60226 // centralLatInput.val(lat); 60227 // centralLatInput.change(); 60228 // } 60229 //}); 60230 60231 wofs_map.map.on('singleclick', function (e) { 60232 const coordinate = e.coordinate; 60233 //const hdms = toStringHDMS(toLonLat(coordinate)); 60234 60235 var selected = null; 60236 60237 wofs_map.map.forEachFeatureAtPixel(e.pixel, function (f) { 60238 selected = f; 60239 return true; 60240 }); 60241 60242 if (selected && selected.get('name')) { 60243 wofs_map.eventManager.trigger_copter_selecting(wofs_map.selected_copter); 60244 60245 wofs_map.selected_copter = selected.get('name'); 60246 wofs_map.waypoints = []; 60247 60248 wofs_map.domain.getSource().getFeatures().forEach(a => a.set('selected', false)); 60249 60250 selected.set('selected', true); 60251 60252 wofs_map.eventManager.trigger_copter_selected({ 60253 copter: wofs_map.selected_copter, 60254 live_url: selected.get('live_url'), 60255 last_seen: selected.get('last_seen') 60256 }); 60257 60258 $('.overlay-copter').show(); 60259 } 60260 }); 60261 60262 if (showControls) { 60263 wofs_map.map.on('dblclick', function (e) { 60264 $('#popup').removeClass('d-none'); 60265 60266 if (wofs_map.selected_copter.length > 0) { 60267 const coordinate = e.coordinate; 60268 const lonLat = toLonLat(coordinate); 60269 60270 // for now, clear it out... maybe a future feature 60271 wofs_map.waypoints = []; 60272 wofs_map.waypoints.push({ 60273 latitude: lonLat[1], 60274 longitude: lonLat[0] 60275 }); 60276 overlay.setPosition(coordinate); 60277 wofs_map.eventManager.trigger_waypoint_added(wofs_map.waypoints[wofs_map.waypoints.length - 1]); 60278 } 60279 }); 60280 } 60281 60282 wofs_map.map.on('pointermove', function (e) { 60283 var selected = null; 60284
60285 wofs_map.map.forEachFeatureAtPixel(e.pixel, function (f) { 60286 selected = f; 60287 return true; 60288 }); 60289 60290 if (selected) { 60291 $(`#${mapId}`).attr('title', selected.get('LABEL2') || selected.get('name')); 60292 } else { 60293 $(`#${mapId}`).removeAttr('title'); 60294 } 60295 }); 60296 60297 wofs_map.loadControlOverlay(); 60298 60299 wofs_map.initDomain(); 60300 60301 function setDataStyles(data) { 60302 data.setStyle(function (feature, resolution) { 60303 var props = feature.getProperties(); 60304 return new style_Style({ 60305 fill: new style_Fill({ 60306 color: colorWithAlpha(props['fill'], 0.15) 60307 }), 60308 stroke: new style_Stroke({ 60309 color: props['stroke'] 60310 }) 60311 }); 60312 }); 60313 } 60314 60315 setDataStyles(wofs_map.tornado); 60316 setDataStyles(wofs_map.hail); 60317 setDataStyles(wofs_map.wind); 60318 60319 wofs_map.domain.setStyle(function (feature, resolution) { 60320 var geo = feature.getGeometry(); 60321 60322 //when it's a point 60323 if (geo.getType().toLowerCase() === 'point') { 60324 var style = [ 60325 new style_Style({ 60326 image: new Circle({ 60327 radius: 7, 60328 fill: new style_Fill({ 60329 color: wofs_map.get_copter_color(feature.get('last_seen')) 60330 }) 60331 }) 60332 }) 60333 ]; 60334 60335 if (feature.get('selected') === true) 60336 style.push(new style_Style({ 60337 image: new Circle({ 60338 radius: 15, 60339 stroke: new style_Stroke({ 60340 color: 'rgba(0,191,255,0.5)', 60341 width: 5, 60342 }) 60343 }) 60344 })); 60345 60346 return style; 60347 } 60348 }); 60349 60350 //refresher(); 60351 60352 //window.setInterval(function () { 60353 // refresher(); 60354 //}, 5 * 60000); 60355 60356 $('#btnSampleColumn').on('click', async function () { 60357 if (wofs_map.selected_copter.length > 0 && wofs_map.waypoints.length > 0) { 60358 const height = $('#txtHeight').val(); 60359 const response = await fetch("UpdateFlightPlan", { 60360 method: 'POST', 60361 headers: { 60362 'Accept': 'application/json', 60363 'Content-Type': 'application/json' 60364 }, 60365 body: `{ 60366 "copter": "${wofs_map.selected_copter}", 60367 "height": "${height}", 60368 "lat": ${wofs_map.waypoints[0].latitude}, 60369 "lon": ${wofs_map.waypoints[0].longitude} 60370 }`, 60371 }); 60372 60373 if (response.ok) { 60374 closer.onclick(); 60375 //console.log(data); 60376 } 60377 } 60378 }); 60379 } 60380 }; 60381 60382 wofs_map.init(); 60383 60384 return wofs_map; 60385} 60386;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/DefaultReconnectPolicy.js 60387// Licensed to the .NET Foundation under one or more agreements. 60388// The .NET Foundation licenses this file to you under the MIT license. 60389// 0, 2, 10, 30 second delays before reconnect attempts. 60390const DEFAULT_RETRY_DELAYS_IN_MILLISECONDS = [0, 2000, 10000, 30000, null]; 60391/** @private */ 60392class DefaultReconnectPolicy { 60393 constructor(retryDelays) { 60394 this._retryDelays = retryDelays !== undefined ? [...retryDelays, null] : DEFAULT_RETRY_DELAYS_IN_MILLISECONDS; 60395 } 60396 nextRetryDelayInMilliseconds(retryContext) { 60397 return this._retryDelays[retryContext.previousRetryCount]; 60398 } 60399} 60400//# sourceMappingURL=DefaultReconnectPolicy.js.map 60401;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/Errors.js 60402// Licensed to the .NET Foundation under one or more agreements. 60403// The .NET Foundation licenses this file to you under the MIT license. 60404/** Error thrown when an HTTP request fails. */
60405class HttpError extends Error { 60406 /** Constructs a new instance of {@link @microsoft/signalr.HttpError}. 60407 * 60408 * @param {string} errorMessage A descriptive error message. 60409 * @param {number} statusCode The HTTP status code represented by this error. 60410 */ 60411 constructor(errorMessage, statusCode) { 60412 const trueProto = new.target.prototype; 60413 super(`${errorMessage}: Status code '${statusCode}'`); 60414 this.statusCode = statusCode; 60415 // Workaround issue in Typescript compiler 60416 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60417 this.__proto__ = trueProto; 60418 } 60419} 60420/** Error thrown when a timeout elapses. */ 60421class TimeoutError extends Error { 60422 /** Constructs a new instance of {@link @microsoft/signalr.TimeoutError}. 60423 * 60424 * @param {string} errorMessage A descriptive error message. 60425 */ 60426 constructor(errorMessage = "A timeout occurred.") { 60427 const trueProto = new.target.prototype; 60428 super(errorMessage); 60429 // Workaround issue in Typescript compiler 60430 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60431 this.__proto__ = trueProto; 60432 } 60433} 60434/** Error thrown when an action is aborted. */ 60435class AbortError extends Error { 60436 /** Constructs a new instance of {@link AbortError}. 60437 * 60438 * @param {string} errorMessage A descriptive error message. 60439 */ 60440 constructor(errorMessage = "An abort occurred.") { 60441 const trueProto = new.target.prototype; 60442 super(errorMessage); 60443 // Workaround issue in Typescript compiler 60444 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60445 this.__proto__ = trueProto; 60446 } 60447} 60448/** Error thrown when the selected transport is unsupported by the browser. */ 60449/** @private */ 60450class UnsupportedTransportError extends Error { 60451 /** Constructs a new instance of {@link @microsoft/signalr.UnsupportedTransportError}. 60452 * 60453 * @param {string} message A descriptive error message. 60454 * @param {HttpTransportType} transport The {@link @microsoft/signalr.HttpTransportType} this error occured on. 60455 */ 60456 constructor(message, transport) { 60457 const trueProto = new.target.prototype; 60458 super(message); 60459 this.transport = transport; 60460 this.errorType = 'UnsupportedTransportError'; 60461 // Workaround issue in Typescript compiler 60462 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60463 this.__proto__ = trueProto; 60464 } 60465} 60466/** Error thrown when the selected transport is disabled by the browser. */ 60467/** @private */ 60468class DisabledTransportError extends Error { 60469 /** Constructs a new instance of {@link @microsoft/signalr.DisabledTransportError}. 60470 * 60471 * @param {string} message A descriptive error message. 60472 * @param {HttpTransportType} transport The {@link @microsoft/signalr.HttpTransportType} this error occured on. 60473 */ 60474 constructor(message, transport) { 60475 const trueProto = new.target.prototype; 60476 super(message); 60477 this.transport = transport; 60478 this.errorType = 'DisabledTransportError'; 60479 // Workaround issue in Typescript compiler 60480 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60481 this.__proto__ = trueProto; 60482 } 60483} 60484/** Error thrown when the selected transport cannot be started. */ 60485/** @private */ 60486class FailedToStartTransportError extends Error { 60487 /** Constructs a new instance of {@link @microsoft/signalr.FailedToStartTransportError}. 60488 * 60489 * @param {string} message A descriptive error message. 60490 * @param {HttpTransportType} transport The {@link @microsoft/signalr.HttpTransportType} this error occured on. 60491 */ 60492 constructor(message, transport) { 60493 const trueProto = new.target.prototype; 60494 super(message); 60495 this.transport = transport; 60496 this.errorType = 'FailedToStartTransportError'; 60497 // Workaround issue in Typescript compiler 60498 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60499 this.__proto__ = trueProto; 60500 } 60501} 60502/** Error thrown when the negotiation with the server failed to complete. */ 60503/** @private */
vendor: 28,056 bytes, lines 60504-61235
60504class FailedToNegotiateWithServerError extends Error { 60505 /** Constructs a new instance of {@link @microsoft/signalr.FailedToNegotiateWithServerError}. 60506 * 60507 * @param {string} message A descriptive error message. 60508 */ 60509 constructor(message) { 60510 const trueProto = new.target.prototype; 60511 super(message); 60512 this.errorType = 'FailedToNegotiateWithServerError'; 60513 // Workaround issue in Typescript compiler 60514 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60515 this.__proto__ = trueProto; 60516 } 60517} 60518/** Error thrown when multiple errors have occured. */ 60519/** @private */ 60520class AggregateErrors extends Error { 60521 /** Constructs a new instance of {@link @microsoft/signalr.AggregateErrors}. 60522 * 60523 * @param {string} message A descriptive error message. 60524 * @param {Error[]} innerErrors The collection of errors this error is aggregating. 60525 */ 60526 constructor(message, innerErrors) { 60527 const trueProto = new.target.prototype; 60528 super(message); 60529 this.innerErrors = innerErrors; 60530 // Workaround issue in Typescript compiler 60531 // https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200 60532 this.__proto__ = trueProto; 60533 } 60534} 60535//# sourceMappingURL=Errors.js.map 60536;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/HttpClient.js 60537// Licensed to the .NET Foundation under one or more agreements. 60538// The .NET Foundation licenses this file to you under the MIT license. 60539/** Represents an HTTP response. */ 60540class HttpResponse { 60541 constructor(statusCode, statusText, content) { 60542 this.statusCode = statusCode; 60543 this.statusText = statusText; 60544 this.content = content; 60545 } 60546} 60547/** Abstraction over an HTTP client. 60548 * 60549 * This class provides an abstraction over an HTTP client so that a different implementation can be provided on different platforms. 60550 */ 60551class HttpClient { 60552 get(url, options) { 60553 return this.send({ 60554 ...options, 60555 method: "GET", 60556 url, 60557 }); 60558 } 60559 post(url, options) { 60560 return this.send({ 60561 ...options, 60562 method: "POST", 60563 url, 60564 }); 60565 } 60566 delete(url, options) { 60567 return this.send({ 60568 ...options, 60569 method: "DELETE", 60570 url, 60571 }); 60572 } 60573 /** Gets all cookies that apply to the specified URL. 60574 * 60575 * @param url The URL that the cookies are valid for. 60576 * @returns {string} A string containing all the key-value cookie pairs for the specified URL. 60577 */ 60578 // @ts-ignore 60579 getCookieString(url) { 60580 return ""; 60581 } 60582} 60583//# sourceMappingURL=HttpClient.js.map 60584;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/ILogger.js 60585// Licensed to the .NET Foundation under one or more agreements. 60586// The .NET Foundation licenses this file to you under the MIT license. 60587// These values are designed to match the ASP.NET Log Levels since that's the pattern we're emulating here. 60588/** Indicates the severity of a log message. 60589 * 60590 * Log Levels are ordered in increasing severity. So `Debug` is more severe than `Trace`, etc. 60591 */ 60592var LogLevel; 60593(function (LogLevel) { 60594 /** Log level for very low severity diagnostic messages. */ 60595 LogLevel[LogLevel["Trace"] = 0] = "Trace"; 60596 /** Log level for low severity diagnostic messages. */ 60597 LogLevel[LogLevel["Debug"] = 1] = "Debug"; 60598 /** Log level for informational diagnostic messages. */ 60599 LogLevel[LogLevel["Information"] = 2] = "Information"; 60600 /** Log level for diagnostic messages that indicate a non-fatal problem. */ 60601 LogLevel[LogLevel["Warning"] = 3] = "Warning"; 60602 /** Log level for diagnostic messages that indicate a failure in the current operation. */ 60603 LogLevel[LogLevel["Error"] = 4] = "Error"; 60604 /** Log level for diagnostic messages that indicate a failure that will terminate the entire application. */ 60605 LogLevel[LogLevel["Critical"] = 5] = "Critical"; 60606 /** The highest possible log level. Used when configuring logging to indicate that no log messages should be emitted. */ 60607 LogLevel[LogLevel["None"] = 6] = "None"; 60608})(LogLevel || (LogLevel = {})); 60609//# sourceMappingURL=ILogger.js.map 60610;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/Loggers.js 60611// Licensed to the .NET Foundation under one or more agreements. 60612// The .NET Foundation licenses this file to you under the MIT license. 60613/** A logger that does nothing when log messages are sent to it. */ 60614class NullLogger { 60615 constructor() { } 60616 /** @inheritDoc */ 60617 // eslint-disable-next-line 60618 log(_logLevel, _message) { 60619 } 60620} 60621/** The singleton instance of the {@link @microsoft/signalr.NullLogger}. */ 60622NullLogger.instance = new NullLogger(); 60623//# sourceMappingURL=Loggers.js.map 60624;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/Utils.js 60625// Licensed to the .NET Foundation under one or more agreements. 60626// The .NET Foundation licenses this file to you under the MIT license. 60627 60628 60629// Version token that will be replaced by the prepack command 60630/** The version of the SignalR client. */ 60631const Utils_VERSION = "6.0.9"; 60632/** @private */ 60633class Arg { 60634 static isRequired(val, name) { 60635 if (val === null || val === undefined) { 60636 throw new Error(`The '${name}' argument is required.`); 60637 } 60638 } 60639 static isNotEmpty(val, name) { 60640 if (!val || val.match(/^\s*$/)) { 60641 throw new Error(`The '${name}' argument should not be empty.`); 60642 } 60643 } 60644 static isIn(val, values, name) { 60645 // TypeScript enums have keys for **both** the name and the value of each enum member on the type itself. 60646 if (!(val in values)) { 60647 throw new Error(`Unknown ${name} value: ${val}.`); 60648 } 60649 } 60650} 60651/** @private */ 60652class Platform { 60653 // react-native has a window but no document so we should check both 60654 static get isBrowser() { 60655 return typeof window === "object" && typeof window.document === "object"; 60656 } 60657 // WebWorkers don't have a window object so the isBrowser check would fail 60658 static get isWebWorker() { 60659 return typeof self === "object" && "importScripts" in self; 60660 } 60661 // react-native has a window but no document 60662 static get isReactNative() { 60663 return typeof window === "object" && typeof window.document === "undefined"; 60664 } 60665 // Node apps shouldn't have a window object, but WebWorkers don't either 60666 // so we need to check for both WebWorker and window 60667 static get isNode() { 60668 return !this.isBrowser && !this.isWebWorker && !this.isReactNative; 60669 } 60670} 60671/** @private */ 60672function getDataDetail(data, includeContent) { 60673 let detail = ""; 60674 if (isArrayBuffer(data)) { 60675 detail = `Binary data of length ${data.byteLength}`; 60676 if (includeContent) { 60677 detail += `. Content: '${formatArrayBuffer(data)}'`; 60678 } 60679 } 60680 else if (typeof data === "string") { 60681 detail = `String data of length ${data.length}`; 60682 if (includeContent) { 60683 detail += `. Content: '${data}'`; 60684 } 60685 } 60686 return detail; 60687} 60688/** @private */ 60689function formatArrayBuffer(data) { 60690 const view = new Uint8Array(data); 60691 // Uint8Array.map only supports returning another Uint8Array? 60692 let str = ""; 60693 view.forEach((num) => { 60694 const pad = num < 16 ? "0" : ""; 60695 str += `0x${pad}${num.toString(16)} `; 60696 }); 60697 // Trim of trailing space. 60698 return str.substr(0, str.length - 1); 60699} 60700// Also in signalr-protocol-msgpack/Utils.ts 60701/** @private */ 60702function isArrayBuffer(val) { 60703 return val && typeof ArrayBuffer !== "undefined" && 60704 (val instanceof ArrayBuffer || 60705 // Sometimes we get an ArrayBuffer that doesn't satisfy instanceof 60706 (val.constructor && val.constructor.name === "ArrayBuffer")); 60707} 60708/** @private */ 60709async function sendMessage(logger, transportName, httpClient, url, accessTokenFactory, content, options) { 60710 let headers = {}; 60711 if (accessTokenFactory) { 60712 const token = await accessTokenFactory(); 60713 if (token) { 60714 headers = { 60715 ["Authorization"]: `Bearer ${token}`, 60716 }; 60717 } 60718 } 60719 const [name, value] = getUserAgentHeader(); 60720 headers[name] = value; 60721 logger.log(LogLevel.Trace, `(${transportName} transport) sending data. ${getDataDetail(content, options.logMessageContent)}.`); 60722 const responseType = isArrayBuffer(content) ? "arraybuffer" : "text"; 60723 const response = await httpClient.post(url, { 60724 content, 60725 headers: { ...headers, ...options.headers }, 60726 responseType, 60727 timeout: options.timeout, 60728 withCredentials: options.withCredentials, 60729 }); 60730 logger.log(LogLevel.Trace, `(${transportName} transport) request complete. Response status: ${response.statusCode}.`); 60731} 60732/** @private */ 60733function createLogger(logger) { 60734 if (logger === undefined) { 60735 return new ConsoleLogger(LogLevel.Information); 60736 } 60737 if (logger === null) { 60738 return NullLogger.instance; 60739 } 60740 if (logger.log !== undefined) { 60741 return logger; 60742 } 60743 return new ConsoleLogger(logger); 60744} 60745/** @private */ 60746class SubjectSubscription { 60747 constructor(subject, observer) { 60748 this._subject = subject; 60749 this._observer = observer; 60750 } 60751 dispose() { 60752 const index = this._subject.observers.indexOf(this._observer); 60753 if (index > -1) { 60754 this._subject.observers.splice(index, 1); 60755 } 60756 if (this._subject.observers.length === 0 && this._subject.cancelCallback) { 60757 this._subject.cancelCallback().catch((_) => { }); 60758 } 60759 } 60760} 60761/** @private */ 60762class ConsoleLogger { 60763 constructor(minimumLogLevel) { 60764 this._minLevel = minimumLogLevel; 60765 this.out = console; 60766 } 60767 log(logLevel, message) { 60768 if (logLevel >= this._minLevel) { 60769 const msg = `[${new Date().toISOString()}] ${LogLevel[logLevel]}: ${message}`; 60770 switch (logLevel) { 60771 case LogLevel.Critical: 60772 case LogLevel.Error: 60773 this.out.error(msg); 60774 break; 60775 case LogLevel.Warning: 60776 this.out.warn(msg); 60777 break; 60778 case LogLevel.Information: 60779 this.out.info(msg); 60780 break; 60781 default: 60782 // console.debug only goes to attached debuggers in Node, so we use console.log for Trace and Debug 60783 this.out.log(msg); 60784 break; 60785 } 60786 } 60787 } 60788} 60789/** @private */ 60790function getUserAgentHeader() { 60791 let userAgentHeaderName = "X-SignalR-User-Agent"; 60792 if (Platform.isNode) { 60793 userAgentHeaderName = "User-Agent"; 60794 } 60795 return [userAgentHeaderName, constructUserAgent(Utils_VERSION, getOsName(), getRuntime(), getRuntimeVersion())]; 60796} 60797/** @private */ 60798function constructUserAgent(version, os, runtime, runtimeVersion) { 60799 // Microsoft SignalR/[Version] ([Detailed Version]; [Operating System]; [Runtime]; [Runtime Version]) 60800 let userAgent = "Microsoft SignalR/"; 60801 const majorAndMinor = version.split("."); 60802 userAgent += `${majorAndMinor[0]}.${majorAndMinor[1]}`; 60803 userAgent += ` (${version}; `; 60804 if (os && os !== "") { 60805 userAgent += `${os}; `; 60806 } 60807 else { 60808 userAgent += "Unknown OS; "; 60809 } 60810 userAgent += `${runtime}`; 60811 if (runtimeVersion) { 60812 userAgent += `; ${runtimeVersion}`; 60813 } 60814 else { 60815 userAgent += "; Unknown Runtime Version"; 60816 } 60817 userAgent += ")"; 60818 return userAgent; 60819} 60820// eslint-disable-next-line spaced-comment 60821/*#__PURE__*/ function getOsName() { 60822 if (Platform.isNode) { 60823 switch (process.platform) { 60824 case "win32": 60825 return "Windows NT"; 60826 case "darwin": 60827 return "macOS"; 60828 case "linux": 60829 return "Linux"; 60830 default: 60831 return process.platform; 60832 } 60833 } 60834 else { 60835 return ""; 60836 } 60837} 60838// eslint-disable-next-line spaced-comment 60839/*#__PURE__*/ function getRuntimeVersion() { 60840 if (Platform.isNode) { 60841 return process.versions.node; 60842 } 60843 return undefined; 60844} 60845function getRuntime() { 60846 if (Platform.isNode) { 60847 return "NodeJS"; 60848 } 60849 else { 60850 return "Browser"; 60851 } 60852} 60853/** @private */ 60854function getErrorString(e) { 60855 if (e.stack) { 60856 return e.stack; 60857 } 60858 else if (e.message) { 60859 return e.message; 60860 } 60861 return `${e}`; 60862} 60863/** @private */ 60864function getGlobalThis() { 60865 // globalThis is semi-new and not available in Node until v12 60866 if (typeof globalThis !== "undefined") { 60867 return globalThis; 60868 } 60869 if (typeof self !== "undefined") { 60870 return self; 60871 } 60872 if (typeof window !== "undefined") { 60873 return window; 60874 } 60875 if (typeof __webpack_require__.g !== "undefined") { 60876 return __webpack_require__.g; 60877 } 60878 throw new Error("could not find global"); 60879} 60880//# sourceMappingURL=Utils.js.map 60881;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/FetchHttpClient.js 60882// Licensed to the .NET Foundation under one or more agreements. 60883// The .NET Foundation licenses this file to you under the MIT license. 60884 60885 60886 60887 60888class FetchHttpClient extends HttpClient { 60889 constructor(logger) { 60890 super(); 60891 this._logger = logger; 60892 if (typeof fetch === "undefined") { 60893 // In order to ignore the dynamic require in webpack builds we need to do this magic 60894 // @ts-ignore: TS doesn't know about these names 60895 const requireFunc = true ? require : 0; 60896 // Cookies aren't automatically handled in Node so we need to add a CookieJar to preserve cookies across requests 60897 this._jar = new (requireFunc("tough-cookie")).CookieJar(); 60898 this._fetchType = requireFunc("node-fetch"); 60899 // node-fetch doesn't have a nice API for getting and setting cookies 60900 // fetch-cookie will wrap a fetch implementation with a default CookieJar or a provided one 60901 this._fetchType = requireFunc("fetch-cookie")(this._fetchType, this._jar); 60902 } 60903 else { 60904 this._fetchType = fetch.bind(getGlobalThis()); 60905 } 60906 if (typeof AbortController === "undefined") { 60907 // In order to ignore the dynamic require in webpack builds we need to do this magic 60908 // @ts-ignore: TS doesn't know about these names 60909 const requireFunc = true ? require : 0; 60910 // Node needs EventListener methods on AbortController which our custom polyfill doesn't provide 60911 this._abortControllerType = requireFunc("abort-controller"); 60912 } 60913 else { 60914 this._abortControllerType = AbortController; 60915 } 60916 } 60917 /** @inheritDoc */ 60918 async send(request) { 60919 // Check that abort was not signaled before calling send 60920 if (request.abortSignal && request.abortSignal.aborted) { 60921 throw new AbortError(); 60922 } 60923 if (!request.method) { 60924 throw new Error("No method defined."); 60925 } 60926 if (!request.url) { 60927 throw new Error("No url defined."); 60928 } 60929 const abortController = new this._abortControllerType(); 60930 let error; 60931 // Hook our abortSignal into the abort controller 60932 if (request.abortSignal) { 60933 request.abortSignal.onabort = () => { 60934 abortController.abort(); 60935 error = new AbortError(); 60936 }; 60937 } 60938 // If a timeout has been passed in, setup a timeout to call abort 60939 // Type needs to be any to fit window.setTimeout and NodeJS.setTimeout 60940 let timeoutId = null; 60941 if (request.timeout) { 60942 const msTimeout = request.timeout; 60943 timeoutId = setTimeout(() => { 60944 abortController.abort(); 60945 this._logger.log(LogLevel.Warning, `Timeout from HTTP request.`); 60946 error = new TimeoutError(); 60947 }, msTimeout); 60948 } 60949 let response; 60950 try { 60951 response = await this._fetchType(request.url, { 60952 body: request.content, 60953 cache: "no-cache", 60954 credentials: request.withCredentials === true ? "include" : "same-origin", 60955 headers: { 60956 "Content-Type": "text/plain;charset=UTF-8", 60957 "X-Requested-With": "XMLHttpRequest", 60958 ...request.headers, 60959 }, 60960 method: request.method, 60961 mode: "cors", 60962 redirect: "follow", 60963 signal: abortController.signal, 60964 }); 60965 } 60966 catch (e) { 60967 if (error) { 60968 throw error; 60969 } 60970 this._logger.log(LogLevel.Warning, `Error from HTTP request. ${e}.`); 60971 throw e; 60972 } 60973 finally { 60974 if (timeoutId) { 60975 clearTimeout(timeoutId); 60976 } 60977 if (request.abortSignal) { 60978 request.abortSignal.onabort = null; 60979 } 60980 } 60981 if (!response.ok) { 60982 const errorMessage = await deserializeContent(response, "text"); 60983 throw new HttpError(errorMessage || response.statusText, response.status); 60984 } 60985 const content = deserializeContent(response, request.responseType); 60986 const payload = await content; 60987 return new HttpResponse(response.status, response.statusText, payload); 60988 } 60989 getCookieString(url) { 60990 let cookies = ""; 60991 if (Platform.isNode && this._jar) { 60992 // @ts-ignore: unused variable 60993 this._jar.getCookies(url, (e, c) => cookies = c.join("; ")); 60994 } 60995 return cookies; 60996 } 60997} 60998function deserializeContent(response, responseType) { 60999 let content; 61000 switch (responseType) { 61001 case "arraybuffer": 61002 content = response.arrayBuffer(); 61003 break; 61004 case "text": 61005 content = response.text(); 61006 break; 61007 case "blob": 61008 case "document": 61009 case "json": 61010 throw new Error(`${responseType} is not supported.`); 61011 default: 61012 content = response.text(); 61013 break; 61014 } 61015 return content; 61016} 61017//# sourceMappingURL=FetchHttpClient.js.map 61018;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/XhrHttpClient.js 61019// Licensed to the .NET Foundation under one or more agreements. 61020// The .NET Foundation licenses this file to you under the MIT license. 61021 61022 61023 61024class XhrHttpClient extends HttpClient { 61025 constructor(logger) { 61026 super(); 61027 this._logger = logger; 61028 } 61029 /** @inheritDoc */ 61030 send(request) { 61031 // Check that abort was not signaled before calling send 61032 if (request.abortSignal && request.abortSignal.aborted) { 61033 return Promise.reject(new AbortError()); 61034 } 61035 if (!request.method) { 61036 return Promise.reject(new Error("No method defined.")); 61037 } 61038 if (!request.url) { 61039 return Promise.reject(new Error("No url defined.")); 61040 } 61041 return new Promise((resolve, reject) => { 61042 const xhr = new XMLHttpRequest(); 61043 xhr.open(request.method, request.url, true); 61044 xhr.withCredentials = request.withCredentials === undefined ? true : request.withCredentials; 61045 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 61046 // Explicitly setting the Content-Type header for React Native on Android platform. 61047 xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); 61048 const headers = request.headers; 61049 if (headers) { 61050 Object.keys(headers) 61051 .forEach((header) => { 61052 xhr.setRequestHeader(header, headers[header]); 61053 }); 61054 } 61055 if (request.responseType) { 61056 xhr.responseType = request.responseType; 61057 } 61058 if (request.abortSignal) { 61059 request.abortSignal.onabort = () => { 61060 xhr.abort(); 61061 reject(new AbortError()); 61062 }; 61063 } 61064 if (request.timeout) { 61065 xhr.timeout = request.timeout; 61066 } 61067 xhr.onload = () => { 61068 if (request.abortSignal) { 61069 request.abortSignal.onabort = null; 61070 } 61071 if (xhr.status >= 200 && xhr.status < 300) { 61072 resolve(new HttpResponse(xhr.status, xhr.statusText, xhr.response || xhr.responseText)); 61073 } 61074 else { 61075 reject(new HttpError(xhr.response || xhr.responseText || xhr.statusText, xhr.status)); 61076 } 61077 }; 61078 xhr.onerror = () => { 61079 this._logger.log(LogLevel.Warning, `Error from HTTP request. ${xhr.status}: ${xhr.statusText}.`); 61080 reject(new HttpError(xhr.statusText, xhr.status)); 61081 }; 61082 xhr.ontimeout = () => { 61083 this._logger.log(LogLevel.Warning, `Timeout from HTTP request.`); 61084 reject(new TimeoutError()); 61085 }; 61086 xhr.send(request.content || ""); 61087 }); 61088 } 61089} 61090//# sourceMappingURL=XhrHttpClient.js.map 61091;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/DefaultHttpClient.js 61092// Licensed to the .NET Foundation under one or more agreements. 61093// The .NET Foundation licenses this file to you under the MIT license. 61094 61095 61096 61097 61098 61099/** Default implementation of {@link @microsoft/signalr.HttpClient}. */ 61100class DefaultHttpClient extends HttpClient { 61101 /** Creates a new instance of the {@link @microsoft/signalr.DefaultHttpClient}, using the provided {@link @microsoft/signalr.ILogger} to log messages. */ 61102 constructor(logger) { 61103 super(); 61104 if (typeof fetch !== "undefined" || Platform.isNode) { 61105 this._httpClient = new FetchHttpClient(logger); 61106 } 61107 else if (typeof XMLHttpRequest !== "undefined") { 61108 this._httpClient = new XhrHttpClient(logger); 61109 } 61110 else { 61111 throw new Error("No usable HttpClient found."); 61112 } 61113 } 61114 /** @inheritDoc */ 61115 send(request) { 61116 // Check that abort was not signaled before calling send 61117 if (request.abortSignal && request.abortSignal.aborted) { 61118 return Promise.reject(new AbortError()); 61119 } 61120 if (!request.method) { 61121 return Promise.reject(new Error("No method defined.")); 61122 } 61123 if (!request.url) { 61124 return Promise.reject(new Error("No url defined.")); 61125 } 61126 return this._httpClient.send(request); 61127 } 61128 getCookieString(url) { 61129 return this._httpClient.getCookieString(url); 61130 } 61131} 61132//# sourceMappingURL=DefaultHttpClient.js.map 61133;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/HeaderNames.js 61134// Licensed to the .NET Foundation under one or more agreements. 61135// The .NET Foundation licenses this file to you under the MIT license. 61136class HeaderNames { 61137} 61138HeaderNames.Authorization = "Authorization"; 61139HeaderNames.Cookie = "Cookie"; 61140//# sourceMappingURL=HeaderNames.js.map 61141;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/ITransport.js 61142// Licensed to the .NET Foundation under one or more agreements. 61143// The .NET Foundation licenses this file to you under the MIT license. 61144// This will be treated as a bit flag in the future, so we keep it using power-of-two values. 61145/** Specifies a specific HTTP transport type. */ 61146var HttpTransportType; 61147(function (HttpTransportType) { 61148 /** Specifies no transport preference. */ 61149 HttpTransportType[HttpTransportType["None"] = 0] = "None"; 61150 /** Specifies the WebSockets transport. */ 61151 HttpTransportType[HttpTransportType["WebSockets"] = 1] = "WebSockets"; 61152 /** Specifies the Server-Sent Events transport. */ 61153 HttpTransportType[HttpTransportType["ServerSentEvents"] = 2] = "ServerSentEvents"; 61154 /** Specifies the Long Polling transport. */ 61155 HttpTransportType[HttpTransportType["LongPolling"] = 4] = "LongPolling"; 61156})(HttpTransportType || (HttpTransportType = {})); 61157/** Specifies the transfer format for a connection. */ 61158var TransferFormat; 61159(function (TransferFormat) { 61160 /** Specifies that only text data will be transmitted over the connection. */ 61161 TransferFormat[TransferFormat["Text"] = 1] = "Text"; 61162 /** Specifies that binary data will be transmitted over the connection. */ 61163 TransferFormat[TransferFormat["Binary"] = 2] = "Binary"; 61164})(TransferFormat || (TransferFormat = {})); 61165//# sourceMappingURL=ITransport.js.map 61166;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/AbortController.js 61167// Licensed to the .NET Foundation under one or more agreements. 61168// The .NET Foundation licenses this file to you under the MIT license. 61169// Rough polyfill of https://developer.mozilla.org/en-US/docs/Web/API/AbortController 61170// We don't actually ever use the API being polyfilled, we always use the polyfill because 61171// it's a very new API right now. 61172// Not exported from index. 61173/** @private */ 61174class AbortController_AbortController { 61175 constructor() { 61176 this._isAborted = false; 61177 this.onabort = null; 61178 } 61179 abort() { 61180 if (!this._isAborted) { 61181 this._isAborted = true; 61182 if (this.onabort) { 61183 this.onabort(); 61184 } 61185 } 61186 } 61187 get signal() { 61188 return this; 61189 } 61190 get aborted() { 61191 return this._isAborted; 61192 } 61193} 61194//# sourceMappingURL=AbortController.js.map 61195;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/LongPollingTransport.js 61196// Licensed to the .NET Foundation under one or more agreements. 61197// The .NET Foundation licenses this file to you under the MIT license. 61198 61199 61200 61201 61202 61203 61204// Not exported from 'index', this type is internal. 61205/** @private */ 61206class LongPollingTransport { 61207 constructor(httpClient, accessTokenFactory, logger, options) { 61208 this._httpClient = httpClient; 61209 this._accessTokenFactory = accessTokenFactory; 61210 this._logger = logger; 61211 this._pollAbort = new AbortController_AbortController(); 61212 this._options = options; 61213 this._running = false; 61214 this.onreceive = null; 61215 this.onclose = null; 61216 } 61217 // This is an internal type, not exported from 'index' so this is really just internal. 61218 get pollAborted() { 61219 return this._pollAbort.aborted; 61220 } 61221 async connect(url, transferFormat) { 61222 Arg.isRequired(url, "url"); 61223 Arg.isRequired(transferFormat, "transferFormat"); 61224 Arg.isIn(transferFormat, TransferFormat, "transferFormat"); 61225 this._url = url; 61226 this._logger.log(LogLevel.Trace, "(LongPolling transport) Connecting."); 61227 // Allow binary format on Node and Browsers that support binary content (indicated by the presence of responseType property) 61228 if (transferFormat === TransferFormat.Binary && 61229 (typeof XMLHttpRequest !== "undefined" && typeof new XMLHttpRequest().responseType !== "string")) { 61230 throw new Error("Binary protocols over XmlHttpRequest not implementing advanced features are not supported."); 61231 } 61232 const [name, value] = getUserAgentHeader(); 61233 const headers = { [name]: value, ...this._options.headers }; 61234 const pollOptions = { 61235 abortSignal: this._pollAbort.signal,
61236 headers, 61237 timeout: 100000, 61238 withCredentials: this._options.withCredentials, 61239 }; 61240 if (transferFormat === TransferFormat.Binary) { 61241 pollOptions.responseType = "arraybuffer"; 61242 } 61243 const token = await this._getAccessToken(); 61244 this._updateHeaderToken(pollOptions, token); 61245 // Make initial long polling request 61246 // Server uses first long polling request to finish initializing connection and it returns without data 61247 const pollUrl = `${url}&_=${Date.now()}`; 61248 this._logger.log(LogLevel.Trace, `(LongPolling transport) polling: ${pollUrl}.`); 61249 const response = await this._httpClient.get(pollUrl, pollOptions); 61250 if (response.statusCode !== 200) { 61251 this._logger.log(LogLevel.Error, `(LongPolling transport) Unexpected response code: ${response.statusCode}.`); 61252 // Mark running as false so that the poll immediately ends and runs the close logic 61253 this._closeError = new HttpError(response.statusText || "", response.statusCode); 61254 this._running = false; 61255 } 61256 else { 61257 this._running = true; 61258 } 61259 this._receiving = this._poll(this._url, pollOptions); 61260 } 61261 async _getAccessToken() { 61262 if (this._accessTokenFactory) { 61263 return await this._accessTokenFactory(); 61264 } 61265 return null; 61266 } 61267 _updateHeaderToken(request, token) { 61268 if (!request.headers) { 61269 request.headers = {}; 61270 } 61271 if (token) { 61272 request.headers[HeaderNames.Authorization] = `Bearer ${token}`; 61273 return; 61274 } 61275 if (request.headers[HeaderNames.Authorization]) { 61276 delete request.headers[HeaderNames.Authorization]; 61277 } 61278 } 61279 async _poll(url, pollOptions) { 61280 try { 61281 while (this._running) { 61282 // We have to get the access token on each poll, in case it changes 61283 const token = await this._getAccessToken(); 61284 this._updateHeaderToken(pollOptions, token); 61285 try { 61286 const pollUrl = `${url}&_=${Date.now()}`; 61287 this._logger.log(LogLevel.Trace, `(LongPolling transport) polling: ${pollUrl}.`); 61288 const response = await this._httpClient.get(pollUrl, pollOptions); 61289 if (response.statusCode === 204) { 61290 this._logger.log(LogLevel.Information, "(LongPolling transport) Poll terminated by server."); 61291 this._running = false; 61292 } 61293 else if (response.statusCode !== 200) { 61294 this._logger.log(LogLevel.Error, `(LongPolling transport) Unexpected response code: ${response.statusCode}.`); 61295 // Unexpected status code 61296 this._closeError = new HttpError(response.statusText || "", response.statusCode); 61297 this._running = false; 61298 } 61299 else { 61300 // Process the response 61301 if (response.content) { 61302 this._logger.log(LogLevel.Trace, `(LongPolling transport) data received. ${getDataDetail(response.content, this._options.logMessageContent)}.`); 61303 if (this.onreceive) { 61304 this.onreceive(response.content); 61305 } 61306 } 61307 else { 61308 // This is another way timeout manifest. 61309 this._logger.log(LogLevel.Trace, "(LongPolling transport) Poll timed out, reissuing."); 61310 } 61311 } 61312 } 61313 catch (e) { 61314 if (!this._running) { 61315 // Log but disregard errors that occur after stopping 61316 this._logger.log(LogLevel.Trace, `(LongPolling transport) Poll errored after shutdown: ${e.message}`); 61317 } 61318 else { 61319 if (e instanceof TimeoutError) { 61320 // Ignore timeouts and reissue the poll. 61321 this._logger.log(LogLevel.Trace, "(LongPolling transport) Poll timed out, reissuing."); 61322 } 61323 else { 61324 // Close the connection with the error as the result. 61325 this._closeError = e; 61326 this._running = false; 61327 } 61328 } 61329 } 61330 } 61331 } 61332 finally { 61333 this._logger.log(LogLevel.Trace, "(LongPolling transport) Polling complete."); 61334 // We will reach here with pollAborted==false when the server returned a response causing the transport to stop. 61335 // If pollAborted==true then client initiated the stop and the stop method will raise the close event after DELETE is sent. 61336 if (!this.pollAborted) { 61337 this._raiseOnClose(); 61338 } 61339 } 61340 } 61341 async send(data) { 61342 if (!this._running) { 61343 return Promise.reject(new Error("Cannot send until the transport is connected")); 61344 } 61345 return sendMessage(this._logger, "LongPolling", this._httpClient, this._url, this._accessTokenFactory, data, this._options); 61346 } 61347 async stop() { 61348 this._logger.log(LogLevel.Trace, "(LongPolling transport) Stopping polling."); 61349 // Tell receiving loop to stop, abort any current request, and then wait for it to finish 61350 this._running = false; 61351 this._pollAbort.abort(); 61352 try { 61353 await this._receiving; 61354 // Send DELETE to clean up long polling on the server 61355 this._logger.log(LogLevel.Trace, `(LongPolling transport) sending DELETE request to ${this._url}.`); 61356 const headers = {}; 61357 const [name, value] = getUserAgentHeader(); 61358 headers[name] = value; 61359 const deleteOptions = { 61360 headers: { ...headers, ...this._options.headers }, 61361 timeout: this._options.timeout, 61362 withCredentials: this._options.withCredentials, 61363 }; 61364 const token = await this._getAccessToken(); 61365 this._updateHeaderToken(deleteOptions, token); 61366 await this._httpClient.delete(this._url, deleteOptions); 61367 this._logger.log(LogLevel.Trace, "(LongPolling transport) DELETE request sent."); 61368 } 61369 finally { 61370 this._logger.log(LogLevel.Trace, "(LongPolling transport) Stop finished."); 61371 // Raise close event here instead of in polling 61372 // It needs to happen after the DELETE request is sent 61373 this._raiseOnClose(); 61374 } 61375 } 61376 _raiseOnClose() { 61377 if (this.onclose) { 61378 let logMessage = "(LongPolling transport) Firing onclose event."; 61379 if (this._closeError) { 61380 logMessage += " Error: " + this._closeError; 61381 } 61382 this._logger.log(LogLevel.Trace, logMessage); 61383 this.onclose(this._closeError); 61384 } 61385 } 61386} 61387//# sourceMappingURL=LongPollingTransport.js.map 61388;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/ServerSentEventsTransport.js 61389// Licensed to the .NET Foundation under one or more agreements. 61390// The .NET Foundation licenses this file to you under the MIT license. 61391 61392 61393 61394/** @private */ 61395class ServerSentEventsTransport { 61396 constructor(httpClient, accessTokenFactory, logger, options) { 61397 this._httpClient = httpClient; 61398 this._accessTokenFactory = accessTokenFactory;
vendor: 69,724 bytes, lines 61399-62809
61399 this._logger = logger; 61400 this._options = options; 61401 this.onreceive = null; 61402 this.onclose = null; 61403 } 61404 async connect(url, transferFormat) { 61405 Arg.isRequired(url, "url"); 61406 Arg.isRequired(transferFormat, "transferFormat"); 61407 Arg.isIn(transferFormat, TransferFormat, "transferFormat"); 61408 this._logger.log(LogLevel.Trace, "(SSE transport) Connecting."); 61409 // set url before accessTokenFactory because this.url is only for send and we set the auth header instead of the query string for send 61410 this._url = url; 61411 if (this._accessTokenFactory) { 61412 const token = await this._accessTokenFactory(); 61413 if (token) { 61414 url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`; 61415 } 61416 } 61417 return new Promise((resolve, reject) => { 61418 let opened = false; 61419 if (transferFormat !== TransferFormat.Text) { 61420 reject(new Error("The Server-Sent Events transport only supports the 'Text' transfer format")); 61421 return; 61422 } 61423 let eventSource; 61424 if (Platform.isBrowser || Platform.isWebWorker) { 61425 eventSource = new this._options.EventSource(url, { withCredentials: this._options.withCredentials }); 61426 } 61427 else { 61428 // Non-browser passes cookies via the dictionary 61429 const cookies = this._httpClient.getCookieString(url); 61430 const headers = {}; 61431 headers.Cookie = cookies; 61432 const [name, value] = getUserAgentHeader(); 61433 headers[name] = value; 61434 eventSource = new this._options.EventSource(url, { withCredentials: this._options.withCredentials, headers: { ...headers, ...this._options.headers } }); 61435 } 61436 try { 61437 eventSource.onmessage = (e) => { 61438 if (this.onreceive) { 61439 try { 61440 this._logger.log(LogLevel.Trace, `(SSE transport) data received. ${getDataDetail(e.data, this._options.logMessageContent)}.`); 61441 this.onreceive(e.data); 61442 } 61443 catch (error) { 61444 this._close(error); 61445 return; 61446 } 61447 } 61448 }; 61449 // @ts-ignore: not using event on purpose 61450 eventSource.onerror = (e) => { 61451 // EventSource doesn't give any useful information about server side closes. 61452 if (opened) { 61453 this._close(); 61454 } 61455 else { 61456 reject(new Error("EventSource failed to connect. The connection could not be found on the server," 61457 + " either the connection ID is not present on the server, or a proxy is refusing/buffering the connection." 61458 + " If you have multiple servers check that sticky sessions are enabled.")); 61459 } 61460 }; 61461 eventSource.onopen = () => { 61462 this._logger.log(LogLevel.Information, `SSE connected to ${this._url}`); 61463 this._eventSource = eventSource; 61464 opened = true; 61465 resolve(); 61466 }; 61467 } 61468 catch (e) { 61469 reject(e); 61470 return; 61471 } 61472 }); 61473 } 61474 async send(data) { 61475 if (!this._eventSource) { 61476 return Promise.reject(new Error("Cannot send until the transport is connected")); 61477 } 61478 return sendMessage(this._logger, "SSE", this._httpClient, this._url, this._accessTokenFactory, data, this._options); 61479 } 61480 stop() { 61481 this._close(); 61482 return Promise.resolve(); 61483 } 61484 _close(e) { 61485 if (this._eventSource) { 61486 this._eventSource.close(); 61487 this._eventSource = undefined; 61488 if (this.onclose) { 61489 this.onclose(e); 61490 } 61491 } 61492 } 61493} 61494//# sourceMappingURL=ServerSentEventsTransport.js.map 61495;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/WebSocketTransport.js 61496// Licensed to the .NET Foundation under one or more agreements. 61497// The .NET Foundation licenses this file to you under the MIT license. 61498 61499 61500 61501 61502/** @private */ 61503class WebSocketTransport { 61504 constructor(httpClient, accessTokenFactory, logger, logMessageContent, webSocketConstructor, headers) { 61505 this._logger = logger; 61506 this._accessTokenFactory = accessTokenFactory; 61507 this._logMessageContent = logMessageContent; 61508 this._webSocketConstructor = webSocketConstructor; 61509 this._httpClient = httpClient; 61510 this.onreceive = null; 61511 this.onclose = null; 61512 this._headers = headers; 61513 } 61514 async connect(url, transferFormat) { 61515 Arg.isRequired(url, "url"); 61516 Arg.isRequired(transferFormat, "transferFormat"); 61517 Arg.isIn(transferFormat, TransferFormat, "transferFormat"); 61518 this._logger.log(LogLevel.Trace, "(WebSockets transport) Connecting."); 61519 if (this._accessTokenFactory) { 61520 const token = await this._accessTokenFactory(); 61521 if (token) { 61522 url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(token)}`; 61523 } 61524 } 61525 return new Promise((resolve, reject) => { 61526 url = url.replace(/^http/, "ws"); 61527 let webSocket; 61528 const cookies = this._httpClient.getCookieString(url); 61529 let opened = false; 61530 if (Platform.isNode) { 61531 const headers = {}; 61532 const [name, value] = getUserAgentHeader(); 61533 headers[name] = value; 61534 if (cookies) { 61535 headers[HeaderNames.Cookie] = `${cookies}`; 61536 } 61537 // Only pass headers when in non-browser environments 61538 webSocket = new this._webSocketConstructor(url, undefined, { 61539 headers: { ...headers, ...this._headers }, 61540 }); 61541 } 61542 if (!webSocket) { 61543 // Chrome is not happy with passing 'undefined' as protocol 61544 webSocket = new this._webSocketConstructor(url); 61545 } 61546 if (transferFormat === TransferFormat.Binary) { 61547 webSocket.binaryType = "arraybuffer"; 61548 } 61549 webSocket.onopen = (_event) => { 61550 this._logger.log(LogLevel.Information, `WebSocket connected to ${url}.`); 61551 this._webSocket = webSocket; 61552 opened = true; 61553 resolve(); 61554 }; 61555 webSocket.onerror = (event) => { 61556 let error = null; 61557 // ErrorEvent is a browser only type we need to check if the type exists before using it 61558 if (typeof ErrorEvent !== "undefined" && event instanceof ErrorEvent) { 61559 error = event.error; 61560 } 61561 else { 61562 error = "There was an error with the transport"; 61563 } 61564 this._logger.log(LogLevel.Information, `(WebSockets transport) ${error}.`); 61565 }; 61566 webSocket.onmessage = (message) => { 61567 this._logger.log(LogLevel.Trace, `(WebSockets transport) data received. ${getDataDetail(message.data, this._logMessageContent)}.`); 61568 if (this.onreceive) { 61569 try { 61570 this.onreceive(message.data); 61571 } 61572 catch (error) { 61573 this._close(error); 61574 return; 61575 } 61576 } 61577 }; 61578 webSocket.onclose = (event) => { 61579 // Don't call close handler if connection was never established 61580 // We'll reject the connect call instead 61581 if (opened) { 61582 this._close(event); 61583 } 61584 else { 61585 let error = null; 61586 // ErrorEvent is a browser only type we need to check if the type exists before using it 61587 if (typeof ErrorEvent !== "undefined" && event instanceof ErrorEvent) { 61588 error = event.error; 61589 } 61590 else { 61591 error = "WebSocket failed to connect. The connection could not be found on the server," 61592 + " either the endpoint may not be a SignalR endpoint," 61593 + " the connection ID is not present on the server, or there is a proxy blocking WebSockets." 61594 + " If you have multiple servers check that sticky sessions are enabled."; 61595 } 61596 reject(new Error(error)); 61597 } 61598 }; 61599 }); 61600 } 61601 send(data) { 61602 if (this._webSocket && this._webSocket.readyState === this._webSocketConstructor.OPEN) { 61603 this._logger.log(LogLevel.Trace, `(WebSockets transport) sending data. ${getDataDetail(data, this._logMessageContent)}.`); 61604 this._webSocket.send(data); 61605 return Promise.resolve(); 61606 } 61607 return Promise.reject("WebSocket is not in the OPEN state"); 61608 } 61609 stop() { 61610 if (this._webSocket) { 61611 // Manually invoke onclose callback inline so we know the HttpConnection was closed properly before returning 61612 // This also solves an issue where websocket.onclose could take 18+ seconds to trigger during network disconnects 61613 this._close(undefined); 61614 } 61615 return Promise.resolve(); 61616 } 61617 _close(event) { 61618 // webSocket will be null if the transport did not start successfully 61619 if (this._webSocket) { 61620 // Clear websocket handlers because we are considering the socket closed now 61621 this._webSocket.onclose = () => { }; 61622 this._webSocket.onmessage = () => { }; 61623 this._webSocket.onerror = () => { }; 61624 this._webSocket.close(); 61625 this._webSocket = undefined; 61626 } 61627 this._logger.log(LogLevel.Trace, "(WebSockets transport) socket closed."); 61628 if (this.onclose) { 61629 if (this._isCloseEvent(event) && (event.wasClean === false || event.code !== 1000)) { 61630 this.onclose(new Error(`WebSocket closed with status code: ${event.code} (${event.reason || "no reason given"}).`)); 61631 } 61632 else if (event instanceof Error) { 61633 this.onclose(event); 61634 } 61635 else { 61636 this.onclose(); 61637 } 61638 } 61639 } 61640 _isCloseEvent(event) { 61641 return event && typeof event.wasClean === "boolean" && typeof event.code === "number"; 61642 } 61643} 61644//# sourceMappingURL=WebSocketTransport.js.map 61645;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/HttpConnection.js 61646// Licensed to the .NET Foundation under one or more agreements. 61647// The .NET Foundation licenses this file to you under the MIT license. 61648 61649 61650 61651 61652 61653 61654 61655 61656 61657const MAX_REDIRECTS = 100; 61658/** @private */ 61659class HttpConnection { 61660 constructor(url, options = {}) { 61661 this._stopPromiseResolver = () => { }; 61662 this.features = {}; 61663 this._negotiateVersion = 1; 61664 Arg.isRequired(url, "url"); 61665 this._logger = createLogger(options.logger); 61666 this.baseUrl = this._resolveUrl(url); 61667 options = options || {}; 61668 options.logMessageContent = options.logMessageContent === undefined ? false : options.logMessageContent; 61669 if (typeof options.withCredentials === "boolean" || options.withCredentials === undefined) { 61670 options.withCredentials = options.withCredentials === undefined ? true : options.withCredentials; 61671 } 61672 else { 61673 throw new Error("withCredentials option was not a 'boolean' or 'undefined' value"); 61674 } 61675 options.timeout = options.timeout === undefined ? 100 * 1000 : options.timeout; 61676 let webSocketModule = null; 61677 let eventSourceModule = null; 61678 if (Platform.isNode && "function" !== "undefined") { 61679 // In order to ignore the dynamic require in webpack builds we need to do this magic 61680 // @ts-ignore: TS doesn't know about these names 61681 const requireFunc = true ? require : 0; 61682 webSocketModule = requireFunc("ws"); 61683 eventSourceModule = requireFunc("eventsource"); 61684 } 61685 if (!Platform.isNode && typeof WebSocket !== "undefined" && !options.WebSocket) { 61686 options.WebSocket = WebSocket; 61687 } 61688 else if (Platform.isNode && !options.WebSocket) { 61689 if (webSocketModule) { 61690 options.WebSocket = webSocketModule; 61691 } 61692 } 61693 if (!Platform.isNode && typeof EventSource !== "undefined" && !options.EventSource) { 61694 options.EventSource = EventSource; 61695 } 61696 else if (Platform.isNode && !options.EventSource) { 61697 if (typeof eventSourceModule !== "undefined") { 61698 options.EventSource = eventSourceModule; 61699 } 61700 } 61701 this._httpClient = options.httpClient || new DefaultHttpClient(this._logger); 61702 this._connectionState = "Disconnected" /* Disconnected */; 61703 this._connectionStarted = false; 61704 this._options = options; 61705 this.onreceive = null; 61706 this.onclose = null; 61707 } 61708 async start(transferFormat) { 61709 transferFormat = transferFormat || TransferFormat.Binary; 61710 Arg.isIn(transferFormat, TransferFormat, "transferFormat"); 61711 this._logger.log(LogLevel.Debug, `Starting connection with transfer format '${TransferFormat[transferFormat]}'.`); 61712 if (this._connectionState !== "Disconnected" /* Disconnected */) { 61713 return Promise.reject(new Error("Cannot start an HttpConnection that is not in the 'Disconnected' state.")); 61714 } 61715 this._connectionState = "Connecting" /* Connecting */; 61716 this._startInternalPromise = this._startInternal(transferFormat); 61717 await this._startInternalPromise; 61718 // The TypeScript compiler thinks that connectionState must be Connecting here. The TypeScript compiler is wrong. 61719 if (this._connectionState === "Disconnecting" /* Disconnecting */) { 61720 // stop() was called and transitioned the client into the Disconnecting state. 61721 const message = "Failed to start the HttpConnection before stop() was called."; 61722 this._logger.log(LogLevel.Error, message); 61723 // We cannot await stopPromise inside startInternal since stopInternal awaits the startInternalPromise. 61724 await this._stopPromise; 61725 return Promise.reject(new Error(message)); 61726 } 61727 else if (this._connectionState !== "Connected" /* Connected */) { 61728 // stop() was called and transitioned the client into the Disconnecting state. 61729 const message = "HttpConnection.startInternal completed gracefully but didn't enter the connection into the connected state!"; 61730 this._logger.log(LogLevel.Error, message); 61731 return Promise.reject(new Error(message)); 61732 } 61733 this._connectionStarted = true; 61734 } 61735 send(data) { 61736 if (this._connectionState !== "Connected" /* Connected */) { 61737 return Promise.reject(new Error("Cannot send data if the connection is not in the 'Connected' State.")); 61738 } 61739 if (!this._sendQueue) { 61740 this._sendQueue = new TransportSendQueue(this.transport); 61741 } 61742 // Transport will not be null if state is connected 61743 return this._sendQueue.send(data); 61744 } 61745 async stop(error) { 61746 if (this._connectionState === "Disconnected" /* Disconnected */) { 61747 this._logger.log(LogLevel.Debug, `Call to HttpConnection.stop(${error}) ignored because the connection is already in the disconnected state.`); 61748 return Promise.resolve(); 61749 } 61750 if (this._connectionState === "Disconnecting" /* Disconnecting */) { 61751 this._logger.log(LogLevel.Debug, `Call to HttpConnection.stop(${error}) ignored because the connection is already in the disconnecting state.`); 61752 return this._stopPromise; 61753 } 61754 this._connectionState = "Disconnecting" /* Disconnecting */; 61755 this._stopPromise = new Promise((resolve) => { 61756 // Don't complete stop() until stopConnection() completes. 61757 this._stopPromiseResolver = resolve; 61758 }); 61759 // stopInternal should never throw so just observe it. 61760 await this._stopInternal(error); 61761 await this._stopPromise; 61762 } 61763 async _stopInternal(error) { 61764 // Set error as soon as possible otherwise there is a race between 61765 // the transport closing and providing an error and the error from a close message 61766 // We would prefer the close message error. 61767 this._stopError = error; 61768 try { 61769 await this._startInternalPromise; 61770 } 61771 catch (e) { 61772 // This exception is returned to the user as a rejected Promise from the start method. 61773 } 61774 // The transport's onclose will trigger stopConnection which will run our onclose event. 61775 // The transport should always be set if currently connected. If it wasn't set, it's likely because 61776 // stop was called during start() and start() failed. 61777 if (this.transport) { 61778 try { 61779 await this.transport.stop(); 61780 } 61781 catch (e) { 61782 this._logger.log(LogLevel.Error, `HttpConnection.transport.stop() threw error '${e}'.`); 61783 this._stopConnection(); 61784 } 61785 this.transport = undefined; 61786 } 61787 else { 61788 this._logger.log(LogLevel.Debug, "HttpConnection.transport is undefined in HttpConnection.stop() because start() failed."); 61789 } 61790 } 61791 async _startInternal(transferFormat) { 61792 // Store the original base url and the access token factory since they may change 61793 // as part of negotiating 61794 let url = this.baseUrl; 61795 this._accessTokenFactory = this._options.accessTokenFactory; 61796 try { 61797 if (this._options.skipNegotiation) { 61798 if (this._options.transport === HttpTransportType.WebSockets) { 61799 // No need to add a connection ID in this case 61800 this.transport = this._constructTransport(HttpTransportType.WebSockets); 61801 // We should just call connect directly in this case. 61802 // No fallback or negotiate in this case. 61803 await this._startTransport(url, transferFormat); 61804 } 61805 else { 61806 throw new Error("Negotiation can only be skipped when using the WebSocket transport directly."); 61807 } 61808 } 61809 else { 61810 let negotiateResponse = null; 61811 let redirects = 0; 61812 do { 61813 negotiateResponse = await this._getNegotiationResponse(url); 61814 // the user tries to stop the connection when it is being started 61815 if (this._connectionState === "Disconnecting" /* Disconnecting */ || this._connectionState === "Disconnected" /* Disconnected */) { 61816 throw new Error("The connection was stopped during negotiation."); 61817 } 61818 if (negotiateResponse.error) { 61819 throw new Error(negotiateResponse.error); 61820 } 61821 if (negotiateResponse.ProtocolVersion) { 61822 throw new Error("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."); 61823 } 61824 if (negotiateResponse.url) { 61825 url = negotiateResponse.url; 61826 } 61827 if (negotiateResponse.accessToken) { 61828 // Replace the current access token factory with one that uses 61829 // the returned access token 61830 const accessToken = negotiateResponse.accessToken; 61831 this._accessTokenFactory = () => accessToken; 61832 } 61833 redirects++; 61834 } while (negotiateResponse.url && redirects < MAX_REDIRECTS); 61835 if (redirects === MAX_REDIRECTS && negotiateResponse.url) { 61836 throw new Error("Negotiate redirection limit exceeded."); 61837 } 61838 await this._createTransport(url, this._options.transport, negotiateResponse, transferFormat); 61839 } 61840 if (this.transport instanceof LongPollingTransport) { 61841 this.features.inherentKeepAlive = true; 61842 } 61843 if (this._connectionState === "Connecting" /* Connecting */) { 61844 // Ensure the connection transitions to the connected state prior to completing this.startInternalPromise. 61845 // start() will handle the case when stop was called and startInternal exits still in the disconnecting state. 61846 this._logger.log(LogLevel.Debug, "The HttpConnection connected successfully."); 61847 this._connectionState = "Connected" /* Connected */; 61848 } 61849 // stop() is waiting on us via this.startInternalPromise so keep this.transport around so it can clean up. 61850 // This is the only case startInternal can exit in neither the connected nor disconnected state because stopConnection() 61851 // will transition to the disconnected state. start() will wait for the transition using the stopPromise. 61852 } 61853 catch (e) { 61854 this._logger.log(LogLevel.Error, "Failed to start the connection: " + e); 61855 this._connectionState = "Disconnected" /* Disconnected */; 61856 this.transport = undefined; 61857 // if start fails, any active calls to stop assume that start will complete the stop promise 61858 this._stopPromiseResolver(); 61859 return Promise.reject(e); 61860 } 61861 } 61862 async _getNegotiationResponse(url) { 61863 const headers = {}; 61864 if (this._accessTokenFactory) { 61865 const token = await this._accessTokenFactory(); 61866 if (token) { 61867 headers[HeaderNames.Authorization] = `Bearer ${token}`; 61868 } 61869 } 61870 const [name, value] = getUserAgentHeader(); 61871 headers[name] = value; 61872 const negotiateUrl = this._resolveNegotiateUrl(url); 61873 this._logger.log(LogLevel.Debug, `Sending negotiation request: ${negotiateUrl}.`); 61874 try { 61875 const response = await this._httpClient.post(negotiateUrl, { 61876 content: "", 61877 headers: { ...headers, ...this._options.headers }, 61878 timeout: this._options.timeout, 61879 withCredentials: this._options.withCredentials, 61880 }); 61881 if (response.statusCode !== 200) { 61882 return Promise.reject(new Error(`Unexpected status code returned from negotiate '${response.statusCode}'`)); 61883 } 61884 const negotiateResponse = JSON.parse(response.content); 61885 if (!negotiateResponse.negotiateVersion || negotiateResponse.negotiateVersion < 1) { 61886 // Negotiate version 0 doesn't use connectionToken 61887 // So we set it equal to connectionId so all our logic can use connectionToken without being aware of the negotiate version 61888 negotiateResponse.connectionToken = negotiateResponse.connectionId; 61889 } 61890 return negotiateResponse; 61891 } 61892 catch (e) { 61893 let errorMessage = "Failed to complete negotiation with the server: " + e; 61894 if (e instanceof HttpError) { 61895 if (e.statusCode === 404) { 61896 errorMessage = errorMessage + " Either this is not a SignalR endpoint or there is a proxy blocking the connection."; 61897 } 61898 } 61899 this._logger.log(LogLevel.Error, errorMessage); 61900 return Promise.reject(new FailedToNegotiateWithServerError(errorMessage)); 61901 } 61902 } 61903 _createConnectUrl(url, connectionToken) { 61904 if (!connectionToken) { 61905 return url; 61906 } 61907 return url + (url.indexOf("?") === -1 ? "?" : "&") + `id=${connectionToken}`; 61908 } 61909 async _createTransport(url, requestedTransport, negotiateResponse, requestedTransferFormat) { 61910 let connectUrl = this._createConnectUrl(url, negotiateResponse.connectionToken); 61911 if (this._isITransport(requestedTransport)) { 61912 this._logger.log(LogLevel.Debug, "Connection was provided an instance of ITransport, using that directly."); 61913 this.transport = requestedTransport; 61914 await this._startTransport(connectUrl, requestedTransferFormat); 61915 this.connectionId = negotiateResponse.connectionId; 61916 return; 61917 } 61918 const transportExceptions = []; 61919 const transports = negotiateResponse.availableTransports || []; 61920 let negotiate = negotiateResponse; 61921 for (const endpoint of transports) { 61922 const transportOrError = this._resolveTransportOrError(endpoint, requestedTransport, requestedTransferFormat); 61923 if (transportOrError instanceof Error) { 61924 // Store the error and continue, we don't want to cause a re-negotiate in these cases 61925 transportExceptions.push(`${endpoint.transport} failed:`); 61926 transportExceptions.push(transportOrError); 61927 } 61928 else if (this._isITransport(transportOrError)) { 61929 this.transport = transportOrError; 61930 if (!negotiate) { 61931 try { 61932 negotiate = await this._getNegotiationResponse(url); 61933 } 61934 catch (ex) { 61935 return Promise.reject(ex); 61936 } 61937 connectUrl = this._createConnectUrl(url, negotiate.connectionToken); 61938 } 61939 try { 61940 await this._startTransport(connectUrl, requestedTransferFormat); 61941 this.connectionId = negotiate.connectionId; 61942 return; 61943 } 61944 catch (ex) { 61945 this._logger.log(LogLevel.Error, `Failed to start the transport '${endpoint.transport}': ${ex}`); 61946 negotiate = undefined; 61947 transportExceptions.push(new FailedToStartTransportError(`${endpoint.transport} failed: ${ex}`, HttpTransportType[endpoint.transport])); 61948 if (this._connectionState !== "Connecting" /* Connecting */) { 61949 const message = "Failed to select transport before stop() was called."; 61950 this._logger.log(LogLevel.Debug, message); 61951 return Promise.reject(new Error(message)); 61952 } 61953 } 61954 } 61955 } 61956 if (transportExceptions.length > 0) { 61957 return Promise.reject(new AggregateErrors(`Unable to connect to the server with any of the available transports. ${transportExceptions.join(" ")}`, transportExceptions)); 61958 } 61959 return Promise.reject(new Error("None of the transports supported by the client are supported by the server.")); 61960 } 61961 _constructTransport(transport) { 61962 switch (transport) { 61963 case HttpTransportType.WebSockets: 61964 if (!this._options.WebSocket) { 61965 throw new Error("'WebSocket' is not supported in your environment."); 61966 } 61967 return new WebSocketTransport(this._httpClient, this._accessTokenFactory, this._logger, this._options.logMessageContent, this._options.WebSocket, this._options.headers || {}); 61968 case HttpTransportType.ServerSentEvents: 61969 if (!this._options.EventSource) { 61970 throw new Error("'EventSource' is not supported in your environment."); 61971 } 61972 return new ServerSentEventsTransport(this._httpClient, this._accessTokenFactory, this._logger, this._options); 61973 case HttpTransportType.LongPolling: 61974 return new LongPollingTransport(this._httpClient, this._accessTokenFactory, this._logger, this._options); 61975 default: 61976 throw new Error(`Unknown transport: ${transport}.`); 61977 } 61978 } 61979 _startTransport(url, transferFormat) { 61980 this.transport.onreceive = this.onreceive; 61981 this.transport.onclose = (e) => this._stopConnection(e); 61982 return this.transport.connect(url, transferFormat); 61983 } 61984 _resolveTransportOrError(endpoint, requestedTransport, requestedTransferFormat) { 61985 const transport = HttpTransportType[endpoint.transport]; 61986 if (transport === null || transport === undefined) { 61987 this._logger.log(LogLevel.Debug, `Skipping transport '${endpoint.transport}' because it is not supported by this client.`); 61988 return new Error(`Skipping transport '${endpoint.transport}' because it is not supported by this client.`); 61989 } 61990 else { 61991 if (transportMatches(requestedTransport, transport)) { 61992 const transferFormats = endpoint.transferFormats.map((s) => TransferFormat[s]); 61993 if (transferFormats.indexOf(requestedTransferFormat) >= 0) { 61994 if ((transport === HttpTransportType.WebSockets && !this._options.WebSocket) || 61995 (transport === HttpTransportType.ServerSentEvents && !this._options.EventSource)) { 61996 this._logger.log(LogLevel.Debug, `Skipping transport '${HttpTransportType[transport]}' because it is not supported in your environment.'`); 61997 return new UnsupportedTransportError(`'${HttpTransportType[transport]}' is not supported in your environment.`, transport); 61998 } 61999 else { 62000 this._logger.log(LogLevel.Debug, `Selecting transport '${HttpTransportType[transport]}'.`); 62001 try { 62002 return this._constructTransport(transport); 62003 } 62004 catch (ex) { 62005 return ex; 62006 } 62007 } 62008 } 62009 else { 62010 this._logger.log(LogLevel.Debug, `Skipping transport '${HttpTransportType[transport]}' because it does not support the requested transfer format '${TransferFormat[requestedTransferFormat]}'.`); 62011 return new Error(`'${HttpTransportType[transport]}' does not support ${TransferFormat[requestedTransferFormat]}.`); 62012 } 62013 } 62014 else { 62015 this._logger.log(LogLevel.Debug, `Skipping transport '${HttpTransportType[transport]}' because it was disabled by the client.`); 62016 return new DisabledTransportError(`'${HttpTransportType[transport]}' is disabled by the client.`, transport); 62017 } 62018 } 62019 } 62020 _isITransport(transport) { 62021 return transport && typeof (transport) === "object" && "connect" in transport; 62022 } 62023 _stopConnection(error) { 62024 this._logger.log(LogLevel.Debug, `HttpConnection.stopConnection(${error}) called while in state ${this._connectionState}.`); 62025 this.transport = undefined; 62026 // If we have a stopError, it takes precedence over the error from the transport 62027 error = this._stopError || error; 62028 this._stopError = undefined; 62029 if (this._connectionState === "Disconnected" /* Disconnected */) { 62030 this._logger.log(LogLevel.Debug, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is already in the disconnected state.`); 62031 return; 62032 } 62033 if (this._connectionState === "Connecting" /* Connecting */) { 62034 this._logger.log(LogLevel.Warning, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is still in the connecting state.`); 62035 throw new Error(`HttpConnection.stopConnection(${error}) was called while the connection is still in the connecting state.`); 62036 } 62037 if (this._connectionState === "Disconnecting" /* Disconnecting */) { 62038 // A call to stop() induced this call to stopConnection and needs to be completed. 62039 // Any stop() awaiters will be scheduled to continue after the onclose callback fires. 62040 this._stopPromiseResolver(); 62041 } 62042 if (error) { 62043 this._logger.log(LogLevel.Error, `Connection disconnected with error '${error}'.`); 62044 } 62045 else { 62046 this._logger.log(LogLevel.Information, "Connection disconnected."); 62047 } 62048 if (this._sendQueue) { 62049 this._sendQueue.stop().catch((e) => { 62050 this._logger.log(LogLevel.Error, `TransportSendQueue.stop() threw error '${e}'.`); 62051 }); 62052 this._sendQueue = undefined; 62053 } 62054 this.connectionId = undefined; 62055 this._connectionState = "Disconnected" /* Disconnected */; 62056 if (this._connectionStarted) { 62057 this._connectionStarted = false; 62058 try { 62059 if (this.onclose) { 62060 this.onclose(error); 62061 } 62062 } 62063 catch (e) { 62064 this._logger.log(LogLevel.Error, `HttpConnection.onclose(${error}) threw error '${e}'.`); 62065 } 62066 } 62067 } 62068 _resolveUrl(url) { 62069 // startsWith is not supported in IE 62070 if (url.lastIndexOf("https://", 0) === 0 || url.lastIndexOf("http://", 0) === 0) { 62071 return url; 62072 } 62073 if (!Platform.isBrowser) { 62074 throw new Error(`Cannot resolve '${url}'.`); 62075 } 62076 // Setting the url to the href propery of an anchor tag handles normalization 62077 // for us. There are 3 main cases. 62078 // 1. Relative path normalization e.g "b" -> "http://localhost:5000/a/b" 62079 // 2. Absolute path normalization e.g "/a/b" -> "http://localhost:5000/a/b" 62080 // 3. Networkpath reference normalization e.g "//localhost:5000/a/b" -> "http://localhost:5000/a/b" 62081 const aTag = window.document.createElement("a"); 62082 aTag.href = url; 62083 this._logger.log(LogLevel.Information, `Normalizing '${url}' to '${aTag.href}'.`); 62084 return aTag.href; 62085 } 62086 _resolveNegotiateUrl(url) { 62087 const index = url.indexOf("?"); 62088 let negotiateUrl = url.substring(0, index === -1 ? url.length : index); 62089 if (negotiateUrl[negotiateUrl.length - 1] !== "/") { 62090 negotiateUrl += "/"; 62091 } 62092 negotiateUrl += "negotiate"; 62093 negotiateUrl += index === -1 ? "" : url.substring(index); 62094 if (negotiateUrl.indexOf("negotiateVersion") === -1) { 62095 negotiateUrl += index === -1 ? "?" : "&"; 62096 negotiateUrl += "negotiateVersion=" + this._negotiateVersion; 62097 } 62098 return negotiateUrl; 62099 } 62100} 62101function transportMatches(requestedTransport, actualTransport) { 62102 return !requestedTransport || ((actualTransport & requestedTransport) !== 0); 62103} 62104/** @private */ 62105class TransportSendQueue { 62106 constructor(_transport) { 62107 this._transport = _transport; 62108 this._buffer = []; 62109 this._executing = true; 62110 this._sendBufferedData = new PromiseSource(); 62111 this._transportResult = new PromiseSource(); 62112 this._sendLoopPromise = this._sendLoop(); 62113 } 62114 send(data) { 62115 this._bufferData(data); 62116 if (!this._transportResult) { 62117 this._transportResult = new PromiseSource(); 62118 } 62119 return this._transportResult.promise; 62120 } 62121 stop() { 62122 this._executing = false; 62123 this._sendBufferedData.resolve(); 62124 return this._sendLoopPromise; 62125 } 62126 _bufferData(data) { 62127 if (this._buffer.length && typeof (this._buffer[0]) !== typeof (data)) { 62128 throw new Error(`Expected data to be of type ${typeof (this._buffer)} but was of type ${typeof (data)}`); 62129 } 62130 this._buffer.push(data); 62131 this._sendBufferedData.resolve(); 62132 } 62133 async _sendLoop() { 62134 while (true) { 62135 await this._sendBufferedData.promise; 62136 if (!this._executing) { 62137 if (this._transportResult) { 62138 this._transportResult.reject("Connection stopped."); 62139 } 62140 break; 62141 } 62142 this._sendBufferedData = new PromiseSource(); 62143 const transportResult = this._transportResult; 62144 this._transportResult = undefined; 62145 const data = typeof (this._buffer[0]) === "string" ? 62146 this._buffer.join("") : 62147 TransportSendQueue._concatBuffers(this._buffer); 62148 this._buffer.length = 0; 62149 try { 62150 await this._transport.send(data); 62151 transportResult.resolve(); 62152 } 62153 catch (error) { 62154 transportResult.reject(error); 62155 } 62156 } 62157 } 62158 static _concatBuffers(arrayBuffers) { 62159 const totalLength = arrayBuffers.map((b) => b.byteLength).reduce((a, b) => a + b); 62160 const result = new Uint8Array(totalLength); 62161 let offset = 0; 62162 for (const item of arrayBuffers) { 62163 result.set(new Uint8Array(item), offset); 62164 offset += item.byteLength; 62165 } 62166 return result.buffer; 62167 } 62168} 62169class PromiseSource { 62170 constructor() { 62171 this.promise = new Promise((resolve, reject) => [this._resolver, this._rejecter] = [resolve, reject]); 62172 } 62173 resolve() { 62174 this._resolver(); 62175 } 62176 reject(reason) { 62177 this._rejecter(reason); 62178 } 62179} 62180//# sourceMappingURL=HttpConnection.js.map 62181;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/TextMessageFormat.js 62182// Licensed to the .NET Foundation under one or more agreements. 62183// The .NET Foundation licenses this file to you under the MIT license. 62184// Not exported from index 62185/** @private */ 62186class TextMessageFormat { 62187 static write(output) { 62188 return `${output}${TextMessageFormat.RecordSeparator}`; 62189 } 62190 static parse(input) { 62191 if (input[input.length - 1] !== TextMessageFormat.RecordSeparator) { 62192 throw new Error("Message is incomplete."); 62193 } 62194 const messages = input.split(TextMessageFormat.RecordSeparator); 62195 messages.pop(); 62196 return messages; 62197 } 62198} 62199TextMessageFormat.RecordSeparatorCode = 0x1e; 62200TextMessageFormat.RecordSeparator = String.fromCharCode(TextMessageFormat.RecordSeparatorCode); 62201//# sourceMappingURL=TextMessageFormat.js.map 62202;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/HandshakeProtocol.js 62203// Licensed to the .NET Foundation under one or more agreements. 62204// The .NET Foundation licenses this file to you under the MIT license. 62205 62206 62207/** @private */ 62208class HandshakeProtocol { 62209 // Handshake request is always JSON 62210 writeHandshakeRequest(handshakeRequest) { 62211 return TextMessageFormat.write(JSON.stringify(handshakeRequest)); 62212 } 62213 parseHandshakeResponse(data) { 62214 let messageData; 62215 let remainingData; 62216 if (isArrayBuffer(data)) { 62217 // Format is binary but still need to read JSON text from handshake response 62218 const binaryData = new Uint8Array(data); 62219 const separatorIndex = binaryData.indexOf(TextMessageFormat.RecordSeparatorCode); 62220 if (separatorIndex === -1) { 62221 throw new Error("Message is incomplete."); 62222 } 62223 // content before separator is handshake response 62224 // optional content after is additional messages 62225 const responseLength = separatorIndex + 1; 62226 messageData = String.fromCharCode.apply(null, Array.prototype.slice.call(binaryData.slice(0, responseLength))); 62227 remainingData = (binaryData.byteLength > responseLength) ? binaryData.slice(responseLength).buffer : null; 62228 } 62229 else { 62230 const textData = data; 62231 const separatorIndex = textData.indexOf(TextMessageFormat.RecordSeparator); 62232 if (separatorIndex === -1) { 62233 throw new Error("Message is incomplete."); 62234 } 62235 // content before separator is handshake response 62236 // optional content after is additional messages 62237 const responseLength = separatorIndex + 1; 62238 messageData = textData.substring(0, responseLength); 62239 remainingData = (textData.length > responseLength) ? textData.substring(responseLength) : null; 62240 } 62241 // At this point we should have just the single handshake message 62242 const messages = TextMessageFormat.parse(messageData); 62243 const response = JSON.parse(messages[0]); 62244 if (response.type) { 62245 throw new Error("Expected a handshake response from the server."); 62246 } 62247 const responseMessage = response; 62248 // multiple messages could have arrived with handshake 62249 // return additional data to be parsed as usual, or null if all parsed 62250 return [remainingData, responseMessage]; 62251 } 62252} 62253//# sourceMappingURL=HandshakeProtocol.js.map 62254;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/IHubProtocol.js 62255// Licensed to the .NET Foundation under one or more agreements. 62256// The .NET Foundation licenses this file to you under the MIT license. 62257/** Defines the type of a Hub Message. */ 62258var MessageType; 62259(function (MessageType) { 62260 /** Indicates the message is an Invocation message and implements the {@link @microsoft/signalr.InvocationMessage} interface. */ 62261 MessageType[MessageType["Invocation"] = 1] = "Invocation"; 62262 /** Indicates the message is a StreamItem message and implements the {@link @microsoft/signalr.StreamItemMessage} interface. */ 62263 MessageType[MessageType["StreamItem"] = 2] = "StreamItem"; 62264 /** Indicates the message is a Completion message and implements the {@link @microsoft/signalr.CompletionMessage} interface. */ 62265 MessageType[MessageType["Completion"] = 3] = "Completion"; 62266 /** Indicates the message is a Stream Invocation message and implements the {@link @microsoft/signalr.StreamInvocationMessage} interface. */ 62267 MessageType[MessageType["StreamInvocation"] = 4] = "StreamInvocation"; 62268 /** Indicates the message is a Cancel Invocation message and implements the {@link @microsoft/signalr.CancelInvocationMessage} interface. */ 62269 MessageType[MessageType["CancelInvocation"] = 5] = "CancelInvocation"; 62270 /** Indicates the message is a Ping message and implements the {@link @microsoft/signalr.PingMessage} interface. */ 62271 MessageType[MessageType["Ping"] = 6] = "Ping"; 62272 /** Indicates the message is a Close message and implements the {@link @microsoft/signalr.CloseMessage} interface. */ 62273 MessageType[MessageType["Close"] = 7] = "Close"; 62274})(MessageType || (MessageType = {})); 62275//# sourceMappingURL=IHubProtocol.js.map 62276;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/Subject.js 62277// Licensed to the .NET Foundation under one or more agreements. 62278// The .NET Foundation licenses this file to you under the MIT license. 62279 62280/** Stream implementation to stream items to the server. */ 62281class Subject { 62282 constructor() { 62283 this.observers = []; 62284 } 62285 next(item) { 62286 for (const observer of this.observers) { 62287 observer.next(item); 62288 } 62289 } 62290 error(err) { 62291 for (const observer of this.observers) { 62292 if (observer.error) { 62293 observer.error(err); 62294 } 62295 } 62296 } 62297 complete() { 62298 for (const observer of this.observers) { 62299 if (observer.complete) { 62300 observer.complete(); 62301 } 62302 } 62303 } 62304 subscribe(observer) { 62305 this.observers.push(observer); 62306 return new SubjectSubscription(this, observer); 62307 } 62308} 62309//# sourceMappingURL=Subject.js.map 62310;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/HubConnection.js 62311// Licensed to the .NET Foundation under one or more agreements. 62312// The .NET Foundation licenses this file to you under the MIT license. 62313 62314 62315 62316 62317 62318const DEFAULT_TIMEOUT_IN_MS = 30 * 1000; 62319const DEFAULT_PING_INTERVAL_IN_MS = 15 * 1000; 62320/** Describes the current state of the {@link HubConnection} to the server. */ 62321var HubConnectionState; 62322(function (HubConnectionState) { 62323 /** The hub connection is disconnected. */ 62324 HubConnectionState["Disconnected"] = "Disconnected"; 62325 /** The hub connection is connecting. */ 62326 HubConnectionState["Connecting"] = "Connecting"; 62327 /** The hub connection is connected. */ 62328 HubConnectionState["Connected"] = "Connected"; 62329 /** The hub connection is disconnecting. */ 62330 HubConnectionState["Disconnecting"] = "Disconnecting"; 62331 /** The hub connection is reconnecting. */ 62332 HubConnectionState["Reconnecting"] = "Reconnecting"; 62333})(HubConnectionState || (HubConnectionState = {})); 62334/** Represents a connection to a SignalR Hub. */ 62335class HubConnection { 62336 constructor(connection, logger, protocol, reconnectPolicy) { 62337 this._nextKeepAlive = 0; 62338 this._freezeEventListener = () => { 62339 this._logger.log(LogLevel.Warning, "The page is being frozen, this will likely lead to the connection being closed and messages being lost. For more information see the docs at https://docs.microsoft.com/aspnet/core/signalr/javascript-client#bsleep"); 62340 }; 62341 Arg.isRequired(connection, "connection"); 62342 Arg.isRequired(logger, "logger"); 62343 Arg.isRequired(protocol, "protocol"); 62344 this.serverTimeoutInMilliseconds = DEFAULT_TIMEOUT_IN_MS; 62345 this.keepAliveIntervalInMilliseconds = DEFAULT_PING_INTERVAL_IN_MS; 62346 this._logger = logger; 62347 this._protocol = protocol; 62348 this.connection = connection; 62349 this._reconnectPolicy = reconnectPolicy; 62350 this._handshakeProtocol = new HandshakeProtocol(); 62351 this.connection.onreceive = (data) => this._processIncomingData(data); 62352 this.connection.onclose = (error) => this._connectionClosed(error); 62353 this._callbacks = {}; 62354 this._methods = {}; 62355 this._closedCallbacks = []; 62356 this._reconnectingCallbacks = []; 62357 this._reconnectedCallbacks = []; 62358 this._invocationId = 0; 62359 this._receivedHandshakeResponse = false; 62360 this._connectionState = HubConnectionState.Disconnected; 62361 this._connectionStarted = false; 62362 this._cachedPingMessage = this._protocol.writeMessage({ type: MessageType.Ping }); 62363 } 62364 /** @internal */ 62365 // Using a public static factory method means we can have a private constructor and an _internal_ 62366 // create method that can be used by HubConnectionBuilder. An "internal" constructor would just 62367 // be stripped away and the '.d.ts' file would have no constructor, which is interpreted as a 62368 // public parameter-less constructor. 62369 static create(connection, logger, protocol, reconnectPolicy) { 62370 return new HubConnection(connection, logger, protocol, reconnectPolicy); 62371 } 62372 /** Indicates the state of the {@link HubConnection} to the server. */ 62373 get state() { 62374 return this._connectionState; 62375 } 62376 /** Represents the connection id of the {@link HubConnection} on the server. The connection id will be null when the connection is either 62377 * in the disconnected state or if the negotiation step was skipped. 62378 */ 62379 get connectionId() { 62380 return this.connection ? (this.connection.connectionId || null) : null; 62381 } 62382 /** Indicates the url of the {@link HubConnection} to the server. */ 62383 get baseUrl() { 62384 return this.connection.baseUrl || ""; 62385 } 62386 /** 62387 * Sets a new url for the HubConnection. Note that the url can only be changed when the connection is in either the Disconnected or 62388 * Reconnecting states. 62389 * @param {string} url The url to connect to. 62390 */ 62391 set baseUrl(url) { 62392 if (this._connectionState !== HubConnectionState.Disconnected && this._connectionState !== HubConnectionState.Reconnecting) { 62393 throw new Error("The HubConnection must be in the Disconnected or Reconnecting state to change the url."); 62394 } 62395 if (!url) { 62396 throw new Error("The HubConnection url must be a valid url."); 62397 } 62398 this.connection.baseUrl = url; 62399 } 62400 /** Starts the connection. 62401 * 62402 * @returns {Promise<void>} A Promise that resolves when the connection has been successfully established, or rejects with an error. 62403 */ 62404 start() { 62405 this._startPromise = this._startWithStateTransitions(); 62406 return this._startPromise; 62407 } 62408 async _startWithStateTransitions() { 62409 if (this._connectionState !== HubConnectionState.Disconnected) { 62410 return Promise.reject(new Error("Cannot start a HubConnection that is not in the 'Disconnected' state.")); 62411 } 62412 this._connectionState = HubConnectionState.Connecting; 62413 this._logger.log(LogLevel.Debug, "Starting HubConnection."); 62414 try { 62415 await this._startInternal(); 62416 if (Platform.isBrowser) { 62417 // Log when the browser freezes the tab so users know why their connection unexpectedly stopped working 62418 window.document.addEventListener("freeze", this._freezeEventListener); 62419 } 62420 this._connectionState = HubConnectionState.Connected; 62421 this._connectionStarted = true; 62422 this._logger.log(LogLevel.Debug, "HubConnection connected successfully."); 62423 } 62424 catch (e) { 62425 this._connectionState = HubConnectionState.Disconnected; 62426 this._logger.log(LogLevel.Debug, `HubConnection failed to start successfully because of error '${e}'.`); 62427 return Promise.reject(e); 62428 } 62429 } 62430 async _startInternal() { 62431 this._stopDuringStartError = undefined; 62432 this._receivedHandshakeResponse = false; 62433 // Set up the promise before any connection is (re)started otherwise it could race with received messages 62434 const handshakePromise = new Promise((resolve, reject) => { 62435 this._handshakeResolver = resolve; 62436 this._handshakeRejecter = reject; 62437 }); 62438 await this.connection.start(this._protocol.transferFormat); 62439 try { 62440 const handshakeRequest = { 62441 protocol: this._protocol.name, 62442 version: this._protocol.version, 62443 }; 62444 this._logger.log(LogLevel.Debug, "Sending handshake request."); 62445 await this._sendMessage(this._handshakeProtocol.writeHandshakeRequest(handshakeRequest)); 62446 this._logger.log(LogLevel.Information, `Using HubProtocol '${this._protocol.name}'.`); 62447 // defensively cleanup timeout in case we receive a message from the server before we finish start 62448 this._cleanupTimeout(); 62449 this._resetTimeoutPeriod(); 62450 this._resetKeepAliveInterval(); 62451 await handshakePromise; 62452 // It's important to check the stopDuringStartError instead of just relying on the handshakePromise 62453 // being rejected on close, because this continuation can run after both the handshake completed successfully 62454 // and the connection was closed. 62455 if (this._stopDuringStartError) { 62456 // It's important to throw instead of returning a rejected promise, because we don't want to allow any state 62457 // transitions to occur between now and the calling code observing the exceptions. Returning a rejected promise 62458 // will cause the calling continuation to get scheduled to run later. 62459 // eslint-disable-next-line @typescript-eslint/no-throw-literal 62460 throw this._stopDuringStartError; 62461 } 62462 } 62463 catch (e) { 62464 this._logger.log(LogLevel.Debug, `Hub handshake failed with error '${e}' during start(). Stopping HubConnection.`); 62465 this._cleanupTimeout(); 62466 this._cleanupPingTimer(); 62467 // HttpConnection.stop() should not complete until after the onclose callback is invoked. 62468 // This will transition the HubConnection to the disconnected state before HttpConnection.stop() completes. 62469 await this.connection.stop(e); 62470 throw e; 62471 } 62472 } 62473 /** Stops the connection. 62474 * 62475 * @returns {Promise<void>} A Promise that resolves when the connection has been successfully terminated, or rejects with an error. 62476 */ 62477 async stop() { 62478 // Capture the start promise before the connection might be restarted in an onclose callback. 62479 const startPromise = this._startPromise; 62480 this._stopPromise = this._stopInternal(); 62481 await this._stopPromise; 62482 try { 62483 // Awaiting undefined continues immediately 62484 await startPromise; 62485 } 62486 catch (e) { 62487 // This exception is returned to the user as a rejected Promise from the start method. 62488 } 62489 } 62490 _stopInternal(error) { 62491 if (this._connectionState === HubConnectionState.Disconnected) { 62492 this._logger.log(LogLevel.Debug, `Call to HubConnection.stop(${error}) ignored because it is already in the disconnected state.`); 62493 return Promise.resolve(); 62494 } 62495 if (this._connectionState === HubConnectionState.Disconnecting) { 62496 this._logger.log(LogLevel.Debug, `Call to HttpConnection.stop(${error}) ignored because the connection is already in the disconnecting state.`); 62497 return this._stopPromise; 62498 } 62499 this._connectionState = HubConnectionState.Disconnecting; 62500 this._logger.log(LogLevel.Debug, "Stopping HubConnection."); 62501 if (this._reconnectDelayHandle) { 62502 // We're in a reconnect delay which means the underlying connection is currently already stopped. 62503 // Just clear the handle to stop the reconnect loop (which no one is waiting on thankfully) and 62504 // fire the onclose callbacks. 62505 this._logger.log(LogLevel.Debug, "Connection stopped during reconnect delay. Done reconnecting."); 62506 clearTimeout(this._reconnectDelayHandle); 62507 this._reconnectDelayHandle = undefined; 62508 this._completeClose(); 62509 return Promise.resolve(); 62510 } 62511 this._cleanupTimeout(); 62512 this._cleanupPingTimer(); 62513 this._stopDuringStartError = error || new Error("The connection was stopped before the hub handshake could complete."); 62514 // HttpConnection.stop() should not complete until after either HttpConnection.start() fails 62515 // or the onclose callback is invoked. The onclose callback will transition the HubConnection 62516 // to the disconnected state if need be before HttpConnection.stop() completes. 62517 return this.connection.stop(error); 62518 } 62519 /** Invokes a streaming hub method on the server using the specified name and arguments. 62520 * 62521 * @typeparam T The type of the items returned by the server. 62522 * @param {string} methodName The name of the server method to invoke. 62523 * @param {any[]} args The arguments used to invoke the server method. 62524 * @returns {IStreamResult<T>} An object that yields results from the server as they are received. 62525 */ 62526 stream(methodName, ...args) { 62527 const [streams, streamIds] = this._replaceStreamingParams(args); 62528 const invocationDescriptor = this._createStreamInvocation(methodName, args, streamIds); 62529 // eslint-disable-next-line prefer-const 62530 let promiseQueue; 62531 const subject = new Subject(); 62532 subject.cancelCallback = () => { 62533 const cancelInvocation = this._createCancelInvocation(invocationDescriptor.invocationId); 62534 delete this._callbacks[invocationDescriptor.invocationId]; 62535 return promiseQueue.then(() => { 62536 return this._sendWithProtocol(cancelInvocation); 62537 }); 62538 }; 62539 this._callbacks[invocationDescriptor.invocationId] = (invocationEvent, error) => { 62540 if (error) { 62541 subject.error(error); 62542 return; 62543 } 62544 else if (invocationEvent) { 62545 // invocationEvent will not be null when an error is not passed to the callback 62546 if (invocationEvent.type === MessageType.Completion) { 62547 if (invocationEvent.error) { 62548 subject.error(new Error(invocationEvent.error)); 62549 } 62550 else { 62551 subject.complete(); 62552 } 62553 } 62554 else { 62555 subject.next((invocationEvent.item)); 62556 } 62557 } 62558 }; 62559 promiseQueue = this._sendWithProtocol(invocationDescriptor) 62560 .catch((e) => { 62561 subject.error(e); 62562 delete this._callbacks[invocationDescriptor.invocationId]; 62563 }); 62564 this._launchStreams(streams, promiseQueue); 62565 return subject; 62566 } 62567 _sendMessage(message) { 62568 this._resetKeepAliveInterval(); 62569 return this.connection.send(message); 62570 } 62571 /** 62572 * Sends a js object to the server. 62573 * @param message The js object to serialize and send. 62574 */ 62575 _sendWithProtocol(message) { 62576 return this._sendMessage(this._protocol.writeMessage(message)); 62577 } 62578 /** Invokes a hub method on the server using the specified name and arguments. Does not wait for a response from the receiver. 62579 * 62580 * The Promise returned by this method resolves when the client has sent the invocation to the server. The server may still 62581 * be processing the invocation. 62582 * 62583 * @param {string} methodName The name of the server method to invoke. 62584 * @param {any[]} args The arguments used to invoke the server method. 62585 * @returns {Promise<void>} A Promise that resolves when the invocation has been successfully sent, or rejects with an error. 62586 */ 62587 send(methodName, ...args) { 62588 const [streams, streamIds] = this._replaceStreamingParams(args); 62589 const sendPromise = this._sendWithProtocol(this._createInvocation(methodName, args, true, streamIds)); 62590 this._launchStreams(streams, sendPromise); 62591 return sendPromise; 62592 } 62593 /** Invokes a hub method on the server using the specified name and arguments. 62594 * 62595 * The Promise returned by this method resolves when the server indicates it has finished invoking the method. When the promise 62596 * resolves, the server has finished invoking the method. If the server method returns a result, it is produced as the result of 62597 * resolving the Promise. 62598 * 62599 * @typeparam T The expected return type. 62600 * @param {string} methodName The name of the server method to invoke. 62601 * @param {any[]} args The arguments used to invoke the server method. 62602 * @returns {Promise<T>} A Promise that resolves with the result of the server method (if any), or rejects with an error. 62603 */ 62604 invoke(methodName, ...args) { 62605 const [streams, streamIds] = this._replaceStreamingParams(args); 62606 const invocationDescriptor = this._createInvocation(methodName, args, false, streamIds); 62607 const p = new Promise((resolve, reject) => { 62608 // invocationId will always have a value for a non-blocking invocation 62609 this._callbacks[invocationDescriptor.invocationId] = (invocationEvent, error) => { 62610 if (error) { 62611 reject(error); 62612 return; 62613 } 62614 else if (invocationEvent) { 62615 // invocationEvent will not be null when an error is not passed to the callback 62616 if (invocationEvent.type === MessageType.Completion) { 62617 if (invocationEvent.error) { 62618 reject(new Error(invocationEvent.error)); 62619 } 62620 else { 62621 resolve(invocationEvent.result); 62622 } 62623 } 62624 else { 62625 reject(new Error(`Unexpected message type: ${invocationEvent.type}`)); 62626 } 62627 } 62628 }; 62629 const promiseQueue = this._sendWithProtocol(invocationDescriptor) 62630 .catch((e) => { 62631 reject(e); 62632 // invocationId will always have a value for a non-blocking invocation 62633 delete this._callbacks[invocationDescriptor.invocationId]; 62634 }); 62635 this._launchStreams(streams, promiseQueue); 62636 }); 62637 return p; 62638 } 62639 /** Registers a handler that will be invoked when the hub method with the specified method name is invoked. 62640 * 62641 * @param {string} methodName The name of the hub method to define. 62642 * @param {Function} newMethod The handler that will be raised when the hub method is invoked. 62643 */ 62644 on(methodName, newMethod) { 62645 if (!methodName || !newMethod) { 62646 return; 62647 } 62648 methodName = methodName.toLowerCase(); 62649 if (!this._methods[methodName]) { 62650 this._methods[methodName] = []; 62651 } 62652 // Preventing adding the same handler multiple times. 62653 if (this._methods[methodName].indexOf(newMethod) !== -1) { 62654 return; 62655 } 62656 this._methods[methodName].push(newMethod); 62657 } 62658 off(methodName, method) { 62659 if (!methodName) { 62660 return; 62661 } 62662 methodName = methodName.toLowerCase(); 62663 const handlers = this._methods[methodName]; 62664 if (!handlers) { 62665 return; 62666 } 62667 if (method) { 62668 const removeIdx = handlers.indexOf(method); 62669 if (removeIdx !== -1) { 62670 handlers.splice(removeIdx, 1); 62671 if (handlers.length === 0) { 62672 delete this._methods[methodName]; 62673 } 62674 } 62675 } 62676 else { 62677 delete this._methods[methodName]; 62678 } 62679 } 62680 /** Registers a handler that will be invoked when the connection is closed. 62681 * 62682 * @param {Function} callback The handler that will be invoked when the connection is closed. Optionally receives a single argument containing the error that caused the connection to close (if any). 62683 */ 62684 onclose(callback) { 62685 if (callback) { 62686 this._closedCallbacks.push(callback); 62687 } 62688 } 62689 /** Registers a handler that will be invoked when the connection starts reconnecting. 62690 * 62691 * @param {Function} callback The handler that will be invoked when the connection starts reconnecting. Optionally receives a single argument containing the error that caused the connection to start reconnecting (if any). 62692 */ 62693 onreconnecting(callback) { 62694 if (callback) { 62695 this._reconnectingCallbacks.push(callback); 62696 } 62697 } 62698 /** Registers a handler that will be invoked when the connection successfully reconnects. 62699 * 62700 * @param {Function} callback The handler that will be invoked when the connection successfully reconnects. 62701 */ 62702 onreconnected(callback) { 62703 if (callback) { 62704 this._reconnectedCallbacks.push(callback); 62705 } 62706 } 62707 _processIncomingData(data) { 62708 this._cleanupTimeout(); 62709 if (!this._receivedHandshakeResponse) { 62710 data = this._processHandshakeResponse(data); 62711 this._receivedHandshakeResponse = true; 62712 } 62713 // Data may have all been read when processing handshake response 62714 if (data) { 62715 // Parse the messages 62716 const messages = this._protocol.parseMessages(data, this._logger); 62717 for (const message of messages) { 62718 switch (message.type) { 62719 case MessageType.Invocation: 62720 this._invokeClientMethod(message); 62721 break; 62722 case MessageType.StreamItem: 62723 case MessageType.Completion: { 62724 const callback = this._callbacks[message.invocationId]; 62725 if (callback) { 62726 if (message.type === MessageType.Completion) { 62727 delete this._callbacks[message.invocationId]; 62728 } 62729 try { 62730 callback(message); 62731 } 62732 catch (e) { 62733 this._logger.log(LogLevel.Error, `Stream callback threw error: ${getErrorString(e)}`); 62734 } 62735 } 62736 break; 62737 } 62738 case MessageType.Ping: 62739 // Don't care about pings 62740 break; 62741 case MessageType.Close: { 62742 this._logger.log(LogLevel.Information, "Close message received from server."); 62743 const error = message.error ? new Error("Server returned an error on close: " + message.error) : undefined; 62744 if (message.allowReconnect === true) { 62745 // It feels wrong not to await connection.stop() here, but processIncomingData is called as part of an onreceive callback which is not async, 62746 // this is already the behavior for serverTimeout(), and HttpConnection.Stop() should catch and log all possible exceptions. 62747 // eslint-disable-next-line @typescript-eslint/no-floating-promises 62748 this.connection.stop(error); 62749 } 62750 else { 62751 // We cannot await stopInternal() here, but subsequent calls to stop() will await this if stopInternal() is still ongoing. 62752 this._stopPromise = this._stopInternal(error); 62753 } 62754 break; 62755 } 62756 default: 62757 this._logger.log(LogLevel.Warning, `Invalid message type: ${message.type}.`); 62758 break; 62759 } 62760 } 62761 } 62762 this._resetTimeoutPeriod(); 62763 } 62764 _processHandshakeResponse(data) { 62765 let responseMessage; 62766 let remainingData; 62767 try { 62768 [remainingData, responseMessage] = this._handshakeProtocol.parseHandshakeResponse(data); 62769 } 62770 catch (e) { 62771 const message = "Error parsing handshake response: " + e; 62772 this._logger.log(LogLevel.Error, message); 62773 const error = new Error(message); 62774 this._handshakeRejecter(error); 62775 throw error; 62776 } 62777 if (responseMessage.error) { 62778 const message = "Server returned handshake error: " + responseMessage.error; 62779 this._logger.log(LogLevel.Error, message); 62780 const error = new Error(message); 62781 this._handshakeRejecter(error); 62782 throw error; 62783 } 62784 else { 62785 this._logger.log(LogLevel.Debug, "Server handshake complete."); 62786 } 62787 this._handshakeResolver(); 62788 return remainingData; 62789 } 62790 _resetKeepAliveInterval() { 62791 if (this.connection.features.inherentKeepAlive) { 62792 return; 62793 } 62794 // Set the time we want the next keep alive to be sent 62795 // Timer will be setup on next message receive 62796 this._nextKeepAlive = new Date().getTime() + this.keepAliveIntervalInMilliseconds; 62797 this._cleanupPingTimer(); 62798 } 62799 _resetTimeoutPeriod() { 62800 if (!this.connection.features || !this.connection.features.inherentKeepAlive) { 62801 // Set the timeout timer 62802 this._timeoutHandle = setTimeout(() => this.serverTimeout(), this.serverTimeoutInMilliseconds); 62803 // Set keepAlive timer if there isn't one 62804 if (this._pingServerHandle === undefined) { 62805 let nextPing = this._nextKeepAlive - new Date().getTime(); 62806 if (nextPing < 0) { 62807 nextPing = 0; 62808 } 62809 // The timer needs to be set from a networking c
62809allback to avoid Chrome timer throttling from causing timers to run once a minute 62810 this._pingServerHandle = setTimeout(async () => { 62811 if (this._connectionState === HubConnectionState.Connected) { 62812 try { 62813 await this._sendMessage(this._cachedPingMessage); 62814 } 62815 catch { 62816 // We don't care about the error. It should be seen elsewhere in the client. 62817 // The connection is probably in a bad or closed state now, cleanup the timer so it stops triggering 62818 this._cleanupPingTimer(); 62819 } 62820 } 62821 }, nextPing); 62822 } 62823 } 62824 } 62825 // eslint-disable-next-line @typescript-eslint/naming-convention 62826 serverTimeout() { 62827 // The server hasn't talked to us in a while. It doesn't like us anymore ... :( 62828 // Terminate the connection, but we don't need to wait on the promise. This could trigger reconnecting. 62829 // eslint-disable-next-line @typescript-eslint/no-floating-promises 62830 this.connection.stop(new Error("Server timeout elapsed without receiving a message from the server.")); 62831 } 62832 _invokeClientMethod(invocationMessage) { 62833 const methods = this._methods[invocationMessage.target.toLowerCase()]; 62834 if (methods) { 62835 try { 62836 methods.forEach((m) => m.apply(this, invocationMessage.arguments)); 62837 } 62838 catch (e) { 62839 this._logger.log(LogLevel.Error, `A callback for the method ${invocationMessage.target.toLowerCase()} threw error '${e}'.`); 62840 } 62841 if (invocationMessage.invocationId) { 62842 // This is not supported in v1. So we return an error to avoid blocking the server waiting for the response. 62843 const message = "Server requested a response, which is not supported in this version of the client."; 62844 this._logger.log(LogLevel.Error, message); 62845 // We don't want to wait on the stop itself. 62846 this._stopPromise = this._stopInternal(new Error(message)); 62847 } 62848 } 62849 else { 62850 this._logger.log(LogLevel.Warning, `No client method with the name '${invocationMessage.target}' found.`); 62851 } 62852 } 62853 _connectionClosed(error) { 62854 this._logger.log(LogLevel.Debug, `HubConnection.connectionClosed(${error}) called while in state ${this._connectionState}.`); 62855 // Triggering this.handshakeRejecter is insufficient because it could already be resolved without the continuation having run yet. 62856 this._stopDuringStartError = this._stopDuringStartError || error || new Error("The underlying connection was closed before the hub handshake could complete."); 62857 // If the handshake is in progress, start will be waiting for the handshake promise, so we complete it. 62858 // If it has already completed, this should just noop. 62859 if (this._handshakeResolver) { 62860 this._handshakeResolver(); 62861 } 62862 this._cancelCallbacksWithError(error || new Error("Invocation canceled due to the underlying connection being closed.")); 62863 this._cleanupTimeout(); 62864 this._cleanupPingTimer(); 62865 if (this._connectionState === HubConnectionState.Disconnecting) { 62866 this._completeClose(error); 62867 } 62868 else if (this._connectionState === HubConnectionState.Connected && this._reconnectPolicy) { 62869 // eslint-disable-next-line @typescript-eslint/no-floating-promises 62870 this._reconnect(error); 62871 } 62872 else if (this._connectionState === HubConnectionState.Connected) { 62873 this._completeClose(error); 62874 } 62875 // If none of the above if conditions were true were called the HubConnection must be in either: 62876 // 1. The Connecting state in which case the handshakeResolver will c
vendor: 17,747 bytes, lines 62876-63307
62876omplete it and stopDuringStartError will fail it. 62877 // 2. The Reconnecting state in which case the handshakeResolver will complete it and stopDuringStartError will fail the current reconnect attempt 62878 // and potentially continue the reconnect() loop. 62879 // 3. The Disconnected state in which case we're already done. 62880 } 62881 _completeClose(error) { 62882 if (this._connectionStarted) { 62883 this._connectionState = HubConnectionState.Disconnected; 62884 this._connectionStarted = false; 62885 if (Platform.isBrowser) { 62886 window.document.removeEventListener("freeze", this._freezeEventListener); 62887 } 62888 try { 62889 this._closedCallbacks.forEach((c) => c.apply(this, [error])); 62890 } 62891 catch (e) { 62892 this._logger.log(LogLevel.Error, `An onclose callback called with error '${error}' threw error '${e}'.`); 62893 } 62894 } 62895 } 62896 async _reconnect(error) { 62897 const reconnectStartTime = Date.now(); 62898 let previousReconnectAttempts = 0; 62899 let retryError = error !== undefined ? error : new Error("Attempting to reconnect due to a unknown error."); 62900 let nextRetryDelay = this._getNextRetryDelay(previousReconnectAttempts++, 0, retryError); 62901 if (nextRetryDelay === null) { 62902 this._logger.log(LogLevel.Debug, "Connection not reconnecting because the IRetryPolicy returned null on the first reconnect attempt."); 62903 this._completeClose(error); 62904 return; 62905 } 62906 this._connectionState = HubConnectionState.Reconnecting; 62907 if (error) { 62908 this._logger.log(LogLevel.Information, `Connection reconnecting because of error '${error}'.`); 62909 } 62910 else { 62911 this._logger.log(LogLevel.Information, "Connection reconnecting."); 62912 } 62913 if (this._reconnectingCallbacks.length !== 0) { 62914 try { 62915 this._reconnectingCallbacks.forEach((c) => c.apply(this, [error])); 62916 } 62917 catch (e) { 62918 this._logger.log(LogLevel.Error, `An onreconnecting callback called with error '${error}' threw error '${e}'.`); 62919 } 62920 // Exit early if an onreconnecting callback called connection.stop(). 62921 if (this._connectionState !== HubConnectionState.Reconnecting) { 62922 this._logger.log(LogLevel.Debug, "Connection left the reconnecting state in onreconnecting callback. Done reconnecting."); 62923 return; 62924 } 62925 } 62926 while (nextRetryDelay !== null) { 62927 this._logger.log(LogLevel.Information, `Reconnect attempt number ${previousReconnectAttempts} will start in ${nextRetryDelay} ms.`); 62928 await new Promise((resolve) => { 62929 this._reconnectDelayHandle = setTimeout(resolve, nextRetryDelay); 62930 }); 62931 this._reconnectDelayHandle = undefined; 62932 if (this._connectionState !== HubConnectionState.Reconnecting) { 62933 this._logger.log(LogLevel.Debug, "Connection left the reconnecting state during reconnect delay. Done reconnecting."); 62934 return; 62935 } 62936 try { 62937 await this._startInternal(); 62938 this._connectionState = HubConnectionState.Connected; 62939 this._logger.log(LogLevel.Information, "HubConnection reconnected successfully."); 62940 if (this._reconnectedCallbacks.length !== 0) { 62941 try { 62942 this._reconnectedCallbacks.forEach((c) => c.apply(this, [this.connection.connectionId])); 62943 } 62944 catch (e) { 62945 this._logger.log(LogLevel.Error, `An onreconnected callback called with connectionId '${this.connection.connectionId}; threw error '${e}'.`); 62946 } 62947 } 62948 return; 62949 } 62950 catch (e) { 62951 this._logger.log(LogLevel.Information, `Reconnect attempt failed because of error '${e}'.`); 62952 if (this._connectionState !== HubConnectionState.Reconnecting) { 62953 this._logger.log(LogLevel.Debug, `Connection moved to the '${this._connectionState}' from the reconnecting state during reconnect attempt. Done reconnecting.`); 62954 // The TypeScript compiler thinks that connectionState must be Connected here. The TypeScript compiler is wrong. 62955 if (this._connectionState === HubConnectionState.Disconnecting) { 62956 this._completeClose(); 62957 } 62958 return; 62959 } 62960 retryError = e instanceof Error ? e : new Error(e.toString()); 62961 nextRetryDelay = this._getNextRetryDelay(previousReconnectAttempts++, Date.now() - reconnectStartTime, retryError); 62962 } 62963 } 62964 this._logger.log(LogLevel.Information, `Reconnect retries have been exhausted after ${Date.now() - reconnectStartTime} ms and ${previousReconnectAttempts} failed attempts. Connection disconnecting.`); 62965 this._completeClose(); 62966 } 62967 _getNextRetryDelay(previousRetryCount, elapsedMilliseconds, retryReason) { 62968 try { 62969 return this._reconnectPolicy.nextRetryDelayInMilliseconds({ 62970 elapsedMilliseconds, 62971 previousRetryCount, 62972 retryReason, 62973 }); 62974 } 62975 catch (e) { 62976 this._logger.log(LogLevel.Error, `IRetryPolicy.nextRetryDelayInMilliseconds(${previousRetryCount}, ${elapsedMilliseconds}) threw error '${e}'.`); 62977 return null; 62978 } 62979 } 62980 _cancelCallbacksWithError(error) { 62981 const callbacks = this._callbacks; 62982 this._callbacks = {}; 62983 Object.keys(callbacks) 62984 .forEach((key) => { 62985 const callback = callbacks[key]; 62986 try { 62987 callback(null, error); 62988 } 62989 catch (e) { 62990 this._logger.log(LogLevel.Error, `Stream 'error' callback called with '${error}' threw error: ${getErrorString(e)}`); 62991 } 62992 }); 62993 } 62994 _cleanupPingTimer() { 62995 if (this._pingServerHandle) { 62996 clearTimeout(this._pingServerHandle); 62997 this._pingServerHandle = undefined; 62998 } 62999 } 63000 _cleanupTimeout() { 63001 if (this._timeoutHandle) { 63002 clearTimeout(this._timeoutHandle); 63003 } 63004 } 63005 _createInvocation(methodName, args, nonblocking, streamIds) { 63006 if (nonblocking) { 63007 if (streamIds.length !== 0) { 63008 return { 63009 arguments: args, 63010 streamIds, 63011 target: methodName, 63012 type: MessageType.Invocation, 63013 }; 63014 } 63015 else { 63016 return { 63017 arguments: args, 63018 target: methodName, 63019 type: MessageType.Invocation, 63020 }; 63021 } 63022 } 63023 else { 63024 const invocationId = this._invocationId; 63025 this._invocationId++; 63026 if (streamIds.length !== 0) { 63027 return { 63028 arguments: args, 63029 invocationId: invocationId.toString(), 63030 streamIds, 63031 target: methodName, 63032 type: MessageType.Invocation, 63033 }; 63034 } 63035 else { 63036 return { 63037 arguments: args, 63038 invocationId: invocationId.toString(), 63039 target: methodName, 63040 type: MessageType.Invocation, 63041 }; 63042 } 63043 } 63044 } 63045 _launchStreams(streams, promiseQueue) { 63046 if (streams.length === 0) { 63047 return; 63048 } 63049 // Synchronize stream data so they arrive in-order on the server 63050 if (!promiseQueue) { 63051 promiseQueue = Promise.resolve(); 63052 } 63053 // We want to iterate over the keys, since the keys are the stream ids 63054 // eslint-disable-next-line guard-for-in 63055 for (const streamId in streams) { 63056 streams[streamId].subscribe({ 63057 complete: () => { 63058 promiseQueue = promiseQueue.then(() => this._sendWithProtocol(this._createCompletionMessage(streamId))); 63059 }, 63060 error: (err) => { 63061 let message; 63062 if (err instanceof Error) { 63063 message = err.message; 63064 } 63065 else if (err && err.toString) { 63066 message = err.toString(); 63067 } 63068 else { 63069 message = "Unknown error"; 63070 } 63071 promiseQueue = promiseQueue.then(() => this._sendWithProtocol(this._createCompletionMessage(streamId, message))); 63072 }, 63073 next: (item) => { 63074 promiseQueue = promiseQueue.then(() => this._sendWithProtocol(this._createStreamItemMessage(streamId, item))); 63075 }, 63076 }); 63077 } 63078 } 63079 _replaceStreamingParams(args) { 63080 const streams = []; 63081 const streamIds = []; 63082 for (let i = 0; i < args.length; i++) { 63083 const argument = args[i]; 63084 if (this._isObservable(argument)) { 63085 const streamId = this._invocationId; 63086 this._invocationId++; 63087 // Store the stream for later use 63088 streams[streamId] = argument; 63089 streamIds.push(streamId.toString()); 63090 // remove stream from args 63091 args.splice(i, 1); 63092 } 63093 } 63094 return [streams, streamIds]; 63095 } 63096 _isObservable(arg) { 63097 // This allows other stream implementations to just work (like rxjs) 63098 return arg && arg.subscribe && typeof arg.subscribe === "function"; 63099 } 63100 _createStreamInvocation(methodName, args, streamIds) { 63101 const invocationId = this._invocationId; 63102 this._invocationId++; 63103 if (streamIds.length !== 0) { 63104 return { 63105 arguments: args, 63106 invocationId: invocationId.toString(), 63107 streamIds, 63108 target: methodName, 63109 type: MessageType.StreamInvocation, 63110 }; 63111 } 63112 else { 63113 return { 63114 arguments: args, 63115 invocationId: invocationId.toString(), 63116 target: methodName, 63117 type: MessageType.StreamInvocation, 63118 }; 63119 } 63120 } 63121 _createCancelInvocation(id) { 63122 return { 63123 invocationId: id, 63124 type: MessageType.CancelInvocation, 63125 }; 63126 } 63127 _createStreamItemMessage(id, item) { 63128 return { 63129 invocationId: id, 63130 item, 63131 type: MessageType.StreamItem, 63132 }; 63133 } 63134 _createCompletionMessage(id, error, result) { 63135 if (error) { 63136 return { 63137 error, 63138 invocationId: id, 63139 type: MessageType.Completion, 63140 }; 63141 } 63142 return { 63143 invocationId: id, 63144 result, 63145 type: MessageType.Completion, 63146 }; 63147 } 63148} 63149//# sourceMappingURL=HubConnection.js.map 63150;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/JsonHubProtocol.js 63151// Licensed to the .NET Foundation under one or more agreements. 63152// The .NET Foundation licenses this file to you under the MIT license. 63153 63154 63155 63156 63157 63158const JSON_HUB_PROTOCOL_NAME = "json"; 63159/** Implements the JSON Hub Protocol. */ 63160class JsonHubProtocol { 63161 constructor() { 63162 /** @inheritDoc */ 63163 this.name = JSON_HUB_PROTOCOL_NAME; 63164 /** @inheritDoc */ 63165 this.version = 1; 63166 /** @inheritDoc */ 63167 this.transferFormat = TransferFormat.Text; 63168 } 63169 /** Creates an array of {@link @microsoft/signalr.HubMessage} objects from the specified serialized representation. 63170 * 63171 * @param {string} input A string containing the serialized representation. 63172 * @param {ILogger} logger A logger that will be used to log messages that occur during parsing. 63173 */ 63174 parseMessages(input, logger) { 63175 // The interface does allow "ArrayBuffer" to be passed in, but this implementation does not. So let's throw a useful error. 63176 if (typeof input !== "string") { 63177 throw new Error("Invalid input for JSON hub protocol. Expected a string."); 63178 } 63179 if (!input) { 63180 return []; 63181 } 63182 if (logger === null) { 63183 logger = NullLogger.instance; 63184 } 63185 // Parse the messages 63186 const messages = TextMessageFormat.parse(input); 63187 const hubMessages = []; 63188 for (const message of messages) { 63189 const parsedMessage = JSON.parse(message); 63190 if (typeof parsedMessage.type !== "number") { 63191 throw new Error("Invalid payload."); 63192 } 63193 switch (parsedMessage.type) { 63194 case MessageType.Invocation: 63195 this._isInvocationMessage(parsedMessage); 63196 break; 63197 case MessageType.StreamItem: 63198 this._isStreamItemMessage(parsedMessage); 63199 break; 63200 case MessageType.Completion: 63201 this._isCompletionMessage(parsedMessage); 63202 break; 63203 case MessageType.Ping: 63204 // Single value, no need to validate 63205 break; 63206 case MessageType.Close: 63207 // All optional values, no need to validate 63208 break; 63209 default: 63210 // Future protocol changes can add message types, old clients can ignore them 63211 logger.log(LogLevel.Information, "Unknown message type '" + parsedMessage.type + "' ignored."); 63212 continue; 63213 } 63214 hubMessages.push(parsedMessage); 63215 } 63216 return hubMessages; 63217 } 63218 /** Writes the specified {@link @microsoft/signalr.HubMessage} to a string and returns it. 63219 * 63220 * @param {HubMessage} message The message to write. 63221 * @returns {string} A string containing the serialized representation of the message. 63222 */ 63223 writeMessage(message) { 63224 return TextMessageFormat.write(JSON.stringify(message)); 63225 } 63226 _isInvocationMessage(message) { 63227 this._assertNotEmptyString(message.target, "Invalid payload for Invocation message."); 63228 if (message.invocationId !== undefined) { 63229 this._assertNotEmptyString(message.invocationId, "Invalid payload for Invocation message."); 63230 } 63231 } 63232 _isStreamItemMessage(message) { 63233 this._assertNotEmptyString(message.invocationId, "Invalid payload for StreamItem message."); 63234 if (message.item === undefined) { 63235 throw new Error("Invalid payload for StreamItem message."); 63236 } 63237 } 63238 _isCompletionMessage(message) { 63239 if (message.result && message.error) { 63240 throw new Error("Invalid payload for Completion message."); 63241 } 63242 if (!message.result && message.error) { 63243 this._assertNotEmptyString(message.error, "Invalid payload for Completion message."); 63244 } 63245 this._assertNotEmptyString(message.invocationId, "Invalid payload for Completion message."); 63246 } 63247 _assertNotEmptyString(value, errorMessage) { 63248 if (typeof value !== "string" || value === "") { 63249 throw new Error(errorMessage); 63250 } 63251 } 63252} 63253//# sourceMappingURL=JsonHubProtocol.js.map 63254;// CONCATENATED MODULE: ./node_modules/@microsoft/signalr/dist/esm/HubConnectionBuilder.js 63255// Licensed to the .NET Foundation under one or more agreements. 63256// The .NET Foundation licenses this file to you under the MIT license. 63257 63258 63259 63260 63261 63262 63263 63264const LogLevelNameMapping = { 63265 trace: LogLevel.Trace, 63266 debug: LogLevel.Debug, 63267 info: LogLevel.Information, 63268 information: LogLevel.Information, 63269 warn: LogLevel.Warning, 63270 warning: LogLevel.Warning, 63271 error: LogLevel.Error, 63272 critical: LogLevel.Critical, 63273 none: LogLevel.None, 63274}; 63275function parseLogLevel(name) { 63276 // Case-insensitive matching via lower-casing 63277 // Yes, I know case-folding is a complicated problem in Unicode, but we only support 63278 // the ASCII strings defined in LogLevelNameMapping anyway, so it's fine -anurse. 63279 const mapping = LogLevelNameMapping[name.toLowerCase()]; 63280 if (typeof mapping !== "undefined") { 63281 return mapping; 63282 } 63283 else { 63284 throw new Error(`Unknown log level: ${name}`); 63285 } 63286} 63287/** A builder for configuring {@link @microsoft/signalr.HubConnection} instances. */ 63288class HubConnectionBuilder { 63289 configureLogging(logging) { 63290 Arg.isRequired(logging, "logging"); 63291 if (isLogger(logging)) { 63292 this.logger = logging; 63293 } 63294 else if (typeof logging === "string") { 63295 const logLevel = parseLogLevel(logging); 63296 this.logger = new ConsoleLogger(logLevel); 63297 } 63298 else { 63299 this.logger = new ConsoleLogger(logging); 63300 } 63301 return this; 63302 } 63303 withUrl(url, transportTypeOrOptions) { 63304 Arg.isRequired(url, "url"); 63305 Arg.isNotEmpty(url, "url"); 63306 this.url = url; 63307 // Flow-typing knows where it's at. Since HttpTransportType is a
63307number and IHttpConnectionOptions is guaranteed 63308 // to be an object, we know (as does TypeScript) this comparison is all we need to figure out which overload was called. 63309 if (typeof transportTypeOrOptions === "object") { 63310 this.httpConnectionOptions = { ...this.httpConnectionOptions, ...transportTypeOrOptions }; 63311 } 63312 else { 63313 this.httpConnectionOptions = { 63314 ...this.httpConnectionOptions, 63315 transport: transportTypeOrOptions, 63316 }; 63317 } 63318 return this; 63319 } 63320 /** Configures the {@link @microsoft/signalr.HubConnection} to use the specified Hub Protocol. 63321 * 63322 * @param {IHubProtocol} protocol The {@link @microsoft/signalr.IHubProtocol} implementation to use. 63323 */ 63324 withHubProtocol(protocol) { 63325 Arg.isRequired(protocol, "protocol"); 63326 this.protocol = protocol; 63327 return this; 63328 } 63329 withAutomaticReconnect(retryDelaysOrReconnectPolicy) { 63330 if (this.reconnectPolicy) { 63331 throw new Error("A reconnectPolicy has already been set."); 63332 } 63333 if (!retryDelaysOrReconnectPolicy) { 63334 this.reconnectPolicy = new DefaultReconnectPolicy(); 63335 } 63336 else if (Array.isArray(retryDelaysOrReconnectPolicy)) { 63337 this.reconnectPolicy = new DefaultReconnectPolicy(retryDelaysOrReconnectPolicy); 63338 } 63339 else { 63340 this.reconnectPolicy = retryDelaysOrReconnectPolicy; 63341 } 63342 return this; 63343 } 63344 /** Creates a {@link @microsoft/signalr.HubConnection} from the configuration options specified in this builder. 63345 * 63346 * @returns {HubConnection} The configured {@link @microsoft/signalr.HubConnection}. 63347 */ 63348 build() { 63349 // If httpConnectionOptions has a logger, use it. Otherwise, override it with the one 63350 // provided to configureLogger 63351 const httpConnectionOptions = this.httpConnectionOptions || {}; 63352 // If it's 'null', the user **explicitly** asked for null, don't mess with it. 63353 if (httpConnectionOptions.logger === undefined) { 63354 // If our logger is undefined or null, that's OK, the HttpConnection constructor will handle it. 63355 httpConnectionOptions.logger = this.logger; 63356 } 63357 // Now create the connection 63358 if (!this.url) { 63359 throw new Error("The 'HubConnectionBuilder.withUrl' method must be called before building the connection."); 63360 } 63361 const connection = new HttpConnection(this.url, httpConnectionOptions); 63362 return HubConnection.create(connection, this.logger || NullLogger.instance, this.protocol || new JsonHubProtocol(), this.reconnectPolicy); 63363 } 63364} 63365function isLogger(logger) { 63366 return logger.log !== undefined; 63367} 63368//# sourceMappingURL=HubConnectionBuilder.js.map 63369;// CONCATENATED MODULE: ./wwwroot/js/domain-map.js 63370/* provided dependency */ var domain_map_$ = __webpack_require__(755); 63371 63372 63373 63374 63375window.domainMap = DomainMap(domain_map_$('#Domain_CentralLatitude'), domain_map_$('#Domain_CentralLongitude'), 'map_canvas', domain_map_$('#Domain_ShowControls').val() === 'true'); 63376 63377const connection = new HubConnectionBuilder() 63378 .withUrl("/copterhub") 63379 .configureLogging(signalR.LogLevel.Information) 63380 .build(); 63381 63382function set_last_seen(mins) { 63383 document.getElementById('txtSeen').innerText = mins >= 60 ? 'over an hour ago' : Math.round(mins) + ' minutes ago'; 63384} 63385 63386window.domainMap.eventManager.on('copterselecting', a => { 63387 if (a && a.copter) { 63388 console.log(`Leaving group ${a.copter}`); 63389 connection.invoke('leaveGroup', a.copter); 63390 } 63391 63392 domain_map_$('.overlay-copter .container-fluid').addClass('visually-hidden'); 63393}); 63394 63395 63396window.domainMap.eventManager.on('copterselected', a => { 63397 if (a && a.copter) { 63398 console.log(`Joining group ${a.copter}`); 63399 connection.invoke('joinGroup', a.copter); 63400 63401 document.getElementById('txtSelected').textContent = a.copter; 63402 document.getElementById('lnkLive').href = a.live_url; 63403 set_last_seen(a.last_seen); 63404 } 63405}); 63406 63407//window.domainMap.eventManager.on('waypoint_added', a => { 63408// if (a) { 63409// document.getElementById('txtLat').value = a.latitude; 63410// document.getElementById('txtLon').value = a.longitude; 63411// } 63412//}); 63413 63414connection.on('LocationUpdate', d => { 63415 if (d) { 63416 //console.log(d); 63417 window.domainMap.update_copter_location(d.copter, d.latitude, d.longitude); 63418 } 63419}); 63420 63421let toC = K => (K - 273.15).toFixed(2); 63422let humidity = v => (v * 100).toFixed(2); 63423 63424connection.on('ReceiveData', d => { 63425 if (d) { 63426 domain_map_$('.overlay-copter .container-fluid').removeClass('visually-hidden'); 63427 63428 let diff = new Date() - Date.parse(d.last_seen); 63429 let mins = Math.round(((diff % 86400000) % 3600000) / 60000); 63430
63431 if (!domain_map_$('#copterStatusIcon').hasClass(d.control_mode.toLowerCase())) { 63432 domain_map_$('#copterStatusIcon').removeClass().addClass(['copter-status', d.control_mode.toLowerCase()]); 63433 } 63434 63435 set_last_seen(mins); 63436 document.getElementById('copterTemp').innerText = toC(d.filteredT); 63437 document.getElementById('copterHum').innerText = humidity(d.filteredRH); 63438 document.getElementById('copterPress').innerText = (d.pressure.value / 100).toFixed(2); 63439 document.getElementById('copterAlt').innerText = d.location.altitude.toFixed(2); 63440 document.getElementById('copterDir').innerText = d.wind.direction.toFixed(2); 63441 document.getElementById('copterSpd').innerText = d.wind.speed.toFixed(2); 63442 // console.log(d); 63443 } 63444}); 63445 63446connection.start() 63447 .then(() => connection.invoke('joinGroup', 'CopterMap')) 63448 .catch(err => console.error(err.toString())); 63449})(); 63450 63451/******/ })() 63452;
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.